mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 07:06:30 +00:00
Compare commits
382 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db4199e08f | ||
|
|
0d9ed02729 | ||
|
|
8e9f0b802b | ||
|
|
c236405251 | ||
|
|
527a5f7fee | ||
|
|
937cffd54c | ||
|
|
2b1e12591a | ||
|
|
7ecfb333b9 | ||
|
|
8f13a66aaa | ||
|
|
ef35d071bf | ||
|
|
b87f9dabb4 | ||
|
|
7decc7975f | ||
|
|
a5cfc244bc | ||
|
|
673bde2b7f | ||
|
|
81de200561 | ||
|
|
cb46fb6410 | ||
|
|
bd58e4128c | ||
|
|
63242e2277 | ||
|
|
69782cf703 | ||
|
|
5acb3e6790 | ||
|
|
6dfcaa357e | ||
|
|
8acc50e752 | ||
|
|
56919ea499 | ||
|
|
b3f64987cb | ||
|
|
388ac2f392 | ||
|
|
8b059bc9b0 | ||
|
|
cfa7155784 | ||
|
|
47644b55ed | ||
|
|
17f30ec364 | ||
|
|
c6b8d78bad | ||
|
|
ae60caacdd | ||
|
|
92d0e6809b | ||
|
|
4c7c681a14 | ||
|
|
29de052dd8 | ||
|
|
ebf2a3a7cc | ||
|
|
37311e15a3 | ||
|
|
a194cf56b3 | ||
|
|
c4f9205f17 | ||
|
|
6d09ebcfb5 | ||
|
|
319a29583d | ||
|
|
a5d47fd478 | ||
|
|
190104c7db | ||
|
|
ff16d3b3bb | ||
|
|
802755fd60 | ||
|
|
d00c0c67d0 | ||
|
|
8d636690bd | ||
|
|
b2081dca52 | ||
|
|
080a29c33b | ||
|
|
dd7a4068d2 | ||
|
|
fcf237fe31 | ||
|
|
4d70a667fb | ||
|
|
c5ba72c2c5 | ||
|
|
0f97a98f28 | ||
|
|
269e3242c8 | ||
|
|
b0ed87832b | ||
|
|
836d2125fe | ||
|
|
bf0d67c60a | ||
|
|
e1d807188d | ||
|
|
108c3a36fb | ||
|
|
8377704596 | ||
|
|
4f642f8332 | ||
|
|
029ba46470 | ||
|
|
098f8eaf2a | ||
|
|
d60bd232f0 | ||
|
|
eca1943026 | ||
|
|
bcab4bc391 | ||
|
|
bb320a64f5 | ||
|
|
3b0cde2846 | ||
|
|
00704913a6 | ||
|
|
efc388065e | ||
|
|
e12fbb7b4d | ||
|
|
0108fb2e72 | ||
|
|
e408351697 | ||
|
|
f904cd2573 | ||
|
|
95fe7ea621 | ||
|
|
a50ac039da | ||
|
|
535fba43d3 | ||
|
|
043a6c5bea | ||
|
|
8da26f1c6c | ||
|
|
7861392450 | ||
|
|
b297e40d77 | ||
|
|
7613b1769c | ||
|
|
b1b49748a7 | ||
|
|
276239422b | ||
|
|
49418e096e | ||
|
|
6c518f1403 | ||
|
|
b365765bc8 | ||
|
|
bd63948937 | ||
|
|
69c1f147ea | ||
|
|
ce8d3cf0b0 | ||
|
|
14134f8e70 | ||
|
|
be8448ddcb | ||
|
|
a2ff1536ad | ||
|
|
9c0c1b663e | ||
|
|
2d43feb34b | ||
|
|
6f315c1b3c | ||
|
|
635bdccb2c | ||
|
|
16048a879e | ||
|
|
eac80ae9c1 | ||
|
|
887b845aa0 | ||
|
|
8320179f34 | ||
|
|
7822aa784f | ||
|
|
4455ded935 | ||
|
|
fd0b850f41 | ||
|
|
d9ac1d6fd0 | ||
|
|
11e4d9fd05 | ||
|
|
4b54106f48 | ||
|
|
f3941ceab0 | ||
|
|
93f80c413e | ||
|
|
09b8a86605 | ||
|
|
6b3d54a5f3 | ||
|
|
85ab2d94b7 | ||
|
|
cda952f1e4 | ||
|
|
99ad57f88a | ||
|
|
ad0671ead2 | ||
|
|
1bbb2ef213 | ||
|
|
62c29aab32 | ||
|
|
b9dc94f28f | ||
|
|
e8ba213174 | ||
|
|
0dcddbb062 | ||
|
|
b4dab86c3b | ||
|
|
644a56a645 | ||
|
|
4876a9fde3 | ||
|
|
ec998bf9c5 | ||
|
|
e36b180de8 | ||
|
|
a2068768ab | ||
|
|
bde9fea48c | ||
|
|
cdaf84c329 | ||
|
|
c4cd0c46da | ||
|
|
3b00dc912a | ||
|
|
1a80de1290 | ||
|
|
26b565dff2 | ||
|
|
96811ccc01 | ||
|
|
73982859f6 | ||
|
|
afb7ca886c | ||
|
|
df11ad894f | ||
|
|
614b4ae84b | ||
|
|
1e1b4b1a65 | ||
|
|
cf64f9e95c | ||
|
|
dfdebd6c08 | ||
|
|
63a11f8926 | ||
|
|
a3f371b8c0 | ||
|
|
938692c169 | ||
|
|
ad24b04c35 | ||
|
|
3ccf1cf182 | ||
|
|
5e4bdb5a1b | ||
|
|
50321bb95d | ||
|
|
253c215c12 | ||
|
|
22c40ae62d | ||
|
|
239a548e9d | ||
|
|
231ef5563e | ||
|
|
e1413fa8ea | ||
|
|
7111483b65 | ||
|
|
1558497ae4 | ||
|
|
9c5e76401f | ||
|
|
a403da67bc | ||
|
|
71b13f5307 | ||
|
|
1c5561d114 | ||
|
|
c0b607ef41 | ||
|
|
462fdca4b4 | ||
|
|
0e55a60660 | ||
|
|
93deab3e96 | ||
|
|
81c69e3677 | ||
|
|
0219f4c91f | ||
|
|
85a4adc99c | ||
|
|
208d7d418e | ||
|
|
7cb6e5af8d | ||
|
|
d2a2df13d5 | ||
|
|
358e001218 | ||
|
|
d7702b3444 | ||
|
|
a8286030c0 | ||
|
|
ff0ba3e19a | ||
|
|
6f5cce7e6f | ||
|
|
509f7a8255 | ||
|
|
e8cdf72ecd | ||
|
|
2a99dfa15b | ||
|
|
bad034f7ee | ||
|
|
cdb504d700 | ||
|
|
0af2077bed | ||
|
|
dea87b7285 | ||
|
|
d6b13f3428 | ||
|
|
5808d8190e | ||
|
|
d2a5cc23cc | ||
|
|
9981ede1af | ||
|
|
40ccae57a3 | ||
|
|
3c2b8e5792 | ||
|
|
354231284e | ||
|
|
dbbfcb6a63 | ||
|
|
bc766a48ed | ||
|
|
55441f2729 | ||
|
|
e38a9ec7e1 | ||
|
|
c1356b9e0d | ||
|
|
383a17fba1 | ||
|
|
29cb153643 | ||
|
|
15625183c1 | ||
|
|
b6a1b75d22 | ||
|
|
c644ddde51 | ||
|
|
ee98a3a58e | ||
|
|
22b3a74fa0 | ||
|
|
98af51da03 | ||
|
|
e5eff3f6d5 | ||
|
|
728a256a93 | ||
|
|
f5f02ae0ee | ||
|
|
64d85587de | ||
|
|
6b7f6089ba | ||
|
|
5719a0dfd3 | ||
|
|
927bf038a0 | ||
|
|
76a93af15c | ||
|
|
ee2df36a76 | ||
|
|
571e6b2783 | ||
|
|
76cc11b786 | ||
|
|
56710f4819 | ||
|
|
f9528efdb8 | ||
|
|
658ec20e37 | ||
|
|
e6aa831782 | ||
|
|
9b56f157dc | ||
|
|
05f872effe | ||
|
|
ae691688be | ||
|
|
57f1e939c5 | ||
|
|
48b5deebf3 | ||
|
|
1868453953 | ||
|
|
dd45189fa8 | ||
|
|
a79c4fae88 | ||
|
|
657ed83921 | ||
|
|
4fb085f52d | ||
|
|
d0bb5b1565 | ||
|
|
ee64f3a745 | ||
|
|
6c81e54f76 | ||
|
|
65bf203a89 | ||
|
|
b4dbee517f | ||
|
|
e23d28a22d | ||
|
|
811d2a45bd | ||
|
|
92f4710ee2 | ||
|
|
044d8a1098 | ||
|
|
b38f45120c | ||
|
|
db3a046393 | ||
|
|
ec068e38a2 | ||
|
|
3a382e826e | ||
|
|
3dcf57a333 | ||
|
|
f658c8d3d8 | ||
|
|
375a96a5c8 | ||
|
|
b4d6724405 | ||
|
|
8fd0c4ad83 | ||
|
|
7ccae6c2b1 | ||
|
|
61d46172b9 | ||
|
|
810471b2f2 | ||
|
|
5bd8cf958a | ||
|
|
5a45997db5 | ||
|
|
f1f5100007 | ||
|
|
1c8ad4d89b | ||
|
|
842a610e84 | ||
|
|
fcb7e7a29b | ||
|
|
26e404b1f3 | ||
|
|
625d032435 | ||
|
|
3d07d65966 | ||
|
|
b705127a34 | ||
|
|
832b38c5cb | ||
|
|
3739a7b84d | ||
|
|
841f03aeba | ||
|
|
cad12b1fb7 | ||
|
|
d31cc80d26 | ||
|
|
625187a61e | ||
|
|
e64d965c6a | ||
|
|
5d8ec136e6 | ||
|
|
9951a8e106 | ||
|
|
26a9e848fd | ||
|
|
ba0b0a497f | ||
|
|
09dc43a61c | ||
|
|
b349f82571 | ||
|
|
adbb627850 | ||
|
|
c47f976bde | ||
|
|
7c8cd7a482 | ||
|
|
edce8addbd | ||
|
|
b0f6202448 | ||
|
|
985b13b6d3 | ||
|
|
69e64a9464 | ||
|
|
f58954b3be | ||
|
|
3761d17752 | ||
|
|
8c121da8a1 | ||
|
|
6e9e4543e8 | ||
|
|
c94f1b7338 | ||
|
|
f78c169c3d | ||
|
|
f2db9f3ea4 | ||
|
|
9944324c3a | ||
|
|
836f32bdbc | ||
|
|
cebbc73c38 | ||
|
|
472d703d2e | ||
|
|
de34e4e89b | ||
|
|
3a8ee126f3 | ||
|
|
da93dd1f57 | ||
|
|
295c18f6ff | ||
|
|
81beec54aa | ||
|
|
2e42226f68 | ||
|
|
de10d7984a | ||
|
|
404aab4041 | ||
|
|
8c422d6084 | ||
|
|
8b78b7292d | ||
|
|
4cebba32e2 | ||
|
|
c9f12cfbe0 | ||
|
|
5b4c92392c | ||
|
|
e2b94adec3 | ||
|
|
3164bfa043 | ||
|
|
08b443dce0 | ||
|
|
9165d27f9f | ||
|
|
b8b991398a | ||
|
|
a9a17f206e | ||
|
|
9d432546bf | ||
|
|
3c557ebd8e | ||
|
|
4efeb52cba | ||
|
|
60422c66f9 | ||
|
|
b63872afbb | ||
|
|
a31980b590 | ||
|
|
e07a3c7976 | ||
|
|
9d9a1be062 | ||
|
|
8208b3f844 | ||
|
|
ecb8297b1f | ||
|
|
1553596f84 | ||
|
|
022d9c58c2 | ||
|
|
a6cc4d80f0 | ||
|
|
7fffe3ed96 | ||
|
|
9b93a595f5 | ||
|
|
c34e08b802 | ||
|
|
eb14bb58c6 | ||
|
|
aa28069d8b | ||
|
|
a1e272f64c | ||
|
|
9908a9c662 | ||
|
|
aa089820ab | ||
|
|
0230bafae1 | ||
|
|
de577adc67 | ||
|
|
fed17d49e3 | ||
|
|
d80763f974 | ||
|
|
331e982bdb | ||
|
|
4ca7e6a6bf | ||
|
|
6ac6e0733a | ||
|
|
79d21b516b | ||
|
|
7232187f4d | ||
|
|
fe98270b3f | ||
|
|
5a3e20fc38 | ||
|
|
4ef2b111da | ||
|
|
97471626b4 | ||
|
|
4bd236b64c | ||
|
|
615dd2ecf4 | ||
|
|
1c1887f9cc | ||
|
|
d3f11a640d | ||
|
|
2341da7a06 | ||
|
|
2c468d64fb | ||
|
|
9d9b74d740 | ||
|
|
a90d4419a6 | ||
|
|
68756c79f3 | ||
|
|
8ad081e7b5 | ||
|
|
6b76704817 | ||
|
|
c03c509e73 | ||
|
|
d9db4f6c45 | ||
|
|
c89d59fe96 | ||
|
|
02b6d3748b | ||
|
|
7c3abe28b9 | ||
|
|
a39b8ccc2d | ||
|
|
5638d4ab89 | ||
|
|
37bdad290c | ||
|
|
8911434da5 | ||
|
|
8a2bbcebfd | ||
|
|
61f01f8305 | ||
|
|
a35d77b7f0 | ||
|
|
40ea1abbb4 | ||
|
|
785bfe9837 | ||
|
|
31cd54bcff | ||
|
|
35c8bb4e75 | ||
|
|
6b9ac22029 | ||
|
|
7bf3c78f57 | ||
|
|
34ee16899e | ||
|
|
0938685ae7 | ||
|
|
b400436fba | ||
|
|
2745c92fc8 | ||
|
|
34c0131b2d | ||
|
|
c9abfdcc04 | ||
|
|
a878d7aaea | ||
|
|
93aa7cea1a | ||
|
|
f00e6296e9 | ||
|
|
91354a71cc | ||
|
|
c78cb6e1d6 | ||
|
|
71430a9f65 | ||
|
|
3e93f847fd |
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
4
FAQ.md
4
FAQ.md
@@ -1,9 +1,7 @@
|
||||
FAQ - Frequently Asked Questions about repmgr
|
||||
=============================================
|
||||
|
||||
The repmgr 4 FAQ is located here:
|
||||
|
||||
https://repmgr.org/docs/appendix-faq.html
|
||||
The repmgr 4 FAQ is located here: [repmgr FAQ (Frequently Asked Questions)](https://repmgr.org/docs/4.0/appendix-faq.html "repmgr FAQ")
|
||||
|
||||
The repmgr 3.x FAQ can be found here:
|
||||
|
||||
|
||||
140
HISTORY
140
HISTORY
@@ -1,6 +1,142 @@
|
||||
4.1.0 2018-??-??
|
||||
repmgr: change default log_level to INFO, add documentation; GitHub #470 (Ian)
|
||||
repmgr: add "--missing-slots" check to "repmgr node check" (Ian)
|
||||
repmgr: improve command line error handling; GitHub #464 (Ian)
|
||||
repmgr: fix "standby register --wait-sync" when no timeout provided (Ian)
|
||||
repmgr: "cluster show" returns non-zero value if an issue encountered;
|
||||
GitHub #456 (Ian)
|
||||
repmgr: "node check" and "node status" returns non-zero value if an issue
|
||||
encountered (Ian)
|
||||
repmgr: add CSV output mode to "cluster event"; GitHub #471 (Ian)
|
||||
repmgr: add -q/--quiet option to suppress non-error output; GitHub #468 (Ian)
|
||||
repmgr: "node status" returns non-zero value if an issue encountered (Ian)
|
||||
repmgr: enable "recovery_min_apply_delay" to be 0; GitHub #448 (Ian)
|
||||
repmgr: "cluster cleanup" - add missing help options; GitHub #461/#462 (gclough)
|
||||
repmgr: ensure witness node follows new primary after switchover;
|
||||
GitHub #453 (Ian)
|
||||
repmgr: fix witness node handling in "node check"/"node status";
|
||||
GitHub #451 (Ian)
|
||||
repmgr: fix "primary_slot_name" when using "standby clone" with --recovery-conf-only;
|
||||
GitHub #474 (Ian)
|
||||
repmgr: don't perform a switchover if an exclusive backup is running;
|
||||
GitHub #476 (Martín)
|
||||
repmgr: enable "witness unregister" to be run on any node; GitHub #472 (Ian)
|
||||
repmgrd: create a PID file by default; GitHub #457 (Ian)
|
||||
repmgrd: daemonize process by default; GitHub #458 (Ian)
|
||||
|
||||
4.0.6 2018-06-14
|
||||
repmgr: (witness register) prevent registration of a witness server with the
|
||||
same name as an existing node (Ian)
|
||||
repmgr: (standby follow) check node has actually connected to new primary
|
||||
before reporting success; GitHub #444 (Ian)
|
||||
repmgr: (standby clone) improve handling of external configuration file copying,
|
||||
including consideration in --dry-run check; GitHub #443 (Ian)
|
||||
repmgr: (standby clone) don't require presence of "user" parameter in
|
||||
conninfo string; GitHub #437 (Ian)
|
||||
repmgr: (standby clone) improve documentation of --recovery-conf-only
|
||||
mode; GitHub #438 (Ian)
|
||||
repmgr: (node rejoin) fix bug when parsing --config-files parameter;
|
||||
GitHub #442 (Ian)
|
||||
repmgr: when using --dry-run, force log level to INFO to ensure output
|
||||
will always be displayed; GitHub #441 (Ian)
|
||||
repmgr: (cluster matrix/crosscheck) return non-zero exit code if node
|
||||
connection issues detected; GitHub #447 (Ian)
|
||||
repmgrd: ensure local node is counted as quorum member; GitHub #439 (Ian)
|
||||
|
||||
4.0.5 2018-05-02
|
||||
repmgr: poll demoted primary after restart as a standby during a
|
||||
switchover operation; GitHub #408 (Ian)
|
||||
repmgr: add configuration parameter "config_directory"; GitHub #424 (Ian)
|
||||
repmgr: add "dbname=replication" to all replication connection strings;
|
||||
GitHub #421 (Ian)
|
||||
repmgr: add sanity check if --upstream-node-id not supplied when executing
|
||||
"standby register"; GitHub #395 (Ian)
|
||||
repmgr: enable provision of "archive_cleanup_command" in recovery.conf;
|
||||
GitHub #416 (Ian)
|
||||
repmgr: actively check for node to rejoin cluster; GitHub #415 (Ian)
|
||||
repmgr: enable pg_rewind to be used with PostgreSQL 9.3/9.4; GitHub #413 (Ian)
|
||||
repmgr: fix minimum accepted value for "degraded_monitoring_timeout";
|
||||
GitHub #411 (Ian)
|
||||
repmgr: fix superuser password handling; GitHub #400 (Ian)
|
||||
repmgr: fix parsing of "archive_ready_critical" configuration file
|
||||
parameter; GitHub #426 (Ian)
|
||||
repmgr: fix display of conninfo parsing error messages (Ian)
|
||||
repmgr: fix "repmgr cluster crosscheck" output; GitHub #389 (Ian)
|
||||
repmgrd: prevent standby connection handle from going stale (Ian)
|
||||
repmgrd: fix memory leaks in witness code; GitHub #402 (AndrzejNowicki, Martín)
|
||||
repmgrd: handle "pg_ctl promote" timeout; GitHub #425 (Ian)
|
||||
repmgrd: handle failover situation with only two nodes in the primary
|
||||
location, and at least one node in another location; GitHub #407 (Ian)
|
||||
repmgrd: set "connect_timeout=2" when pinging a server (Ian)
|
||||
|
||||
4.0.4 2018-03-09
|
||||
repmgr: add "standby clone --recovery-conf-only" option; GitHub #382 (Ian)
|
||||
repmgr: make "standby promote" timeout values configurable; GitHub #387 (Ian)
|
||||
repmgr: improve replication slot warnings generated by "node status";
|
||||
GitHub #385 (Ian)
|
||||
repmgr: remove restriction on replication slots when cloning from
|
||||
a Barman server; GitHub #379 (Ian)
|
||||
repmgr: ensure "node rejoin" honours "--dry-run" option; GitHub #383 (Ian)
|
||||
repmgr: fix --superuser handling when cloning a standby; GitHub #380 (Ian)
|
||||
repmgr: update various help options; GitHub #391, #392 (hasegeli)
|
||||
repmgrd: add event "repmgrd_shutdown"; GitHub #393 (Ian)
|
||||
repmgrd: improve detection of status change from primary to standby (Ian)
|
||||
repmgrd: improve log output in various situations (Ian)
|
||||
repmgrd: improve reconnection to the local node after a failover (Ian)
|
||||
repmgrd: ensure witness server connects to new primary after a failover (Ian)
|
||||
|
||||
4.0.3 2018-02-15
|
||||
repmgr: improve switchover handling when "pg_ctl" used to control the
|
||||
server and logging output is not explicitly redirected (Ian)
|
||||
repmgr: improve switchover log messages and exit code when old primary could
|
||||
not be shut down cleanly (Ian)
|
||||
repmgr: check demotion candidate can make a replication connection to the
|
||||
promotion candidate before executing a switchover; GitHub #370 (Ian)
|
||||
repmgr: add check for sufficient walsenders/replication slots before executing
|
||||
a switchover; GitHub #371 (Ian)
|
||||
repmgr: add --dry-run mode to "repmgr standby follow"; GitHub #368 (Ian)
|
||||
repmgr: provide information about the primary node for "standby_register" and
|
||||
"standby_follow" event notifications; GitHub #375 (Ian)
|
||||
repmgr: add "standby_register_sync" event notification; GitHub #374 (Ian)
|
||||
repmgr: output any connection error messages in "cluster show"'s list of
|
||||
warnings; GitHub #369 (Ian)
|
||||
repmgr: ensure an inactive data directory can be deleted; GitHub #366 (Ian)
|
||||
repmgr: fix upstream node display in "repmgr node status"; GitHub #363 (fanf2)
|
||||
repmgr: improve/clarify documentation and update --help output for
|
||||
"primary unregister"; GitHub #373 (Ian)
|
||||
repmgr: allow replication slots when Barman is configured; GitHub #379 (Ian)
|
||||
repmgr: fix parsing of "pg_basebackup_options"; GitHub #376 (Ian)
|
||||
repmgr: ensure "pg_subtrans" directory is created when cloning a standby in
|
||||
Barman mode (Ian)
|
||||
repmgr: fix primary node check in "witness register"; GitHub #377 (Ian)
|
||||
|
||||
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)
|
||||
|
||||
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 +359,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)
|
||||
|
||||
@@ -11,7 +11,10 @@ EXTENSION = repmgr
|
||||
|
||||
DATA = \
|
||||
repmgr--unpackaged--4.0.sql \
|
||||
repmgr--4.0.sql
|
||||
repmgr--4.0.sql \
|
||||
repmgr--4.0--4.1.sql \
|
||||
repmgr--4.1.sql
|
||||
|
||||
|
||||
REGRESS = repmgr_extension
|
||||
|
||||
|
||||
20
TODO.md
Normal file
20
TODO.md
Normal file
@@ -0,0 +1,20 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
This file contains a list of improvements which are desireable and/or have
|
||||
been requested, and which we aim to address/implement when time and resources
|
||||
permit.
|
||||
|
||||
It is *not* a roadmap and there's no guarantee of any item being implemented
|
||||
within any given timeframe.
|
||||
|
||||
|
||||
Enable suspension of repmgrd failover
|
||||
-------------------------------------
|
||||
|
||||
When performing maintenance, e.g. a switchover, it's necessary to stop all
|
||||
repmgrd nodes to prevent unintended failover; this is obviously inconvenient.
|
||||
We'll need to implement some way of notifying each repmgrd to suspend automatic
|
||||
failover until further notice.
|
||||
|
||||
Requested in GitHub #410 ( https://github.com/2ndQuadrant/repmgr/issues/410 )
|
||||
2
compat.c
2
compat.c
@@ -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
|
||||
|
||||
2
compat.h
2
compat.h
@@ -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
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
/* config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Only build repmgr for BDR */
|
||||
#undef BDR_ONLY
|
||||
|
||||
317
configfile.c
317
configfile.c
@@ -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
|
||||
@@ -29,9 +29,6 @@ static bool config_file_provided = false;
|
||||
bool config_file_found = false;
|
||||
|
||||
static void _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
|
||||
static bool parse_bool(const char *s,
|
||||
const char *config_item,
|
||||
ItemList *error_list);
|
||||
|
||||
static void _parse_line(char *buf, char *name, char *value);
|
||||
static void parse_event_notifications_list(t_configuration_options *options, const char *arg);
|
||||
@@ -288,6 +285,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
memset(options->node_name, 0, sizeof(options->node_name));
|
||||
memset(options->conninfo, 0, sizeof(options->conninfo));
|
||||
memset(options->data_directory, 0, sizeof(options->data_directory));
|
||||
memset(options->config_directory, 0, sizeof(options->data_directory));
|
||||
memset(options->pg_bindir, 0, sizeof(options->pg_bindir));
|
||||
options->replication_type = REPLICATION_TYPE_PHYSICAL;
|
||||
|
||||
@@ -303,7 +301,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
options->log_status_interval = DEFAULT_LOG_STATUS_INTERVAL;
|
||||
|
||||
/*-----------------------
|
||||
* standby action settings
|
||||
* standby clone settings
|
||||
*------------------------
|
||||
*/
|
||||
options->use_replication_slots = false;
|
||||
@@ -314,9 +312,30 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
options->tablespace_mapping.tail = NULL;
|
||||
memset(options->recovery_min_apply_delay, 0, sizeof(options->recovery_min_apply_delay));
|
||||
options->recovery_min_apply_delay_provided = false;
|
||||
memset(options->archive_cleanup_command, 0, sizeof(options->archive_cleanup_command));
|
||||
options->use_primary_conninfo_password = false;
|
||||
memset(options->passfile, 0, sizeof(options->passfile));
|
||||
|
||||
/*-------------------------
|
||||
* standby promote settings
|
||||
*-------------------------
|
||||
*/
|
||||
options->promote_check_timeout = DEFAULT_PROMOTE_CHECK_TIMEOUT;
|
||||
options->promote_check_interval = DEFAULT_PROMOTE_CHECK_INTERVAL;
|
||||
|
||||
/*------------------------
|
||||
* standby follow settings
|
||||
*------------------------
|
||||
*/
|
||||
options->primary_follow_timeout = DEFAULT_PRIMARY_FOLLOW_TIMEOUT;
|
||||
options->standby_follow_timeout = DEFAULT_STANDBY_FOLLOW_TIMEOUT;
|
||||
|
||||
/*------------------------
|
||||
* standby switchover settings
|
||||
*------------------------
|
||||
*/
|
||||
options->standby_reconnect_timeout = DEFAULT_STANDBY_RECONNECT_TIMEOUT;
|
||||
|
||||
/*-----------------
|
||||
* repmgrd settings
|
||||
*-----------------
|
||||
@@ -336,7 +355,8 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
options->degraded_monitoring_timeout = -1;
|
||||
options->async_query_timeout = DEFAULT_ASYNC_QUERY_TIMEOUT;
|
||||
options->primary_notification_timeout = DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT;
|
||||
options->primary_follow_timeout = DEFAULT_PRIMARY_FOLLOW_TIMEOUT;
|
||||
options->repmgrd_standby_startup_timeout = -1; /* defaults to "standby_reconnect_timeout" if not set */
|
||||
memset(options->repmgrd_pid_file, 0, sizeof(options->repmgrd_pid_file));
|
||||
|
||||
/*-------------
|
||||
* witness settings
|
||||
@@ -455,6 +475,9 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
strncpy(options->conninfo, value, MAXLEN);
|
||||
else if (strcmp(name, "data_directory") == 0)
|
||||
strncpy(options->data_directory, value, MAXPGPATH);
|
||||
else if (strcmp(name, "config_directory") == 0)
|
||||
strncpy(options->config_directory, value, MAXPGPATH);
|
||||
|
||||
else if (strcmp(name, "replication_user") == 0)
|
||||
{
|
||||
if (strlen(value) < NAMEDATALEN)
|
||||
@@ -500,15 +523,38 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
parse_time_unit_parameter(name, value, options->recovery_min_apply_delay, error_list);
|
||||
options->recovery_min_apply_delay_provided = true;
|
||||
}
|
||||
else if (strcmp(name, "archive_cleanup_command") == 0)
|
||||
strncpy(options->archive_cleanup_command, value, MAXLEN);
|
||||
else if (strcmp(name, "use_primary_conninfo_password") == 0)
|
||||
options->use_primary_conninfo_password = parse_bool(value, name, error_list);
|
||||
else if (strcmp(name, "passfile") == 0)
|
||||
strncpy(options->passfile, value, sizeof(options->passfile));
|
||||
|
||||
/* standby promote settings */
|
||||
else if (strcmp(name, "promote_check_timeout") == 0)
|
||||
options->promote_check_timeout = repmgr_atoi(value, name, error_list, 1);
|
||||
|
||||
else if (strcmp(name, "promote_check_interval") == 0)
|
||||
options->promote_check_interval = repmgr_atoi(value, name, error_list, 1);
|
||||
|
||||
/* standby follow settings */
|
||||
else if (strcmp(name, "primary_follow_timeout") == 0)
|
||||
options->primary_follow_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
else if (strcmp(name, "standby_follow_timeout") == 0)
|
||||
options->standby_follow_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
|
||||
/* standby switchover settings */
|
||||
else if (strcmp(name, "standby_reconnect_timeout") == 0)
|
||||
options->standby_reconnect_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
|
||||
/* node rejoin settings */
|
||||
else if (strcmp(name, "node_rejoin_timeout") == 0)
|
||||
options->node_rejoin_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
|
||||
/* node check settings */
|
||||
else if (strcmp(name, "archive_ready_warning") == 0)
|
||||
options->archive_ready_warning = repmgr_atoi(value, name, error_list, 1);
|
||||
else if (strcmp(name, "archive_ready_critcial") == 0)
|
||||
else if (strcmp(name, "archive_ready_critical") == 0)
|
||||
options->archive_ready_critical = repmgr_atoi(value, name, error_list, 1);
|
||||
else if (strcmp(name, "replication_lag_warning") == 0)
|
||||
options->replication_lag_warning = repmgr_atoi(value, name, error_list, 1);
|
||||
@@ -549,13 +595,15 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
else if (strcmp(name, "monitoring_history") == 0)
|
||||
options->monitoring_history = parse_bool(value, name, error_list);
|
||||
else if (strcmp(name, "degraded_monitoring_timeout") == 0)
|
||||
options->degraded_monitoring_timeout = repmgr_atoi(value, name, error_list, 1);
|
||||
options->degraded_monitoring_timeout = repmgr_atoi(value, name, error_list, -1);
|
||||
else if (strcmp(name, "async_query_timeout") == 0)
|
||||
options->async_query_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
else if (strcmp(name, "primary_notification_timeout") == 0)
|
||||
options->primary_notification_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
else if (strcmp(name, "primary_follow_timeout") == 0)
|
||||
options->primary_follow_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
else if (strcmp(name, "repmgrd_standby_startup_timeout") == 0)
|
||||
options->repmgrd_standby_startup_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||
else if (strcmp(name, "repmgrd_pid_file") == 0)
|
||||
strncpy(options->repmgrd_pid_file, value, MAXPGPATH);
|
||||
|
||||
/* witness settings */
|
||||
else if (strcmp(name, "witness_sync_interval") == 0)
|
||||
@@ -671,7 +719,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
* Raise an error if a known parameter is provided with an empty
|
||||
* value. Currently there's no reason why empty parameters are needed;
|
||||
* if we want to accept those, we'd need to add stricter default
|
||||
* checking, as currently e.g. an empty `node` value will be converted
|
||||
* checking, as currently e.g. an empty `node_id` value will be converted
|
||||
* to '0'.
|
||||
*/
|
||||
if (known_parameter == true && !strlen(value))
|
||||
@@ -737,6 +785,18 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
PQconninfoFree(conninfo_options);
|
||||
}
|
||||
|
||||
|
||||
/* set values for parameters which default to other parameters */
|
||||
|
||||
/*
|
||||
* From 4.1, "repmgrd_standby_startup_timeout" replaces "standby_reconnect_timeout"
|
||||
* in repmgrd; fall back to "standby_reconnect_timeout" if no value explicitly provided
|
||||
*/
|
||||
if (options->repmgrd_standby_startup_timeout == -1)
|
||||
{
|
||||
options->repmgrd_standby_startup_timeout = options->standby_reconnect_timeout;
|
||||
}
|
||||
|
||||
/* add warning about changed "barman_" parameter meanings */
|
||||
if ((options->barman_host[0] == '\0' && options->barman_server[0] != '\0') ||
|
||||
(options->barman_host[0] != '\0' && options->barman_server[0] == '\0'))
|
||||
@@ -761,6 +821,12 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
item_list_append(error_list,
|
||||
_("\replication_lag_critical\" must be greater than \"replication_lag_warning\""));
|
||||
}
|
||||
|
||||
if (options->standby_reconnect_timeout < options->node_rejoin_timeout)
|
||||
{
|
||||
item_list_append(error_list,
|
||||
_("\"standby_reconnect_timeout\" must be equal to or greater than \"node_rejoin_timeout\""));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -925,12 +991,11 @@ parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemL
|
||||
char *ptr = NULL;
|
||||
int targ = strtol(value, &ptr, 10);
|
||||
|
||||
if (targ < 1)
|
||||
if (targ < 0)
|
||||
{
|
||||
if (errors != NULL)
|
||||
{
|
||||
item_list_append_format(
|
||||
errors,
|
||||
item_list_append_format(errors,
|
||||
_("invalid value provided for \"%s\""),
|
||||
name);
|
||||
}
|
||||
@@ -984,6 +1049,7 @@ parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemL
|
||||
* - promote_delay
|
||||
* - reconnect_attempts
|
||||
* - reconnect_interval
|
||||
* - repmgrd_standby_startup_timeout
|
||||
* - retry_promote_interval_secs
|
||||
*
|
||||
* non-changeable options
|
||||
@@ -1009,17 +1075,36 @@ reload_config(t_configuration_options *orig_options)
|
||||
static ItemList config_errors = {NULL, NULL};
|
||||
static ItemList config_warnings = {NULL, NULL};
|
||||
|
||||
PQExpBufferData errors;
|
||||
|
||||
log_info(_("reloading configuration file"));
|
||||
|
||||
_parse_config(&new_options, &config_errors, &config_warnings);
|
||||
|
||||
if (config_errors.head != NULL)
|
||||
{
|
||||
/* XXX dump errors to log */
|
||||
ItemListCell *cell = NULL;
|
||||
|
||||
log_warning(_("unable to parse new configuration, retaining current configuration"));
|
||||
|
||||
initPQExpBuffer(&errors);
|
||||
|
||||
appendPQExpBuffer(&errors,
|
||||
"following errors were detected:\n");
|
||||
|
||||
for (cell = config_errors.head; cell; cell = cell->next)
|
||||
{
|
||||
appendPQExpBuffer(&errors,
|
||||
" %s\n", cell->string);
|
||||
}
|
||||
|
||||
log_detail("%s", errors.data);
|
||||
termPQExpBuffer(&errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* The following options cannot be changed */
|
||||
|
||||
if (new_options.node_id != orig_options->node_id)
|
||||
@@ -1028,7 +1113,7 @@ reload_config(t_configuration_options *orig_options)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(new_options.node_name, orig_options->node_name) != 0)
|
||||
if (strncmp(new_options.node_name, orig_options->node_name, MAXLEN) != 0)
|
||||
{
|
||||
log_warning(_("\"node_name\" cannot be changed, keeping current configuration"));
|
||||
return false;
|
||||
@@ -1072,7 +1157,7 @@ reload_config(t_configuration_options *orig_options)
|
||||
}
|
||||
|
||||
/* conninfo */
|
||||
if (strcmp(orig_options->conninfo, new_options.conninfo) != 0)
|
||||
if (strncmp(orig_options->conninfo, new_options.conninfo, MAXLEN) != 0)
|
||||
{
|
||||
/* Test conninfo string works */
|
||||
conn = establish_db_connection(new_options.conninfo, false);
|
||||
@@ -1099,7 +1184,7 @@ reload_config(t_configuration_options *orig_options)
|
||||
}
|
||||
|
||||
/* event_notification_command */
|
||||
if (strcmp(orig_options->event_notification_command, new_options.event_notification_command) != 0)
|
||||
if (strncmp(orig_options->event_notification_command, new_options.event_notification_command, MAXLEN) != 0)
|
||||
{
|
||||
strncpy(orig_options->event_notification_command, new_options.event_notification_command, MAXLEN);
|
||||
log_info(_("\"event_notification_command\" is now \"%s\""), new_options.event_notification_command);
|
||||
@@ -1108,7 +1193,7 @@ reload_config(t_configuration_options *orig_options)
|
||||
}
|
||||
|
||||
/* event_notifications */
|
||||
if (strcmp(orig_options->event_notifications_orig, new_options.event_notifications_orig) != 0)
|
||||
if (strncmp(orig_options->event_notifications_orig, new_options.event_notifications_orig, MAXLEN) != 0)
|
||||
{
|
||||
strncpy(orig_options->event_notifications_orig, new_options.event_notifications_orig, MAXLEN);
|
||||
log_info(_("\"event_notifications\" is now \"%s\""), new_options.event_notifications_orig);
|
||||
@@ -1128,7 +1213,7 @@ reload_config(t_configuration_options *orig_options)
|
||||
}
|
||||
|
||||
/* follow_command */
|
||||
if (strcmp(orig_options->follow_command, new_options.follow_command) != 0)
|
||||
if (strncmp(orig_options->follow_command, new_options.follow_command, MAXLEN) != 0)
|
||||
{
|
||||
strncpy(orig_options->follow_command, new_options.follow_command, MAXLEN);
|
||||
log_info(_("\"follow_command\" is now \"%s\""), new_options.follow_command);
|
||||
@@ -1165,7 +1250,7 @@ reload_config(t_configuration_options *orig_options)
|
||||
|
||||
|
||||
/* promote_command */
|
||||
if (strcmp(orig_options->promote_command, new_options.promote_command) != 0)
|
||||
if (strncmp(orig_options->promote_command, new_options.promote_command, MAXLEN) != 0)
|
||||
{
|
||||
strncpy(orig_options->promote_command, new_options.promote_command, MAXLEN);
|
||||
log_info(_("\"promote_command\" is now \"%s\""), new_options.promote_command);
|
||||
@@ -1200,23 +1285,32 @@ reload_config(t_configuration_options *orig_options)
|
||||
config_changed = true;
|
||||
}
|
||||
|
||||
/* repmgrd_standby_startup_timeout */
|
||||
if (orig_options->repmgrd_standby_startup_timeout != new_options.repmgrd_standby_startup_timeout)
|
||||
{
|
||||
orig_options->repmgrd_standby_startup_timeout = new_options.repmgrd_standby_startup_timeout;
|
||||
log_info(_("\"repmgrd_standby_startup_timeout\" is now \"%i\""), new_options.repmgrd_standby_startup_timeout);
|
||||
|
||||
config_changed = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle changes to logging configuration
|
||||
*/
|
||||
|
||||
/* log_facility */
|
||||
if (strcmp(orig_options->log_facility, new_options.log_facility) != 0)
|
||||
if (strncmp(orig_options->log_facility, new_options.log_facility, MAXLEN) != 0)
|
||||
{
|
||||
strcpy(orig_options->log_facility, new_options.log_facility);
|
||||
strncpy(orig_options->log_facility, new_options.log_facility, MAXLEN);
|
||||
log_info(_("\"log_facility\" is now \"%s\""), new_options.log_facility);
|
||||
|
||||
log_config_changed = true;
|
||||
}
|
||||
|
||||
/* log_file */
|
||||
if (strcmp(orig_options->log_file, new_options.log_file) != 0)
|
||||
if (strncmp(orig_options->log_file, new_options.log_file, MAXLEN) != 0)
|
||||
{
|
||||
strcpy(orig_options->log_file, new_options.log_file);
|
||||
strncpy(orig_options->log_file, new_options.log_file, MAXLEN);
|
||||
log_info(_("\"log_file\" is now \"%s\""), new_options.log_file);
|
||||
|
||||
log_config_changed = true;
|
||||
@@ -1224,9 +1318,9 @@ reload_config(t_configuration_options *orig_options)
|
||||
|
||||
|
||||
/* log_level */
|
||||
if (strcmp(orig_options->log_level, new_options.log_level) != 0)
|
||||
if (strncmp(orig_options->log_level, new_options.log_level, MAXLEN) != 0)
|
||||
{
|
||||
strcpy(orig_options->log_level, new_options.log_level);
|
||||
strncpy(orig_options->log_level, new_options.log_level, MAXLEN);
|
||||
log_info(_("\"log_level\" is now \"%s\""), new_options.log_level);
|
||||
|
||||
log_config_changed = true;
|
||||
@@ -1292,13 +1386,23 @@ exit_with_config_file_errors(ItemList *config_errors, ItemList *config_warnings,
|
||||
|
||||
|
||||
void
|
||||
exit_with_cli_errors(ItemList *error_list)
|
||||
exit_with_cli_errors(ItemList *error_list, const char *repmgr_command)
|
||||
{
|
||||
fprintf(stderr, _("The following command line errors were encountered:\n"));
|
||||
|
||||
print_item_list(error_list);
|
||||
|
||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname());
|
||||
if (repmgr_command != NULL)
|
||||
{
|
||||
fprintf(stderr, _("Try \"%s --help\" or \"%s %s --help\" for more information.\n"),
|
||||
progname(),
|
||||
progname(),
|
||||
repmgr_command);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname());
|
||||
}
|
||||
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
@@ -1403,7 +1507,7 @@ repmgr_atoi(const char *value, const char *config_item, ItemList *error_list, in
|
||||
*
|
||||
* https://www.postgresql.org/docs/current/static/config-setting.html
|
||||
*/
|
||||
static bool
|
||||
bool
|
||||
parse_bool(const char *s, const char *config_item, ItemList *error_list)
|
||||
{
|
||||
PQExpBufferData errors;
|
||||
@@ -1600,31 +1704,112 @@ clear_event_notification_list(t_configuration_options *options)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_options *backup_options, int server_version_num, ItemList *error_list)
|
||||
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
|
||||
*/
|
||||
static ItemList option_argv = {NULL, NULL};
|
||||
ItemList option_argv = {NULL, NULL};
|
||||
|
||||
char *argv_item = NULL;
|
||||
int c,
|
||||
argc_item = 1;
|
||||
options_len = strlen(string) + 1;
|
||||
options_string = pg_malloc0(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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool
|
||||
parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_options *backup_options, int server_version_num, ItemList *error_list)
|
||||
{
|
||||
bool backup_options_ok = true;
|
||||
|
||||
int c = 0,
|
||||
argc_item = 0;
|
||||
|
||||
char **argv_array = NULL;
|
||||
ItemListCell *cell = NULL;
|
||||
|
||||
int optindex = 0;
|
||||
|
||||
struct option *long_options = NULL;
|
||||
|
||||
bool backup_options_ok = true;
|
||||
|
||||
/* We're only interested in these options */
|
||||
static struct option long_options_9[] =
|
||||
@@ -1650,56 +1835,12 @@ parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_opti
|
||||
if (!strlen(pg_basebackup_options))
|
||||
return backup_options_ok;
|
||||
|
||||
options_len = strlen(pg_basebackup_options) + 1;
|
||||
options_string = pg_malloc(options_len);
|
||||
options_string_ptr = options_string;
|
||||
|
||||
if (server_version_num >= 100000)
|
||||
long_options = long_options_10;
|
||||
else
|
||||
long_options = long_options_9;
|
||||
|
||||
/* Copy the string before operating on it with strtok() */
|
||||
strncpy(options_string, pg_basebackup_options, 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(pg_basebackup_options, &argv_array);
|
||||
|
||||
/* Reset getopt's optind variable */
|
||||
optind = 0;
|
||||
@@ -1743,15 +1884,7 @@ parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_opti
|
||||
backup_options_ok = false;
|
||||
}
|
||||
|
||||
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 backup_options_ok;
|
||||
}
|
||||
|
||||
52
configfile.h
52
configfile.h
@@ -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
|
||||
@@ -73,6 +73,7 @@ typedef struct
|
||||
char conninfo[MAXLEN];
|
||||
char replication_user[NAMEDATALEN];
|
||||
char data_directory[MAXPGPATH];
|
||||
char config_directory[MAXPGPATH];
|
||||
char pg_bindir[MAXPGPATH];
|
||||
int replication_type;
|
||||
|
||||
@@ -82,16 +83,31 @@ typedef struct
|
||||
char log_file[MAXLEN];
|
||||
int log_status_interval;
|
||||
|
||||
/* standby action settings */
|
||||
/* standby clone settings */
|
||||
bool use_replication_slots;
|
||||
char pg_basebackup_options[MAXLEN];
|
||||
char restore_command[MAXLEN];
|
||||
TablespaceList tablespace_mapping;
|
||||
char recovery_min_apply_delay[MAXLEN];
|
||||
bool recovery_min_apply_delay_provided;
|
||||
char archive_cleanup_command[MAXLEN];
|
||||
bool use_primary_conninfo_password;
|
||||
char passfile[MAXPGPATH];
|
||||
|
||||
/* standby promote settings */
|
||||
int promote_check_timeout;
|
||||
int promote_check_interval;
|
||||
|
||||
/* standby follow settings */
|
||||
int primary_follow_timeout;
|
||||
int standby_follow_timeout;
|
||||
|
||||
/* standby switchover settings */
|
||||
int standby_reconnect_timeout;
|
||||
|
||||
/* node rejoin settings */
|
||||
int node_rejoin_timeout;
|
||||
|
||||
/* node check settings */
|
||||
int archive_ready_warning;
|
||||
int archive_ready_critical;
|
||||
@@ -114,7 +130,8 @@ typedef struct
|
||||
int degraded_monitoring_timeout;
|
||||
int async_query_timeout;
|
||||
int primary_notification_timeout;
|
||||
int primary_follow_timeout;
|
||||
int repmgrd_standby_startup_timeout;
|
||||
char repmgrd_pid_file[MAXPGPATH];
|
||||
|
||||
/* BDR settings */
|
||||
bool bdr_local_monitoring_only;
|
||||
@@ -153,11 +170,20 @@ typedef struct
|
||||
|
||||
#define T_CONFIGURATION_OPTIONS_INITIALIZER { \
|
||||
/* node information */ \
|
||||
UNKNOWN_NODE_ID, "", "", "", "", "", REPLICATION_TYPE_PHYSICAL, \
|
||||
UNKNOWN_NODE_ID, "", "", "", "", "", "", REPLICATION_TYPE_PHYSICAL, \
|
||||
/* log settings */ \
|
||||
"", "", "", DEFAULT_LOG_STATUS_INTERVAL, \
|
||||
/* standby action settings */ \
|
||||
false, "", "", { NULL, NULL }, "", false, false, "", \
|
||||
/* standby clone settings */ \
|
||||
false, "", "", { NULL, NULL }, "", false, "", false, "", \
|
||||
/* standby promote settings */ \
|
||||
DEFAULT_PROMOTE_CHECK_TIMEOUT, DEFAULT_PROMOTE_CHECK_INTERVAL, \
|
||||
/* standby follow settings */ \
|
||||
DEFAULT_PRIMARY_FOLLOW_TIMEOUT, \
|
||||
DEFAULT_STANDBY_FOLLOW_TIMEOUT, \
|
||||
/* standby switchover settings */ \
|
||||
DEFAULT_STANDBY_RECONNECT_TIMEOUT, \
|
||||
/* node rejoin settings */ \
|
||||
DEFAULT_NODE_REJOIN_TIMEOUT, \
|
||||
/* node check settings */ \
|
||||
DEFAULT_ARCHIVE_READY_WARNING, DEFAULT_ARCHIVE_READY_CRITICAL, \
|
||||
DEFAULT_REPLICATION_LAG_WARNING, DEFAULT_REPLICATION_LAG_CRITICAL, \
|
||||
@@ -171,7 +197,7 @@ typedef struct
|
||||
false, -1, \
|
||||
DEFAULT_ASYNC_QUERY_TIMEOUT, \
|
||||
DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT, \
|
||||
DEFAULT_PRIMARY_FOLLOW_TIMEOUT, \
|
||||
-1, "", \
|
||||
/* BDR settings */ \
|
||||
false, DEFAULT_BDR_RECOVERY_TIMEOUT, \
|
||||
/* service settings */ \
|
||||
@@ -248,7 +274,6 @@ typedef struct
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_progname(const char *argv0);
|
||||
const char *progname(void);
|
||||
|
||||
@@ -258,19 +283,26 @@ bool reload_config(t_configuration_options *orig_options);
|
||||
|
||||
bool parse_recovery_conf(const char *data_dir, t_recovery_conf *conf);
|
||||
|
||||
bool parse_bool(const char *s,
|
||||
const char *config_item,
|
||||
ItemList *error_list);
|
||||
|
||||
int repmgr_atoi(const char *s,
|
||||
const char *config_item,
|
||||
ItemList *error_list,
|
||||
int minval);
|
||||
|
||||
|
||||
bool parse_pg_basebackup_options(const char *pg_basebackup_options,
|
||||
t_basebackup_options *backup_options,
|
||||
int server_version_num,
|
||||
ItemList *error_list);
|
||||
|
||||
int parse_output_to_argv(const char *string, char ***argv_array);
|
||||
void free_parsed_argv(char ***argv_array);
|
||||
|
||||
|
||||
/* called by repmgr-client and repmgrd */
|
||||
void exit_with_cli_errors(ItemList *error_list);
|
||||
void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
|
||||
void print_item_list(ItemList *item_list);
|
||||
|
||||
#endif /* _REPMGR_CONFIGFILE_H_ */
|
||||
|
||||
42
configure
vendored
42
configure
vendored
@@ -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.1.
|
||||
#
|
||||
# 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.1'
|
||||
PACKAGE_STRING='repmgr 4.1'
|
||||
PACKAGE_BUGREPORT='pgsql-bugs@postgresql.org'
|
||||
PACKAGE_URL='https://2ndquadrant.com/en/resources/repmgr/'
|
||||
|
||||
@@ -633,7 +633,6 @@ SHELL'
|
||||
ac_subst_files=''
|
||||
ac_user_opts='
|
||||
enable_option_checking
|
||||
with_bdr_only
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
@@ -1179,7 +1178,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.1 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1240,15 +1239,10 @@ 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.1:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||
--with-bdr-only BDR-only build
|
||||
|
||||
Some influential environment variables:
|
||||
PG_CONFIG Location to find pg_config for target PostgreSQL (default PATH)
|
||||
|
||||
@@ -1319,14 +1313,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.1
|
||||
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 +1332,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.1, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -1694,20 +1688,6 @@ ac_config_headers="$ac_config_headers config.h"
|
||||
|
||||
|
||||
|
||||
|
||||
# Check whether --with-bdr_only was given.
|
||||
if test "${with_bdr_only+set}" = set; then :
|
||||
withval=$with_bdr_only;
|
||||
fi
|
||||
|
||||
if test "x$with_bdr_only" != "x"; then :
|
||||
|
||||
$as_echo "#define BDR_ONLY \"1\"" >>confdefs.h
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
|
||||
$as_echo_n "checking for a sed that does not truncate output... " >&6; }
|
||||
if ${ac_cv_path_SED+:} false; then :
|
||||
@@ -2379,7 +2359,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.1, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -2442,7 +2422,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.1
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
10
configure.in
10
configure.in
@@ -1,17 +1,11 @@
|
||||
AC_INIT([repmgr], [4.0.0], [pgsql-bugs@postgresql.org], [repmgr], [https://2ndquadrant.com/en/resources/repmgr/])
|
||||
AC_INIT([repmgr], [4.1], [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)
|
||||
|
||||
AC_ARG_VAR([PG_CONFIG], [Location to find pg_config for target PostgreSQL (default PATH)])
|
||||
|
||||
AC_ARG_WITH([bdr_only], [AS_HELP_STRING([--with-bdr-only], [BDR-only build])])
|
||||
AS_IF([test "x$with_bdr_only" != "x"],
|
||||
[AC_DEFINE([BDR_ONLY], ["1"], [Only build repmgr for BDR])]
|
||||
)
|
||||
|
||||
|
||||
AC_PROG_SED
|
||||
|
||||
if test -z "$PG_CONFIG"; then
|
||||
|
||||
151
controldata.c
151
controldata.c
@@ -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
|
||||
@@ -37,13 +37,8 @@ get_system_identifier(const char *data_directory)
|
||||
uint64 system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
|
||||
|
||||
control_file_info = get_controlfile(data_directory);
|
||||
system_identifier = control_file_info->system_identifier;
|
||||
|
||||
if (control_file_info->control_file_processed == true)
|
||||
system_identifier = control_file_info->control_file->system_identifier;
|
||||
else
|
||||
system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
|
||||
|
||||
pfree(control_file_info->control_file);
|
||||
pfree(control_file_info);
|
||||
|
||||
return system_identifier;
|
||||
@@ -57,13 +52,8 @@ get_db_state(const char *data_directory)
|
||||
|
||||
control_file_info = get_controlfile(data_directory);
|
||||
|
||||
if (control_file_info->control_file_processed == true)
|
||||
state = control_file_info->control_file->state;
|
||||
else
|
||||
/* if we were unable to parse the control file, assume DB is shut down */
|
||||
state = DB_SHUTDOWNED;
|
||||
state = control_file_info->state;
|
||||
|
||||
pfree(control_file_info->control_file);
|
||||
pfree(control_file_info);
|
||||
|
||||
return state;
|
||||
@@ -78,12 +68,8 @@ get_latest_checkpoint_location(const char *data_directory)
|
||||
|
||||
control_file_info = get_controlfile(data_directory);
|
||||
|
||||
if (control_file_info->control_file_processed == false)
|
||||
return InvalidXLogRecPtr;
|
||||
checkPoint = control_file_info->checkPoint;
|
||||
|
||||
checkPoint = control_file_info->control_file->checkPoint;
|
||||
|
||||
pfree(control_file_info->control_file);
|
||||
pfree(control_file_info);
|
||||
|
||||
return checkPoint;
|
||||
@@ -98,16 +84,8 @@ get_data_checksum_version(const char *data_directory)
|
||||
|
||||
control_file_info = get_controlfile(data_directory);
|
||||
|
||||
if (control_file_info->control_file_processed == false)
|
||||
{
|
||||
data_checksum_version = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_checksum_version = (int) control_file_info->control_file->data_checksum_version;
|
||||
}
|
||||
data_checksum_version = (int) control_file_info->data_checksum_version;
|
||||
|
||||
pfree(control_file_info->control_file);
|
||||
pfree(control_file_info);
|
||||
|
||||
return data_checksum_version;
|
||||
@@ -139,33 +117,109 @@ describe_db_state(DBState state)
|
||||
|
||||
|
||||
/*
|
||||
* we maintain our own version of get_controlfile() as we need cross-version
|
||||
* We maintain our own version of get_controlfile() as we need cross-version
|
||||
* compatibility, and also don't care if the file isn't readable.
|
||||
*/
|
||||
static ControlFileInfo *
|
||||
get_controlfile(const char *DataDir)
|
||||
{
|
||||
ControlFileInfo *control_file_info;
|
||||
int fd;
|
||||
FILE *fp = NULL;
|
||||
int fd, ret, version_num;
|
||||
char PgVersionPath[MAXPGPATH] = "";
|
||||
char ControlFilePath[MAXPGPATH] = "";
|
||||
char file_version_string[64] = "";
|
||||
long file_major, file_minor;
|
||||
char *endptr = NULL;
|
||||
void *ControlFileDataPtr = NULL;
|
||||
int expected_size = 0;
|
||||
|
||||
control_file_info = palloc0(sizeof(ControlFileInfo));
|
||||
|
||||
/* set default values */
|
||||
control_file_info->control_file_processed = false;
|
||||
control_file_info->control_file = palloc0(sizeof(ControlFileData));
|
||||
control_file_info->system_identifier = UNKNOWN_SYSTEM_IDENTIFIER;
|
||||
control_file_info->state = DB_SHUTDOWNED;
|
||||
control_file_info->checkPoint = InvalidXLogRecPtr;
|
||||
control_file_info->data_checksum_version = -1;
|
||||
|
||||
/*
|
||||
* Read PG_VERSION, as we'll need to determine which struct to read
|
||||
* the control file contents into
|
||||
*/
|
||||
snprintf(PgVersionPath, MAXPGPATH, "%s/PG_VERSION", DataDir);
|
||||
|
||||
fp = fopen(PgVersionPath, "r");
|
||||
|
||||
if (fp == NULL)
|
||||
{
|
||||
log_warning(_("could not open file \"%s\" for reading"),
|
||||
PgVersionPath);
|
||||
log_detail("%s", strerror(errno));
|
||||
return control_file_info;
|
||||
}
|
||||
|
||||
file_version_string[0] = '\0';
|
||||
|
||||
ret = fscanf(fp, "%63s", file_version_string);
|
||||
fclose(fp);
|
||||
|
||||
if (ret != 1 || endptr == file_version_string)
|
||||
{
|
||||
log_warning(_("unable to determine major version number from PG_VERSION"));
|
||||
|
||||
return control_file_info;
|
||||
}
|
||||
|
||||
file_major = strtol(file_version_string, &endptr, 10);
|
||||
file_minor = 0;
|
||||
|
||||
if (*endptr == '.')
|
||||
file_minor = strtol(endptr + 1, NULL, 10);
|
||||
|
||||
version_num = ((int) file_major * 10000) + ((int) file_minor * 100);
|
||||
|
||||
if (version_num < 90300)
|
||||
{
|
||||
log_warning(_("Data directory appears to be initialised for %s"), file_version_string);
|
||||
return control_file_info;
|
||||
}
|
||||
|
||||
|
||||
snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
|
||||
|
||||
if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
|
||||
{
|
||||
log_debug("could not open file \"%s\" for reading: %s",
|
||||
ControlFilePath, strerror(errno));
|
||||
log_warning(_("could not open file \"%s\" for reading"),
|
||||
ControlFilePath);
|
||||
log_detail("%s", strerror(errno));
|
||||
return control_file_info;
|
||||
}
|
||||
|
||||
if (read(fd, control_file_info->control_file, sizeof(ControlFileData)) != sizeof(ControlFileData))
|
||||
|
||||
if (version_num >= 90500)
|
||||
{
|
||||
log_debug("could not read file \"%s\": %s",
|
||||
ControlFilePath, strerror(errno));
|
||||
expected_size = sizeof(ControlFileData95);
|
||||
ControlFileDataPtr = palloc0(expected_size);
|
||||
}
|
||||
else if (version_num >= 90400)
|
||||
{
|
||||
expected_size = sizeof(ControlFileData94);
|
||||
ControlFileDataPtr = palloc0(expected_size);
|
||||
}
|
||||
else if (version_num >= 90300)
|
||||
{
|
||||
expected_size = sizeof(ControlFileData93);
|
||||
ControlFileDataPtr = palloc0(expected_size);
|
||||
}
|
||||
|
||||
|
||||
if (read(fd, ControlFileDataPtr, expected_size) != expected_size)
|
||||
{
|
||||
log_warning(_("could not read file \"%s\""),
|
||||
ControlFilePath);
|
||||
log_detail("%s", strerror(errno));
|
||||
|
||||
return control_file_info;
|
||||
}
|
||||
|
||||
@@ -173,6 +227,33 @@ get_controlfile(const char *DataDir)
|
||||
|
||||
control_file_info->control_file_processed = true;
|
||||
|
||||
if (version_num >= 90500)
|
||||
{
|
||||
ControlFileData95 *ptr = (struct ControlFileData95 *)ControlFileDataPtr;
|
||||
control_file_info->system_identifier = ptr->system_identifier;
|
||||
control_file_info->state = ptr->state;
|
||||
control_file_info->checkPoint = ptr->checkPoint;
|
||||
control_file_info->data_checksum_version = ptr->data_checksum_version;
|
||||
}
|
||||
else if (version_num >= 90400)
|
||||
{
|
||||
ControlFileData94 *ptr = (struct ControlFileData94 *)ControlFileDataPtr;
|
||||
control_file_info->system_identifier = ptr->system_identifier;
|
||||
control_file_info->state = ptr->state;
|
||||
control_file_info->checkPoint = ptr->checkPoint;
|
||||
control_file_info->data_checksum_version = ptr->data_checksum_version;
|
||||
}
|
||||
else if (version_num >= 90300)
|
||||
{
|
||||
ControlFileData93 *ptr = (struct ControlFileData93 *)ControlFileDataPtr;
|
||||
control_file_info->system_identifier = ptr->system_identifier;
|
||||
control_file_info->state = ptr->state;
|
||||
control_file_info->checkPoint = ptr->checkPoint;
|
||||
control_file_info->data_checksum_version = ptr->data_checksum_version;
|
||||
}
|
||||
|
||||
pfree(ControlFileDataPtr);
|
||||
|
||||
/*
|
||||
* We don't check the CRC here as we're potentially checking a pg_control
|
||||
* file from a different PostgreSQL version to the one repmgr was compiled
|
||||
|
||||
253
controldata.h
253
controldata.h
@@ -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
|
||||
@@ -12,12 +12,261 @@
|
||||
#include "postgres_fe.h"
|
||||
#include "catalog/pg_control.h"
|
||||
|
||||
/*
|
||||
* A simplified representation of pg_control containing only those fields
|
||||
* required by repmgr.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool control_file_processed;
|
||||
ControlFileData *control_file;
|
||||
uint64 system_identifier;
|
||||
DBState state;
|
||||
XLogRecPtr checkPoint;
|
||||
uint32 data_checksum_version;
|
||||
} ControlFileInfo;
|
||||
|
||||
|
||||
|
||||
/* Same for 9.3, 9.4 */
|
||||
typedef struct CheckPoint93
|
||||
{
|
||||
XLogRecPtr redo; /* next RecPtr available when we began to
|
||||
* create CheckPoint (i.e. REDO start point) */
|
||||
TimeLineID ThisTimeLineID; /* current TLI */
|
||||
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
|
||||
* timeline (equals ThisTimeLineID otherwise) */
|
||||
bool fullPageWrites; /* current full_page_writes */
|
||||
uint32 nextXidEpoch; /* higher-order bits of nextXid */
|
||||
TransactionId nextXid; /* next free XID */
|
||||
Oid nextOid; /* next free OID */
|
||||
MultiXactId nextMulti; /* next free MultiXactId */
|
||||
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
|
||||
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
|
||||
Oid oldestXidDB; /* database with minimum datfrozenxid */
|
||||
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
|
||||
Oid oldestMultiDB; /* database with minimum datminmxid */
|
||||
pg_time_t time; /* time stamp of checkpoint */
|
||||
|
||||
TransactionId oldestActiveXid;
|
||||
} CheckPoint93;
|
||||
|
||||
|
||||
/* Same for 9.5, 9.6, 10, HEAD */
|
||||
typedef struct CheckPoint95
|
||||
{
|
||||
XLogRecPtr redo; /* next RecPtr available when we began to
|
||||
* create CheckPoint (i.e. REDO start point) */
|
||||
TimeLineID ThisTimeLineID; /* current TLI */
|
||||
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
|
||||
* timeline (equals ThisTimeLineID otherwise) */
|
||||
bool fullPageWrites; /* current full_page_writes */
|
||||
uint32 nextXidEpoch; /* higher-order bits of nextXid */
|
||||
TransactionId nextXid; /* next free XID */
|
||||
Oid nextOid; /* next free OID */
|
||||
MultiXactId nextMulti; /* next free MultiXactId */
|
||||
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
|
||||
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
|
||||
Oid oldestXidDB; /* database with minimum datfrozenxid */
|
||||
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
|
||||
Oid oldestMultiDB; /* database with minimum datminmxid */
|
||||
pg_time_t time; /* time stamp of checkpoint */
|
||||
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
|
||||
* timestamp */
|
||||
TransactionId newestCommitTsXid; /* newest Xid with valid commit
|
||||
* timestamp */
|
||||
|
||||
TransactionId oldestActiveXid;
|
||||
} CheckPoint95;
|
||||
|
||||
|
||||
typedef struct ControlFileData93
|
||||
{
|
||||
uint64 system_identifier;
|
||||
|
||||
uint32 pg_control_version; /* PG_CONTROL_VERSION */
|
||||
uint32 catalog_version_no; /* see catversion.h */
|
||||
|
||||
DBState state; /* see enum above */
|
||||
pg_time_t time; /* time stamp of last pg_control update */
|
||||
XLogRecPtr checkPoint; /* last check point record ptr */
|
||||
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
|
||||
|
||||
CheckPoint93 checkPointCopy; /* copy of last check point record */
|
||||
|
||||
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
||||
|
||||
XLogRecPtr minRecoveryPoint;
|
||||
TimeLineID minRecoveryPointTLI;
|
||||
XLogRecPtr backupStartPoint;
|
||||
XLogRecPtr backupEndPoint;
|
||||
bool backupEndRequired;
|
||||
|
||||
int wal_level;
|
||||
int MaxConnections;
|
||||
int max_prepared_xacts;
|
||||
int max_locks_per_xact;
|
||||
|
||||
uint32 maxAlign; /* alignment requirement for tuples */
|
||||
double floatFormat; /* constant 1234567.0 */
|
||||
|
||||
uint32 blcksz; /* data block size for this DB */
|
||||
uint32 relseg_size; /* blocks per segment of large relation */
|
||||
|
||||
uint32 xlog_blcksz; /* block size within WAL files */
|
||||
uint32 xlog_seg_size; /* size of each WAL segment */
|
||||
|
||||
uint32 nameDataLen; /* catalog name field width */
|
||||
uint32 indexMaxKeys; /* max number of columns in an index */
|
||||
|
||||
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
|
||||
|
||||
/* flag indicating internal format of timestamp, interval, time */
|
||||
bool enableIntTimes; /* int64 storage enabled? */
|
||||
|
||||
/* flags indicating pass-by-value status of various types */
|
||||
bool float4ByVal; /* float4 pass-by-value? */
|
||||
bool float8ByVal; /* float8, int8, etc pass-by-value? */
|
||||
|
||||
/* Are data pages protected by checksums? Zero if no checksum version */
|
||||
uint32 data_checksum_version;
|
||||
|
||||
} ControlFileData93;
|
||||
|
||||
|
||||
/*
|
||||
* Following fields added since 9.3:
|
||||
*
|
||||
* int max_worker_processes;
|
||||
* int max_prepared_xacts;
|
||||
* int max_locks_per_xact;
|
||||
*
|
||||
*/
|
||||
typedef struct ControlFileData94
|
||||
{
|
||||
uint64 system_identifier;
|
||||
|
||||
uint32 pg_control_version; /* PG_CONTROL_VERSION */
|
||||
uint32 catalog_version_no; /* see catversion.h */
|
||||
|
||||
DBState state; /* see enum above */
|
||||
pg_time_t time; /* time stamp of last pg_control update */
|
||||
XLogRecPtr checkPoint; /* last check point record ptr */
|
||||
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
|
||||
|
||||
CheckPoint93 checkPointCopy; /* copy of last check point record */
|
||||
|
||||
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
||||
|
||||
XLogRecPtr minRecoveryPoint;
|
||||
TimeLineID minRecoveryPointTLI;
|
||||
XLogRecPtr backupStartPoint;
|
||||
XLogRecPtr backupEndPoint;
|
||||
bool backupEndRequired;
|
||||
|
||||
int wal_level;
|
||||
bool wal_log_hints;
|
||||
int MaxConnections;
|
||||
int max_worker_processes;
|
||||
int max_prepared_xacts;
|
||||
int max_locks_per_xact;
|
||||
|
||||
uint32 maxAlign; /* alignment requirement for tuples */
|
||||
double floatFormat; /* constant 1234567.0 */
|
||||
|
||||
uint32 blcksz; /* data block size for this DB */
|
||||
uint32 relseg_size; /* blocks per segment of large relation */
|
||||
|
||||
uint32 xlog_blcksz; /* block size within WAL files */
|
||||
uint32 xlog_seg_size; /* size of each WAL segment */
|
||||
|
||||
uint32 nameDataLen; /* catalog name field width */
|
||||
uint32 indexMaxKeys; /* max number of columns in an index */
|
||||
|
||||
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
|
||||
uint32 loblksize; /* chunk size in pg_largeobject */
|
||||
|
||||
bool enableIntTimes; /* int64 storage enabled? */
|
||||
|
||||
bool float4ByVal; /* float4 pass-by-value? */
|
||||
bool float8ByVal; /* float8, int8, etc pass-by-value? */
|
||||
|
||||
/* Are data pages protected by checksums? Zero if no checksum version */
|
||||
uint32 data_checksum_version;
|
||||
|
||||
} ControlFileData94;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Following field added since 9.4:
|
||||
*
|
||||
* bool track_commit_timestamp;
|
||||
*
|
||||
* Unchanged in 9.6
|
||||
*
|
||||
* In 10, following field appended *after* "data_checksum_version":
|
||||
*
|
||||
* char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN];
|
||||
*
|
||||
* (but we don't care about that)
|
||||
*/
|
||||
|
||||
typedef struct ControlFileData95
|
||||
{
|
||||
uint64 system_identifier;
|
||||
|
||||
uint32 pg_control_version; /* PG_CONTROL_VERSION */
|
||||
uint32 catalog_version_no; /* see catversion.h */
|
||||
|
||||
DBState state; /* see enum above */
|
||||
pg_time_t time; /* time stamp of last pg_control update */
|
||||
XLogRecPtr checkPoint; /* last check point record ptr */
|
||||
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
|
||||
|
||||
CheckPoint95 checkPointCopy; /* copy of last check point record */
|
||||
|
||||
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
||||
|
||||
XLogRecPtr minRecoveryPoint;
|
||||
TimeLineID minRecoveryPointTLI;
|
||||
XLogRecPtr backupStartPoint;
|
||||
XLogRecPtr backupEndPoint;
|
||||
bool backupEndRequired;
|
||||
|
||||
int wal_level;
|
||||
bool wal_log_hints;
|
||||
int MaxConnections;
|
||||
int max_worker_processes;
|
||||
int max_prepared_xacts;
|
||||
int max_locks_per_xact;
|
||||
bool track_commit_timestamp;
|
||||
|
||||
uint32 maxAlign; /* alignment requirement for tuples */
|
||||
double floatFormat; /* constant 1234567.0 */
|
||||
|
||||
uint32 blcksz; /* data block size for this DB */
|
||||
uint32 relseg_size; /* blocks per segment of large relation */
|
||||
|
||||
uint32 xlog_blcksz; /* block size within WAL files */
|
||||
uint32 xlog_seg_size; /* size of each WAL segment */
|
||||
|
||||
uint32 nameDataLen; /* catalog name field width */
|
||||
uint32 indexMaxKeys; /* max number of columns in an index */
|
||||
|
||||
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
|
||||
uint32 loblksize; /* chunk size in pg_largeobject */
|
||||
|
||||
bool enableIntTimes; /* int64 storage enabled? */
|
||||
|
||||
bool float4ByVal; /* float4 pass-by-value? */
|
||||
bool float8ByVal; /* float8, int8, etc pass-by-value? */
|
||||
|
||||
uint32 data_checksum_version;
|
||||
|
||||
} ControlFileData95;
|
||||
|
||||
|
||||
|
||||
extern DBState get_db_state(const char *data_directory);
|
||||
extern const char *describe_db_state(DBState state);
|
||||
extern int get_data_checksum_version(const char *data_directory);
|
||||
|
||||
80
dbutils.h
80
dbutils.h
@@ -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
|
||||
@@ -28,8 +28,10 @@
|
||||
#include "strutil.h"
|
||||
#include "voting.h"
|
||||
|
||||
#define REPMGR_NODES_COLUMNS "node_id, type, upstream_node_id, node_name, conninfo, repluser, slot_name, location, priority, active, config_file, '' AS upstream_node_name "
|
||||
#define BDR_NODES_COLUMNS "node_sysid, node_timeline, node_dboid, node_status, node_name, node_local_dsn, node_init_from_dsn, node_read_only, node_seq_id"
|
||||
#define REPMGR_NODES_COLUMNS "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, n.config_file, '' AS upstream_node_name "
|
||||
#define BDR2_NODES_COLUMNS "node_sysid, node_timeline, node_dboid, node_name, node_local_dsn, ''"
|
||||
#define BDR3_NODES_COLUMNS "ns.node_id, 0, 0, ns.node_name, ns.interface_connstr, ns.peer_state_name"
|
||||
|
||||
|
||||
#define ERRBUFF_SIZE 512
|
||||
|
||||
@@ -74,10 +76,19 @@ typedef enum
|
||||
{
|
||||
NODE_STATUS_UNKNOWN = -1,
|
||||
NODE_STATUS_UP,
|
||||
NODE_STATUS_SHUTTING_DOWN,
|
||||
NODE_STATUS_DOWN,
|
||||
NODE_STATUS_UNCLEAN_SHUTDOWN
|
||||
} NodeStatus;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CONN_UNKNOWN = -1,
|
||||
CONN_OK,
|
||||
CONN_BAD,
|
||||
CONN_ERROR
|
||||
} ConnectionStatus;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SLOT_UNKNOWN = -1,
|
||||
@@ -85,6 +96,14 @@ typedef enum
|
||||
SLOT_ACTIVE
|
||||
} ReplSlotStatus;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BACKUP_STATE_UNKNOWN = -1,
|
||||
BACKUP_STATE_IN_BACKUP,
|
||||
BACKUP_STATE_NO_BACKUP
|
||||
} BackupState;
|
||||
|
||||
|
||||
/*
|
||||
* Struct to store node information
|
||||
*/
|
||||
@@ -174,11 +193,13 @@ typedef struct s_event_info
|
||||
{
|
||||
char *node_name;
|
||||
char *conninfo_str;
|
||||
int node_id;
|
||||
} t_event_info;
|
||||
|
||||
#define T_EVENT_INFO_INITIALIZER { \
|
||||
NULL, \
|
||||
NULL \
|
||||
NULL, \
|
||||
UNKNOWN_NODE_ID \
|
||||
}
|
||||
|
||||
|
||||
@@ -226,18 +247,14 @@ typedef struct s_bdr_node_info
|
||||
char node_sysid[MAXLEN];
|
||||
uint32 node_timeline;
|
||||
uint32 node_dboid;
|
||||
char node_status;
|
||||
char node_name[MAXLEN];
|
||||
char node_local_dsn[MAXLEN];
|
||||
char node_init_from_dsn[MAXLEN];
|
||||
bool read_only;
|
||||
uint32 node_seq_id;
|
||||
char peer_state_name[MAXLEN];
|
||||
} t_bdr_node_info;
|
||||
|
||||
#define T_BDR_NODE_INFO_INITIALIZER { \
|
||||
"", InvalidOid, InvalidOid, \
|
||||
'?', "", "", "", \
|
||||
false, -1 \
|
||||
"", "", "" \
|
||||
}
|
||||
|
||||
|
||||
@@ -332,9 +349,6 @@ bool atobool(const char *value);
|
||||
PGconn *establish_db_connection(const char *conninfo,
|
||||
const bool exit_on_error);
|
||||
PGconn *establish_db_connection_quiet(const char *conninfo);
|
||||
PGconn *establish_db_connection_as_user(const char *conninfo,
|
||||
const char *user,
|
||||
const bool exit_on_error);
|
||||
|
||||
PGconn *establish_db_connection_by_params(t_conninfo_param_list *param_list,
|
||||
const bool exit_on_error);
|
||||
@@ -345,10 +359,11 @@ PGconn *get_primary_connection(PGconn *standby_conn, int *primary_id, char *p
|
||||
PGconn *get_primary_connection_quiet(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out);
|
||||
|
||||
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
||||
void close_connection(PGconn **conn);
|
||||
|
||||
/* conninfo manipulation functions */
|
||||
bool get_conninfo_value(const char *conninfo, const char *keyword, char *output);
|
||||
|
||||
bool get_conninfo_default_value(const char *param, char *output, int maxlen);
|
||||
void initialize_conninfo_params(t_conninfo_param_list *param_list, bool set_defaults);
|
||||
void free_conninfo_params(t_conninfo_param_list *param_list);
|
||||
void copy_conninfo_params(t_conninfo_param_list *dest_list, t_conninfo_param_list *source_list);
|
||||
@@ -356,10 +371,11 @@ void conn_to_param_list(PGconn *conn, t_conninfo_param_list *param_list);
|
||||
void param_set(t_conninfo_param_list *param_list, const char *param, const char *value);
|
||||
void param_set_ine(t_conninfo_param_list *param_list, const char *param, const char *value);
|
||||
char *param_get(t_conninfo_param_list *param_list, const char *param);
|
||||
bool parse_conninfo_string(const char *conninfo_str, t_conninfo_param_list *param_list, char *errmsg, bool ignore_local_params);
|
||||
bool parse_conninfo_string(const char *conninfo_str, t_conninfo_param_list *param_list, char **errmsg, bool ignore_local_params);
|
||||
char *param_list_to_string(t_conninfo_param_list *param_list);
|
||||
bool has_passfile(void);
|
||||
|
||||
|
||||
/* transaction functions */
|
||||
bool begin_transaction(PGconn *conn);
|
||||
bool commit_transaction(PGconn *conn);
|
||||
@@ -369,10 +385,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 */
|
||||
@@ -380,11 +394,11 @@ bool get_cluster_size(PGconn *conn, char *size);
|
||||
int get_server_version(PGconn *conn, char *server_version);
|
||||
RecoveryType get_recovery_type(PGconn *conn);
|
||||
int get_primary_node_id(PGconn *conn);
|
||||
bool can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason);
|
||||
int get_ready_archive_files(PGconn *conn, const char *data_directory);
|
||||
bool identify_system(PGconn *repl_conn, t_system_identification *identification);
|
||||
bool repmgrd_set_local_node_id(PGconn *conn, int local_node_id);
|
||||
int repmgrd_get_local_node_id(PGconn *conn);
|
||||
BackupState server_in_exclusive_backup_mode(PGconn *conn);
|
||||
|
||||
/* extension functions */
|
||||
ExtensionStatus get_repmgr_extension_status(PGconn *conn);
|
||||
@@ -399,6 +413,8 @@ t_server_type parse_node_type(const char *type);
|
||||
const char *get_node_type_string(t_server_type type);
|
||||
|
||||
RecordStatus get_node_record(PGconn *conn, int node_id, t_node_info *node_info);
|
||||
RecordStatus get_node_record_with_upstream(PGconn *conn, int node_id, t_node_info *node_info);
|
||||
|
||||
RecordStatus get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info *node_info);
|
||||
t_node_info *get_node_record_pointer(PGconn *conn, int node_id);
|
||||
|
||||
@@ -409,7 +425,8 @@ void get_all_node_records(PGconn *conn, NodeInfoList *node_list);
|
||||
void get_downstream_node_records(PGconn *conn, int node_id, NodeInfoList *nodes);
|
||||
void get_active_sibling_node_records(PGconn *conn, int node_id, int upstream_node_id, NodeInfoList *node_list);
|
||||
void get_node_records_by_priority(PGconn *conn, NodeInfoList *node_list);
|
||||
void get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list);
|
||||
bool get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list);
|
||||
bool get_downstream_nodes_with_missing_slot(PGconn *conn, int this_node_id, NodeInfoList *noede_list);
|
||||
|
||||
bool create_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info);
|
||||
bool update_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info);
|
||||
@@ -418,13 +435,14 @@ bool truncate_node_records(PGconn *conn);
|
||||
|
||||
bool update_node_record_set_active(PGconn *conn, int this_node_id, bool active);
|
||||
bool update_node_record_set_primary(PGconn *conn, int this_node_id);
|
||||
bool update_node_record_set_active_standby(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,11 +455,15 @@ 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);
|
||||
int get_free_replication_slot_count(PGconn *conn);
|
||||
int get_inactive_replication_slots(PGconn *conn, KeyValueList *list);
|
||||
|
||||
/* tablespace functions */
|
||||
bool get_tablespace_name_by_location(PGconn *conn, const char *location, char *name);
|
||||
@@ -452,6 +474,8 @@ int wait_connection_availability(PGconn *conn, long long timeout);
|
||||
|
||||
/* node availability functions */
|
||||
bool is_server_available(const char *conninfo);
|
||||
bool is_server_available_params(t_conninfo_param_list *param_list);
|
||||
void connection_ping(PGconn *conn);
|
||||
|
||||
/* monitoring functions */
|
||||
void
|
||||
@@ -473,6 +497,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);
|
||||
@@ -489,21 +514,28 @@ void get_node_replication_stats(PGconn *conn, int server_version_num, t_node_in
|
||||
bool is_downstream_node_attached(PGconn *conn, char *node_name);
|
||||
|
||||
/* BDR functions */
|
||||
int get_bdr_version_num(void);
|
||||
void get_all_bdr_node_records(PGconn *conn, BdrNodeInfoList *node_list);
|
||||
RecordStatus get_bdr_node_record_by_name(PGconn *conn, const char *node_name, t_bdr_node_info *node_info);
|
||||
bool is_bdr_db(PGconn *conn, PQExpBufferData *output);
|
||||
bool is_bdr_db_quiet(PGconn *conn);
|
||||
bool is_active_bdr_node(PGconn *conn, const char *node_name);
|
||||
bool is_bdr_repmgr(PGconn *conn);
|
||||
char *get_default_bdr_replication_set(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_ */
|
||||
|
||||
208
dirutil.c
208
dirutil.c
@@ -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
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@@ -34,34 +35,33 @@
|
||||
#include "dirutil.h"
|
||||
#include "strutil.h"
|
||||
#include "log.h"
|
||||
#include "controldata.h"
|
||||
|
||||
static int unlink_dir_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
|
||||
|
||||
/* PID can be negative if backend is standalone */
|
||||
typedef long pgpid_t;
|
||||
|
||||
|
||||
/*
|
||||
* make sure the directory either doesn't exist or is empty
|
||||
* we use this function to check the new data directory and
|
||||
* the directories for tablespaces
|
||||
* Check if a directory exists, and if so whether it is empty.
|
||||
*
|
||||
* This is the same check initdb does on the new PGDATA dir
|
||||
*
|
||||
* Returns 0 if nonexistent, 1 if exists and empty, 2 if not empty,
|
||||
* or -1 if trouble accessing directory
|
||||
* This function is used for checking both the data directory
|
||||
* and tablespace directories.
|
||||
*/
|
||||
int
|
||||
DataDirState
|
||||
check_dir(char *path)
|
||||
{
|
||||
DIR *chkdir;
|
||||
struct dirent *file;
|
||||
int result = 1;
|
||||
DIR *chkdir = NULL;
|
||||
struct dirent *file = NULL;
|
||||
int result = DIR_EMPTY;
|
||||
|
||||
errno = 0;
|
||||
|
||||
chkdir = opendir(path);
|
||||
|
||||
if (!chkdir)
|
||||
return (errno == ENOENT) ? 0 : -1;
|
||||
return (errno == ENOENT) ? DIR_NOENT : DIR_ERROR;
|
||||
|
||||
while ((file = readdir(chkdir)) != NULL)
|
||||
{
|
||||
@@ -73,25 +73,15 @@ check_dir(char *path)
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 2; /* not empty */
|
||||
result = DIR_NOT_EMPTY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/*
|
||||
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
|
||||
* released version
|
||||
*/
|
||||
if (GetLastError() == ERROR_NO_MORE_FILES)
|
||||
errno = 0;
|
||||
#endif
|
||||
|
||||
closedir(chkdir);
|
||||
|
||||
if (errno != 0)
|
||||
return -1; /* some kind of I/O error? */
|
||||
return DIR_ERROR; /* some kind of I/O error? */
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -106,12 +96,13 @@ create_dir(char *path)
|
||||
if (mkdir_p(path, 0700) == 0)
|
||||
return true;
|
||||
|
||||
log_error(_("unable to create directory \"%s\": %s"),
|
||||
path, strerror(errno));
|
||||
log_error(_("unable to create directory \"%s\""), path);
|
||||
log_detail("%s", strerror(errno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
set_dir_permissions(char *path)
|
||||
{
|
||||
@@ -146,26 +137,6 @@ mkdir_p(char *path, mode_t omode)
|
||||
oumask = 0;
|
||||
retval = 0;
|
||||
|
||||
#ifdef WIN32
|
||||
/* skip network and drive specifiers for win32 */
|
||||
if (strlen(p) >= 2)
|
||||
{
|
||||
if (p[0] == '/' && p[1] == '/')
|
||||
{
|
||||
/* network drive */
|
||||
p = strstr(p + 2, "/");
|
||||
if (p == NULL)
|
||||
return 1;
|
||||
}
|
||||
else if (p[1] == ':' &&
|
||||
((p[0] >= 'a' && p[0] <= 'z') ||
|
||||
(p[0] >= 'A' && p[0] <= 'Z')))
|
||||
{
|
||||
/* local drive */
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p[0] == '/') /* Skip leading '/'. */
|
||||
++p;
|
||||
@@ -242,17 +213,91 @@ is_pg_dir(char *path)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to determine if a PostgreSQL data directory is in use
|
||||
* by reading the pidfile. This is the same mechanism used by
|
||||
* "pg_ctl".
|
||||
*
|
||||
* This function will abort with appropriate log messages if a file error
|
||||
* is encountered, as the user will need to address the situation before
|
||||
* any further useful progress can be made.
|
||||
*/
|
||||
PgDirState
|
||||
is_pg_running(char *path)
|
||||
{
|
||||
long pid;
|
||||
FILE *pidf;
|
||||
|
||||
char pid_file[MAXPGPATH];
|
||||
|
||||
/* it's reasonable to assume the pidfile name will not change */
|
||||
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", path);
|
||||
|
||||
pidf = fopen(pid_file, "r");
|
||||
if (pidf == NULL)
|
||||
{
|
||||
/*
|
||||
* No PID file - PostgreSQL shouldn't be running. From 9.3 (the
|
||||
* earliesty version we care about) removal of the PID file will
|
||||
* cause the postmaster to shut down, so it's highly unlikely
|
||||
* that PostgreSQL will still be running.
|
||||
*/
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
return PG_DIR_NOT_RUNNING;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error(_("unable to open PostgreSQL PID file \"%s\""), pid_file);
|
||||
log_detail("%s", strerror(errno));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* In the unlikely event we're unable to extract a PID from the PID file,
|
||||
* log a warning but assume we're not dealing with a running instance
|
||||
* as PostgreSQL should have shut itself down in these cases anyway.
|
||||
*/
|
||||
if (fscanf(pidf, "%ld", &pid) != 1)
|
||||
{
|
||||
/* Is the file empty? */
|
||||
if (ftell(pidf) == 0 && feof(pidf))
|
||||
{
|
||||
log_warning(_("PostgreSQL PID file \"%s\" is empty"), path);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_warning(_("invalid data in PostgreSQL PID file \"%s\""), path);
|
||||
}
|
||||
|
||||
return PG_DIR_NOT_RUNNING;
|
||||
}
|
||||
|
||||
fclose(pidf);
|
||||
|
||||
if (pid == getpid())
|
||||
return PG_DIR_NOT_RUNNING;
|
||||
|
||||
if (pid == getppid())
|
||||
return PG_DIR_NOT_RUNNING;
|
||||
|
||||
if (kill(pid, 0) == 0)
|
||||
return PG_DIR_RUNNING;
|
||||
|
||||
return PG_DIR_NOT_RUNNING;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
create_pg_dir(char *path, bool force)
|
||||
{
|
||||
bool pg_dir = false;
|
||||
|
||||
/* Check this directory could be used as a PGDATA dir */
|
||||
/* Check this directory can be used as a PGDATA dir */
|
||||
switch (check_dir(path))
|
||||
{
|
||||
case 0:
|
||||
/* dir not there, must create it */
|
||||
case DIR_NOENT:
|
||||
/* directory does not exist, attempt to create it */
|
||||
log_info(_("creating directory \"%s\"..."), path);
|
||||
|
||||
if (!create_dir(path))
|
||||
@@ -262,55 +307,62 @@ create_pg_dir(char *path, bool force)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* Present but empty, fix permissions and use it */
|
||||
log_info(_("checking and correcting permissions on existing directory %s"),
|
||||
case DIR_EMPTY:
|
||||
/* exists but empty, fix permissions and use it */
|
||||
log_info(_("checking and correcting permissions on existing directory \"%s\""),
|
||||
path);
|
||||
|
||||
if (!set_dir_permissions(path))
|
||||
{
|
||||
log_error(_("unable to change permissions of directory \"%s\":\n %s"),
|
||||
path, strerror(errno));
|
||||
log_error(_("unable to change permissions of directory \"%s\""), path);
|
||||
log_detail("%s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* Present and not empty */
|
||||
case DIR_NOT_EMPTY:
|
||||
/* exists but is not empty */
|
||||
log_warning(_("directory \"%s\" exists but is not empty"),
|
||||
path);
|
||||
|
||||
pg_dir = is_pg_dir(path);
|
||||
|
||||
if (pg_dir && force)
|
||||
if (is_pg_dir(path))
|
||||
{
|
||||
/* TODO: check DB state, if not running overwrite */
|
||||
|
||||
if (false)
|
||||
if (force == true)
|
||||
{
|
||||
log_notice(_("deleting existing data directory \"%s\""), path);
|
||||
log_notice(_("-F/--force provided - deleting existing data directory \"%s\""), path);
|
||||
nftw(path, unlink_dir_callback, 64, FTW_DEPTH | FTW_PHYS);
|
||||
return true;
|
||||
}
|
||||
/* Let it continue */
|
||||
break;
|
||||
}
|
||||
else if (pg_dir && !force)
|
||||
{
|
||||
log_hint(_("This looks like a PostgreSQL directory.\n"
|
||||
"If you are sure you want to clone here, "
|
||||
"please check there is no PostgreSQL server "
|
||||
"running and use the -F/--force option"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
default:
|
||||
else
|
||||
{
|
||||
if (force == true)
|
||||
{
|
||||
log_notice(_("deleting existing directory \"%s\""), path);
|
||||
nftw(path, unlink_dir_callback, 64, FTW_DEPTH | FTW_PHYS);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DIR_ERROR:
|
||||
log_error(_("could not access directory \"%s\": %s"),
|
||||
path, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
21
dirutil.h
21
dirutil.h
@@ -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
|
||||
@@ -19,12 +19,29 @@
|
||||
#ifndef _DIRUTIL_H_
|
||||
#define _DIRUTIL_H_
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DIR_ERROR = -1,
|
||||
DIR_NOENT,
|
||||
DIR_EMPTY,
|
||||
DIR_NOT_EMPTY
|
||||
} DataDirState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PG_DIR_ERROR = -1,
|
||||
PG_DIR_NOT_RUNNING,
|
||||
PG_DIR_RUNNING
|
||||
} PgDirState;
|
||||
|
||||
extern int mkdir_p(char *path, mode_t omode);
|
||||
extern bool set_dir_permissions(char *path);
|
||||
|
||||
extern int check_dir(char *path);
|
||||
extern DataDirState check_dir(char *path);
|
||||
extern bool create_dir(char *path);
|
||||
extern bool is_pg_dir(char *path);
|
||||
extern PgDirState is_pg_running(char *path);
|
||||
extern bool create_pg_dir(char *path, bool force);
|
||||
extern int rmdir_recursive(char *path);
|
||||
|
||||
#endif
|
||||
|
||||
2
doc/.gitignore
vendored
2
doc/.gitignore
vendored
@@ -2,4 +2,6 @@ HTML.index
|
||||
bookindex.sgml
|
||||
html-stamp
|
||||
html/
|
||||
nochunks.dsl
|
||||
repmgr.html
|
||||
version.sgml
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<appendix id="appendix-faq" xreflabel="FAQ">
|
||||
<indexterm>
|
||||
<indexterm>
|
||||
<primary>FAQ (Frequently Asked Questions)</primary>
|
||||
</indexterm>
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
series will no longer be actively maintained.
|
||||
</para>
|
||||
<para>
|
||||
repmgr 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
|
||||
with PostgreSQL 9.3, we recommend using repmgr 4.x.
|
||||
&repmgr; 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
|
||||
with PostgreSQL 9.3, we recommend using repmgr 4.x. &repmgr; 2.x is
|
||||
no longer maintained.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@@ -35,7 +36,7 @@
|
||||
Replication slots, introduced in PostgreSQL 9.4, ensure that the
|
||||
primary server will retain WAL files until they have been consumed
|
||||
by all standby servers. This makes WAL file management much easier,
|
||||
and if used `repmgr` will no longer insist on a fixed minimum number
|
||||
and if used &repmgr; will no longer insist on a fixed minimum number
|
||||
(default: 5000) of WAL files being retained.
|
||||
</para>
|
||||
<para>
|
||||
@@ -69,12 +70,50 @@
|
||||
in a streaming replication cluster.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-upgrades" xreflabel="Upgrading PostgreSQL with repmgr">
|
||||
<title>Can &repmgr; assist with upgrading a PostgreSQL cluster?</title>
|
||||
<para>
|
||||
For <emphasis>minor</emphasis> version upgrades, e.g. from 9.6.7 to 9.6.8, a common
|
||||
approach is to upgrade a standby to the latest version, perform a
|
||||
<link linkend="performing-switchover">switchover</link> promoting it to a primary,
|
||||
then upgrade the former primary.
|
||||
</para>
|
||||
<para>
|
||||
For <emphasis>major</emphasis> version upgrades (e.g. from PostgreSQL 9.6 to PostgreSQL 10),
|
||||
the traditional approach is to "reseed" a cluster by upgrading a single
|
||||
node with <ulink url="https://www.postgresql.org/docs/current/static/pgupgrade.html">pg_upgrade</ulink>
|
||||
and recloning standbys from this.
|
||||
</para>
|
||||
<para>
|
||||
To minimize downtime during major upgrades, for more recent PostgreSQL
|
||||
versions (PostgreSQL 9.4 and later),
|
||||
<ulink url="https://www.2ndquadrant.com/en/resources/pglogical/">pglogical</ulink>
|
||||
can be used to set up a parallel cluster using the newer PostgreSQL version,
|
||||
which can be kept in sync with the existing production cluster until the
|
||||
new cluster is ready to be put into production.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-libdir-repmgr-error">
|
||||
<title>What does this error mean: <literal>ERROR: could not access file "$libdir/repmgr"</literal>?</title>
|
||||
<para>
|
||||
It means the &repmgr; extension code is not installed in the
|
||||
PostgreSQL application directory. This typically happens when using PostgreSQL
|
||||
packages provided by a third-party vendor, which often have different
|
||||
filesystem layouts.
|
||||
</para>
|
||||
<para>
|
||||
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
|
||||
is not possible, contact your vendor for assistance.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="faq-repmgr" xreflabel="repmgr">
|
||||
<title><command>repmgr</command></title>
|
||||
|
||||
<sect2 id="faq-register-existing-node" xreflabel="">
|
||||
<sect2 id="faq-register-existing-node" xreflabel="registering an existing node">
|
||||
<title>Can I register an existing PostgreSQL server with repmgr?</title>
|
||||
<para>
|
||||
Yes, any existing PostgreSQL server which is part of the same replication
|
||||
@@ -83,6 +122,26 @@
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-clone-other-source" >
|
||||
<title>Can I use a standby not cloned by &repmgr; as a &repmgr; node?</title>
|
||||
|
||||
<para>
|
||||
For a standby which has been manually cloned or recovered from an external
|
||||
backup manager such as Barman, the command
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone --recovery-conf-only</link></command>
|
||||
can be used to create the correct <filename>recovery.conf</filename> file for
|
||||
use with &repmgr; (and will create a replication slot if required). Once this has been done,
|
||||
<link linkend="repmgr-standby-register">register the node</link> as usual.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-recovery-conf" >
|
||||
<title>What does &repmgr; write in <filename>recovery.conf</filename>, and what options can be set there?</title>
|
||||
<para>
|
||||
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-failed-primary-standby" xreflabel="Reintegrate a failed primary as a standby">
|
||||
<title>How can a failed primary be re-added as a standby?</title>
|
||||
<para>
|
||||
@@ -91,19 +150,23 @@
|
||||
needs to be re-registered as a standby.
|
||||
</para>
|
||||
<para>
|
||||
In PostgreSQL 9.5 and later, it's possible to use <command>pg_rewind</command>
|
||||
to re-synchronise the existing data directory, which will usually be much
|
||||
It's possible to use <command>pg_rewind</command> to re-synchronise the existing data
|
||||
directory, which will usually be much
|
||||
faster than re-cloning the server. However <command>pg_rewind</command> can only
|
||||
be used if PostgreSQL either has <varname>wal_log_hints</varname> enabled, or
|
||||
data checksums were enabled when the cluster was initialized.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; provides the command <command>repmgr node rejoin</command> which can
|
||||
optionally execute <command>pg_rewind</command>; see the <xref linkend="repmgr-node-rejoin">
|
||||
documentation for details.
|
||||
Note that <command>pg_rewind</command> is available as part of the core PostgreSQL
|
||||
distribution from PostgreSQL 9.5, and as a third-party utility for PostgreSQL 9.3 and 9.4.
|
||||
</para>
|
||||
<para>
|
||||
If <command>pg_rewind</command> cannot be used, then the data directory will have
|
||||
&repmgr; provides the command <command>repmgr node rejoin</command> which can
|
||||
optionally execute <command>pg_rewind</command>; see the <xref linkend="repmgr-node-rejoin">
|
||||
documentation for details, in particular the section <xref linkend="repmgr-node-rejoin-pg-rewind">.
|
||||
</para>
|
||||
<para>
|
||||
If <command>pg_rewind</command> cannot be used, then the data directory will need
|
||||
to be re-cloned from scratch.
|
||||
</para>
|
||||
|
||||
@@ -180,6 +243,9 @@
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="faq-repmgrd" xreflabel="repmgrd">
|
||||
|
||||
411
doc/appendix-packages.sgml
Normal file
411
doc/appendix-packages.sgml
Normal file
@@ -0,0 +1,411 @@
|
||||
<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 Packages</title>
|
||||
<indexterm>
|
||||
<primary>packages</primary>
|
||||
<secondary>CentOS packages</secondary>
|
||||
</indexterm>
|
||||
<para>
|
||||
Currently, &repmgr; RPM packages are provided for versions 6.x and 7.x of CentOS. These should also
|
||||
work on matching versions of Red Hat Enterprise Linux, Scientific Linux and Oracle Enterprise Linux;
|
||||
together with CentOS, these are the same RedHat-based distributions for which the main community project
|
||||
(PGDG) provides packages (see the <ulink url="https://yum.postgresql.org/">PostgreSQL RPM Building Project</ulink>
|
||||
page for details).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note these &repmgr; RPM packages are not designed to work with SuSE/OpenSuSE.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
&repmgr; packages are designed to be compatible with community-provided PostgreSQL packages.
|
||||
They may not work with vendor-specific packages such as those provided by RedHat for RHEL
|
||||
customers, as the filesystem layout may be different to the community RPMs.
|
||||
Please contact your support vendor for assistance.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<sect2 id="packages-centos-repositories">
|
||||
<title>CentOS repositories</title>
|
||||
|
||||
<para>
|
||||
&repmgr; packages are available from the public 2ndQuadrant repository, and also the
|
||||
PostgreSQL community repository. The 2ndQuadrant repository is updated immediately
|
||||
after each
|
||||
&repmgr; release.
|
||||
</para>
|
||||
|
||||
<table id="centos-2ndquadrant-repository">
|
||||
<title>2ndQuadrant public repository</title>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Repository URL:</entry>
|
||||
<entry><ulink url="https://rpm.2ndquadrant.com/">https://rpm.2ndquadrant.com/</ulink></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Repository documentation:</entry>
|
||||
<entry><ulink url="https://repmgr.org/docs/4.0/installation-packages.html#INSTALLATION-PACKAGES-REDHAT-2NDQ">https://repmgr.org/docs/4.0/installation-packages.html#INSTALLATION-PACKAGES-REDHAT-2NDQ</ulink></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<table id="centos-pgdg-repository">
|
||||
<title>PostgreSQL community repository (PGDG)</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>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="packages-centos-details">
|
||||
<title>CentOS package details</title>
|
||||
|
||||
<para>
|
||||
The two tables below list relevant information, paths, commands etc. for the &repmgr; packages on
|
||||
CentOS 7 (with systemd) and CentOS 6 (no systemd). Substitute the appropriate PostgreSQL major
|
||||
version number for your installation.
|
||||
</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; e.g. the
|
||||
package name is <literal>repmgr96</literal>, but the binary directory is
|
||||
<filename>/var/lib/pgsql/9.6/data</filename>.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
(package <literal>repmgr10</literal>, binary directory <filename>/var/lib/pgsql/10/data</filename>).
|
||||
</para>
|
||||
</note>
|
||||
|
||||
|
||||
<table id="centos-7-packages">
|
||||
<title>CentOS 7 packages</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
<entry>Package name example:</entry>
|
||||
<entry><filename>repmgr10-4.0.4-1.rhel7.x86_64</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Metapackage:</entry>
|
||||
<entry>(none)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Installation command:</entry>
|
||||
<entry><literal>yum install repmgr10</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Binary location:</entry>
|
||||
<entry><filename>/usr/pgsql-10/bin</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgr 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>Data directory:</entry>
|
||||
<entry><filename>/var/lib/pgsql/10/data</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgrd service command:</entry>
|
||||
<entry><command>systemctl [start|stop|restart|reload] repmgr10</command></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 by package; set in <filename>repmgr.conf</filename>)</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<table id="centos-6-packages">
|
||||
<title>CentOS 6 packages</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
<entry>Package name example:</entry>
|
||||
<entry><filename>repmgr96-4.0.4-1.rhel6.x86_64</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Metapackage:</entry>
|
||||
<entry>(none)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Installation command:</entry>
|
||||
<entry><literal>yum install repmgr96</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Binary location:</entry>
|
||||
<entry><filename>/usr/pgsql-9.6/bin</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgr 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>Data directory:</entry>
|
||||
<entry><filename>/var/lib/pgsql/9.6/data</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgrd service command:</entry>
|
||||
<entry><literal>service [start|stop|restart|reload] repmgr-9.6</literal></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>
|
||||
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
|
||||
<sect1 id="packages-debian-ubuntu" xreflabel="Debian/Ubuntu packages">
|
||||
<title>Debian/Ubuntu Packages</title>
|
||||
<indexterm>
|
||||
<primary>packages</primary>
|
||||
<secondary>Debian/Ubuntu packages</secondary>
|
||||
</indexterm>
|
||||
<para>
|
||||
&repmgr; <literal>.deb</literal> packages are provided via the
|
||||
PostgreSQL Community APT repository, and are available for each community-supported
|
||||
PostgreSQL version, currently supported Debian releases, and currently supported
|
||||
Ubuntu LTS releases.
|
||||
</para>
|
||||
|
||||
<sect2 id="packages-apt-repository">
|
||||
<title>APT repository</title>
|
||||
|
||||
<para>
|
||||
&repmgr; packages are available from the PostgreSQL Community APT repository,
|
||||
which is updated immediately after each &repmgr; release.
|
||||
</para>
|
||||
|
||||
|
||||
<table id="apt-repository">
|
||||
<title>PostgreSQL Community APT repository (PGDG)</title>
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Repository URL:</entry>
|
||||
<entry><ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</ulink></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Repository documentation:</entry>
|
||||
<entry><ulink url="https://wiki.postgresql.org/wiki/Apt)">https://wiki.postgresql.org/wiki/Apt)</ulink></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="packages-debian-details">
|
||||
<title>Debian/Ubuntu package details</title>
|
||||
|
||||
<para>
|
||||
The table below lists relevant information, paths, commands etc. for the &repmgr; packages on
|
||||
Debian 9.x ("Stretch"). Substitute the appropriate PostgreSQL major
|
||||
version number for your installation.
|
||||
</para>
|
||||
<para>
|
||||
See also <xref linkend="repmgrd-configuration-debian-ubuntu"> for some specifics related
|
||||
to configuring the <application>repmgrd</application> daemon.
|
||||
</para>
|
||||
|
||||
<table id="debian-9-packages">
|
||||
<title>Debian 9.x packages</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
<entry>Package name example:</entry>
|
||||
<entry><filename>postgresql-10-repmgr</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Metapackage:</entry>
|
||||
<entry><filename>repmgr-common</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Installation command:</entry>
|
||||
<entry><literal>apt-get install postgresql-10-repmgr</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Binary location:</entry>
|
||||
<entry><filename>/usr/lib/postgresql/10/bin</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgr in default path:</entry>
|
||||
<entry>Yes (via wrapper script <filename>/usr/bin/repmgr</filename>)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Configuration file location:</entry>
|
||||
<entry>(not set by package)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Data directory:</entry>
|
||||
<entry><filename>/var/lib/postgresql/10/main</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>PostgreSQL service command:</entry>
|
||||
<entry><command>systemctl [start|stop|restart|reload] postgresql@10-main</command></entry>
|
||||
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgrd service command:</entry>
|
||||
<entry><command>systemctl [start|stop|restart|reload] repmgrd</command></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgrd service file location:</entry>
|
||||
<entry><filename>/etc/init.d/repmgrd</filename> (defaults in: <filename>/etc/defaults/repmgrd</filename>)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgrd log file location:</entry>
|
||||
<entry>(not specified by package; set in <filename>repmgr.conf</filename>)</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
<note>
|
||||
<para>
|
||||
Instead of using the <application>systemd</application> service command directly,
|
||||
it's recommended to execute <command>pg_ctlcluster</command> (as <literal>root</literal>,
|
||||
either directly or via <command>sudo</command>), e.g.:
|
||||
<programlisting>
|
||||
<command>pg_ctlcluster 10 main [start|stop|restart|reload]</command></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
For pre-<application>systemd</application> systems, <command>pg_ctlcluster</command>
|
||||
can be executed directly by the <literal>postgres</literal> user.
|
||||
</para>
|
||||
</note>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="packages-packager-info" xreflabel="Information for packagers">
|
||||
<title>Information for packagers</title>
|
||||
<indexterm>
|
||||
<primary>packages</primary>
|
||||
<secondary>information for packagers</secondary>
|
||||
</indexterm>
|
||||
<para>
|
||||
We recommend patching the following parameters when
|
||||
building the package as built-in default values for user convenience.
|
||||
These values can nevertheless be overridden by the user, if desired.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Configuration file location: the default configuration file location
|
||||
can be hard-coded by patching <varname>package_conf_file</varname>
|
||||
in <filename>configfile.c</filename>:
|
||||
<programlisting>
|
||||
/* packagers: if feasible, patch configuration file path into "package_conf_file" */
|
||||
char package_conf_file[MAXPGPATH] = "";</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
See also: <xref linkend="configuration-file">
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
PID file location: the default <application>repmgrd</application> PID file
|
||||
location can be hard-coded by patching <varname>package_pid_file</varname>
|
||||
in <filename>repmgrd.c</filename>:
|
||||
<programlisting>
|
||||
/* packagers: if feasible, patch PID file path into "package_pid_file" */
|
||||
char package_pid_file[MAXPGPATH] = "";</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
See also: <xref linkend="repmgrd-pid-file">
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</sect1>
|
||||
</appendix>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,34 +33,5 @@
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="repmgr-rpm-key" xreflabel="repmgr rpm key">
|
||||
<title>repmgr RPM signing key</title>
|
||||
<para>
|
||||
The signing key ID used for <application>repmgr</application> source code bundles is:
|
||||
<ulink url="http://packages.2ndquadrant.com/repmgr/RPM-GPG-KEY-repmgr">
|
||||
<literal>0x702D883A</literal></ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To download the <application>repmgr</application> source key to your computer:
|
||||
<programlisting>
|
||||
curl -s http://packages.2ndquadrant.com/repmgr/RPM-GPG-KEY-repmgr | gpg --import
|
||||
gpg --fingerprint 0x702D883A
|
||||
</programlisting>
|
||||
then verify that the fingerprint is the expected value:
|
||||
<programlisting>
|
||||
AE4E 390E A58E 0037 6148 3F29 888D 018B 702D 883A</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To check a repository RPM, use <application>rpmkeys</application> to load the
|
||||
packaging signing key into the RPM database then use <literal>rpm -K</literal>, e.g.:
|
||||
<programlisting>
|
||||
sudo rpmkeys --import http://packages.2ndquadrant.com/repmgr/RPM-GPG-KEY-repmgr
|
||||
rpm -K postgresql-bdr94-2ndquadrant-redhat-1.0-2.noarch.rpm
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</appendix>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<sect2 id="cloning-from-barman-prerequisites" xreflabel="Prerequisites for cloning from Barman">
|
||||
<sect2 id="cloning-from-barman-prerequisites">
|
||||
<title>Prerequisites for cloning from Barman</title>
|
||||
<para>
|
||||
In order to enable Barman support for <command>repmgr standby clone</command>, following
|
||||
@@ -356,7 +356,7 @@
|
||||
By default, <command>pg_basebackup</command> performs a checkpoint before beginning the backup
|
||||
process. However, a normal checkpoint may take some time to complete;
|
||||
a fast checkpoint can be forced with the <literal>-c/--fast-checkpoint</literal> option.
|
||||
However this may impact performance of the server being cloned from (typically the primary)
|
||||
Note that this may impact performance of the server being cloned from (typically the primary)
|
||||
so should be used with care.
|
||||
</para>
|
||||
<tip>
|
||||
@@ -384,11 +384,16 @@
|
||||
|
||||
<sect2 id="cloning-advanced-managing-passwords" xreflabel="Managing passwords">
|
||||
<title>Managing passwords</title>
|
||||
<indexterm>
|
||||
<primary>cloning</primary>
|
||||
<secondary>using passwords</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
If replication connections to a standby's upstream server are password-protected,
|
||||
the standby must be able to provide the password so it can begin streaming
|
||||
replication.
|
||||
the standby must be able to provide the password so it can begin streaming replication.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The recommended way to do this is to store the password in the <literal>postgres</literal> system
|
||||
user's <filename>~/.pgpass</filename> file. It's also possible to store the password in the
|
||||
@@ -396,6 +401,17 @@
|
||||
security reasons. For more details see the
|
||||
<ulink url="https://www.postgresql.org/docs/current/static/libpq-pgpass.html">PostgreSQL password file documentation</ulink>.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If using a <filename>pgpass</filename> file, an entry for the replication user (by default the
|
||||
user who connects to the <literal>repmgr</literal> database) <emphasis>must</emphasis>
|
||||
be provided, with database name set to <literal>replication</literal>, e.g.:
|
||||
<programlisting>
|
||||
node1:5432:replication:repmgr:12345</programlisting>
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
If, for whatever reason, you wish to include the password in <filename>recovery.conf</filename>,
|
||||
set <varname>use_primary_conninfo_password</varname> to <literal>true</literal> in
|
||||
@@ -407,8 +423,7 @@
|
||||
</para>
|
||||
<para>
|
||||
It is of course also possible to include the password value in the <varname>conninfo</varname>
|
||||
string for each node, but this is obviously a security risk and should be
|
||||
avoided.
|
||||
string for each node, but this is obviously a security risk and should be avoided.
|
||||
</para>
|
||||
<para>
|
||||
From PostgreSQL 9.6, <application>libpq</application> supports the <varname>passfile</varname>
|
||||
|
||||
107
doc/configuration-file-log-settings.sgml
Normal file
107
doc/configuration-file-log-settings.sgml
Normal file
@@ -0,0 +1,107 @@
|
||||
<sect1 id="configuration-file-log-settings" xreflabel="log settings">
|
||||
<indexterm>
|
||||
<primary>repmgr.conf</primary>
|
||||
<secondary>log settings</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>log settings</primary>
|
||||
<secondary>configuration in repmgr.conf</secondary>
|
||||
</indexterm>
|
||||
<title>Log settings</title>
|
||||
|
||||
<para>
|
||||
By default, &repmgr; and <application>repmgrd</application> write log output to
|
||||
<literal>STDERR</literal>. An alternative log destination can be specified
|
||||
(either a file or <literal>syslog</literal>).
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
The &repmgr; application itself will continue to write log output to <literal>STDERR</literal>
|
||||
even if another log destination is configured, as otherwise any output resulting from a command
|
||||
line operation will "disappear" into the log.
|
||||
</para>
|
||||
<para>
|
||||
This behaviour can be overriden with the command line option <option>--log-to-file</option>,
|
||||
which will redirect all logging output to the configured log destination. This is recommended
|
||||
when &repmgr; is executed by another application, particularly <application>repmgrd</application>,
|
||||
to enable log output generated by the &repmgr; application to be stored for later reference.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry id="repmgr-conf-log-level" xreflabel="log_level">
|
||||
<term><varname>log_level</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>log_level</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
One of <option>DEBUG</option>, <option>INFO</option>, <option>NOTICE</option>,
|
||||
<option>WARNING</option>, <option>ERROR</option>, <option>ALERT</option>, <option>CRIT</option>
|
||||
or <option>EMERG</option>.
|
||||
</para>
|
||||
<para>
|
||||
Default is <option>INFO</option>.
|
||||
</para>
|
||||
<para>
|
||||
Note that <option>DEBUG</option> will produce a substantial amount of log output
|
||||
and should not be enabled in normal use.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-log-facility" xreflabel="log_facility">
|
||||
<term><varname>log_facility</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>log_facility</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Logging facility: possible values are <option>STDERR</option> (default), or for
|
||||
syslog integration, one of <option>LOCAL0</option>, <option>LOCAL1</option>, <option>...</option>,
|
||||
<option>LOCAL7</option>, <option>USER</option>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-log-file" xreflabel="log_file">
|
||||
<term><varname>log_file</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>log_file</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If <xref linkend="repmgr-conf-log-facility"> is set to <option>STDERR</option>, log output
|
||||
can be redirected to the specified file.
|
||||
</para>
|
||||
<para>
|
||||
See <xref linkend="repmgrd-log-rotation"> for information on configuring log rotation.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-log-status-interval" xreflabel="log_status_interval">
|
||||
<term><varname>log_status_interval</varname> (<type>integer</type>)
|
||||
<indexterm>
|
||||
<primary><varname>log_status_interval</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This setting causes <application>repmgrd</application> to emit a status log
|
||||
line at the specified interval (in seconds, default <literal>300</literal>)
|
||||
describing <application>repmgrd</application>'s current state, e.g.:
|
||||
</para>
|
||||
<programlisting>
|
||||
[2018-07-12 00:47:32] [INFO] monitoring connection to upstream node "node1" (node ID: 1)</programlisting>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</sect1>
|
||||
@@ -1,10 +1,10 @@
|
||||
<sect1 id="configuration-file-settings" xreflabel="configuration file settings">
|
||||
<sect1 id="configuration-file-settings" xreflabel="required configuration file settings">
|
||||
<indexterm>
|
||||
<primary>repmgr.conf</primary>
|
||||
<secondary>settings</secondary>
|
||||
<secondary>required settings</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>Configuration file settings</title>
|
||||
<title>Required configuration file settings</title>
|
||||
<para>
|
||||
Each <filename>repmgr.conf</filename> file must contain the following parameters:
|
||||
</para>
|
||||
@@ -92,7 +92,10 @@
|
||||
|
||||
<para>
|
||||
For a full list of annotated configuration items, see the file
|
||||
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</>.
|
||||
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
For <application>repmgrd</application>-specific settings, see <xref linkend="repmgrd-configuration">.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
123
doc/configuration-file-service-commands.sgml
Normal file
123
doc/configuration-file-service-commands.sgml
Normal file
@@ -0,0 +1,123 @@
|
||||
<sect1 id="configuration-file-service-commands" xreflabel="service command settings">
|
||||
<indexterm>
|
||||
<primary>repmgr.conf</primary>
|
||||
<secondary>service command settings</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>service command settings</primary>
|
||||
<secondary>configuration in repmgr.conf</secondary>
|
||||
</indexterm>
|
||||
<title>Service command settings</title>
|
||||
|
||||
<para>
|
||||
In some circumstances, &repmgr; (and <application>repmgrd</application>) need to
|
||||
be able to stop, start or restart PostgreSQL. &repmgr; commands which need to do this
|
||||
include <link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>,
|
||||
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link> and
|
||||
<link linkend="repmgr-node-rejoin"><command>repmgr node rejoin</command></link>.
|
||||
</para>
|
||||
<para>
|
||||
By default, &repmgr; will use PostgreSQL's <command>pg_ctl</command> to control the PostgreSQL
|
||||
server. However this can lead to various problems, particularly when PostgreSQL has been
|
||||
installed from packages, and expecially so if <application>systemd</application> is in use.
|
||||
</para>
|
||||
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If using <application>systemd</application>, ensure you have <varname>RemoteIPC</varname> set to <literal>off</literal>.
|
||||
See the <ulink url="https://wiki.postgresql.org/wiki/Systemd">systemd</ulink>
|
||||
entry in the <ulink url="https://wiki.postgresql.org/wiki/Main_Page">PostgreSQL wiki</ulink> for details.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
|
||||
<para>
|
||||
With this in mind, we recommend to <emphasis>always</emphasis> configure &repmgr; to use the
|
||||
available system service commands.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To do this, specify the appropriate command for each action
|
||||
in <filename>repmgr.conf</filename> using the following configuration
|
||||
parameters:
|
||||
<programlisting>
|
||||
service_start_command
|
||||
service_stop_command
|
||||
service_restart_command
|
||||
service_reload_command</programlisting>
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
It's also possible to specify a <varname>service_promote_command</varname>.
|
||||
This is intended for systems which provide a package-level promote command,
|
||||
such as Debian's <application>pg_ctlcluster</application>, to promote the
|
||||
PostgreSQL from standby to primary.
|
||||
</para>
|
||||
<para>
|
||||
If your packaging system does not provide such a command, it can be left empty,
|
||||
and &repmgr; will generate the appropriate `pg_ctl ... promote` command.
|
||||
</para>
|
||||
<para>
|
||||
Do not confuse this with <varname>promote_command</varname>, which is used
|
||||
by <application>repmgrd</application> to execute <xref linkend="repmgr-standby-promote">.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
To confirm which command &repmgr; will execute for each action, use
|
||||
<command>repmgr node service --list --action=...</command>, e.g.:
|
||||
<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
|
||||
repmgr -f /etc/repmgr.conf node service --list --action=reload</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
These commands will be executed by the system user which &repmgr; runs as (usually <literal>postgres</literal>)
|
||||
and will probably require passwordless sudo access to be able to execute the command.
|
||||
</para>
|
||||
<para>
|
||||
For example, using <application>systemd</application> on CentOS 7, the service commands can be
|
||||
set as follows:
|
||||
<programlisting>
|
||||
service_start_command = 'sudo systemctl start postgresql-9.6'
|
||||
service_stop_command = 'sudo systemctl stop postgresql-9.6'
|
||||
service_restart_command = 'sudo systemctl restart postgresql-9.6'
|
||||
service_reload_command = 'sudo systemctl reload postgresql-9.6'</programlisting>
|
||||
and <filename>/etc/sudoers</filename> should be set as follows:
|
||||
<programlisting>
|
||||
Defaults:postgres !requiretty
|
||||
postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-9.6, \
|
||||
/usr/bin/systemctl start postgresql-9.6, \
|
||||
/usr/bin/systemctl restart postgresql-9.6 \
|
||||
/usr/bin/systemctl reload postgresql-9.6</programlisting>
|
||||
</para>
|
||||
|
||||
<important>
|
||||
<indexterm>
|
||||
<primary>pg_ctlcluster</primary>
|
||||
<secondary>service command settings</secondary>
|
||||
</indexterm>
|
||||
<para>
|
||||
Debian/Ubuntu users: instead of calling <command>sudo systemctl</command> directly, use
|
||||
<command>sudo pg_ctlcluster</command>, e.g.:
|
||||
<programlisting>
|
||||
service_start_command = 'sudo pg_ctlcluster 9.6 main start'
|
||||
service_stop_command = 'sudo pg_ctlcluster 9.6 main stop'
|
||||
service_restart_command = 'sudo pg_ctlcluster 9.6 main restart'
|
||||
service_reload_command = 'sudo pg_ctlcluster 9.6 main reload'</programlisting>
|
||||
and set <filename>/etc/sudoers</filename> accordingly.
|
||||
</para>
|
||||
<para>
|
||||
While <command>pg_ctlcluster</command> will work when executed as user <literal>postgres</literal>,
|
||||
it's strongly recommended to use <command>sudo pg_ctlcluster</command> on <application>systemd</application>
|
||||
systems, to ensure <application>systemd</application> has a correct picture of
|
||||
the PostgreSQL application state.
|
||||
</para>
|
||||
|
||||
</important>
|
||||
|
||||
</sect1>
|
||||
@@ -2,15 +2,17 @@
|
||||
<title>repmgr configuration</title>
|
||||
|
||||
&configuration-file;
|
||||
&configuration-file-settings;
|
||||
&configuration-file-required-settings;
|
||||
&configuration-file-log-settings;
|
||||
&configuration-file-service-commands;
|
||||
|
||||
<sect1 id="configuration-permissions" xreflabel="User permissions">
|
||||
<sect1 id="configuration-permissions" xreflabel="Database user permissions">
|
||||
<indexterm>
|
||||
<primary>configuration</primary>
|
||||
<secondary>user permissions</secondary>
|
||||
<secondary>database user permissions</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>repmgr user permissions</title>
|
||||
<title>repmgr database user permissions</title>
|
||||
<para>
|
||||
&repmgr; will create an extension database containing objects
|
||||
for administering &repmgr; metadata. The user defined in the <varname>conninfo</varname>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
<para>
|
||||
This parameter accepts the following format placeholders:
|
||||
The following format placeholders are provided for all event notifications:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
@@ -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>
|
||||
@@ -85,6 +85,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
The values provided for <literal>%t</literal> and <literal>%d</literal>
|
||||
will probably contain spaces, so should be quoted in the provided command
|
||||
@@ -93,42 +94,75 @@
|
||||
event_notification_command='/path/to/some/script %n %e %s "%t" "%d"'
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Additionally the following format placeholders are available for the event
|
||||
type <varname>bdr_failover</varname> and optionally <varname>bdr_recovery</varname>:
|
||||
The following parameters are provided for a subset of event notifications:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>%p</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
node ID of the current primary (<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
|
||||
</para>
|
||||
<para>
|
||||
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"> only)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>%c</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
conninfo string of the next available node
|
||||
<literal>conninfo</literal> string of the primary node
|
||||
(<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
|
||||
</para>
|
||||
<para>
|
||||
<literal>conninfo</literal> string of the next available node
|
||||
(<varname>bdr_failover</varname> and <varname>bdr_recovery</varname>)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>%a</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
name of the next available node
|
||||
name of the current primary node (<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
|
||||
</para>
|
||||
<para>
|
||||
name of the next available node (<varname>bdr_failover</varname> and <varname>bdr_recovery</varname>)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
These should always be quoted.
|
||||
The values provided for <literal>%c</literal> and <literal>%a</literal>
|
||||
will probably contain spaces, so should always be quoted.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
By default, all notification types will be passed to the designated script;
|
||||
the notification types can be filtered to explicitly named ones:
|
||||
the notification types can be filtered to explicitly named ones using the
|
||||
<varname>event_notifications</varname> parameter:
|
||||
|
||||
<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>
|
||||
<listitem>
|
||||
<simpara><literal>standby_register_sync</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>standby_unregister</literal></simpara>
|
||||
</listitem>
|
||||
@@ -144,6 +178,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>
|
||||
@@ -156,6 +205,18 @@
|
||||
<listitem>
|
||||
<simpara><literal>repmgrd_failover_follow</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>repmgrd_failover_aborted</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>repmgrd_upstream_disconnect</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>repmgrd_upstream_reconnect</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>repmgrd_promote_error</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>bdr_failover</literal></simpara>
|
||||
</listitem>
|
||||
@@ -174,6 +235,7 @@
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that under some circumstances (e.g. when no replication cluster primary
|
||||
could be located), it will not be possible to write an entry into the
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
<!ENTITY quickstart SYSTEM "quickstart.sgml">
|
||||
<!ENTITY configuration SYSTEM "configuration.sgml">
|
||||
<!ENTITY configuration-file SYSTEM "configuration-file.sgml">
|
||||
<!ENTITY configuration-file-settings SYSTEM "configuration-file-settings.sgml">
|
||||
<!ENTITY configuration-file-required-settings SYSTEM "configuration-file-required-settings.sgml">
|
||||
<!ENTITY configuration-file-log-settings SYSTEM "configuration-file-log-settings.sgml">
|
||||
<!ENTITY configuration-file-service-commands SYSTEM "configuration-file-service-commands.sgml">
|
||||
<!ENTITY cloning-standbys SYSTEM "cloning-standbys.sgml">
|
||||
<!ENTITY promoting-standby SYSTEM "promoting-standby.sgml">
|
||||
<!ENTITY follow-new-primary SYSTEM "follow-new-primary.sgml">
|
||||
@@ -80,6 +82,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">
|
||||
|
||||
|
||||
@@ -5,28 +5,151 @@
|
||||
system.
|
||||
</para>
|
||||
|
||||
<sect2 id="installation-packages-redhat" xreflabel="Installing from packages on RHEL, Fedora and CentOS">
|
||||
<sect2 id="installation-packages-redhat" xreflabel="Installing from packages on RHEL, CentOS and Fedora">
|
||||
|
||||
<indexterm>
|
||||
<primary>installation</primary>
|
||||
<secondary>on Redhat/CentOS/Fedora etc.</secondary>
|
||||
<secondary>on Red Hat/CentOS/Fedora etc.</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>RedHat/Fedora/CentOS</title>
|
||||
<title>RedHat/CentOS/Fedora</title>
|
||||
<para>
|
||||
RPM packages for &repmgr; are available via Yum through
|
||||
&repmgr; RPM packages for RedHat/CentOS variants and Fedora are available from the
|
||||
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
|
||||
<ulink url="https://rpm.2ndquadrant.com/">public RPM repository</ulink>; see following
|
||||
section for details.
|
||||
</para>
|
||||
<para>
|
||||
RPM packages for &repmgr; are also 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.
|
||||
Fedora, etc.) and architecture as detailed there. Note that it can take some days
|
||||
for new &repmgr; packages to become available via the this repository.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
&repmgr; packages are designed to be compatible with the community-provided PostgreSQL packages.
|
||||
They may not work with vendor-specific packages such as those provided by RedHat for RHEL
|
||||
customers, as the filesystem layout may be different to the community RPMs.
|
||||
Please contact your support vendor for assistance.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
<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</>
|
||||
For more information on the package contents, including details of installation
|
||||
paths and relevant <link linkend="configuration-file-service-commands">service commands</link>,
|
||||
see the appendix section <xref linkend="packages-centos">.
|
||||
</para>
|
||||
|
||||
|
||||
<sect3 id="installation-packages-redhat-2ndq">
|
||||
<title>2ndQuadrant public RPM yum repository</title>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink> previously provided a dedicated
|
||||
&repmgr; repository at
|
||||
<ulink url="http://packages.2ndquadrant.com/repmgr/">http://packages.2ndquadrant.com/repmgr/</ulink>.
|
||||
This repository will be deprecated in a future release as it is now replaced by
|
||||
the <ulink url="https://rpm.2ndquadrant.com/">public RPM repository</ulink>
|
||||
documented below.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
Beginning with <ulink url="https://repmgr.org/docs/4.0/release-4.0.5.html">repmgr 4.0.5</ulink>,
|
||||
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a dedicated <literal>yum</literal>
|
||||
<ulink url="https://rpm.2ndquadrant.com/">public RPM repository</ulink> for 2ndQuadrant software,
|
||||
including &repmgr;. We recommend using this for all future &repmgr; releases.
|
||||
</para>
|
||||
<para>
|
||||
General instructions for using this repository can be found on its
|
||||
<ulink url="https://rpm.2ndquadrant.com/">homepage</ulink>. Specific instructions
|
||||
for installing &repmgr; follow below.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>Installation</emphasis>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Locate the repository RPM for your PostgreSQL version from the list at:
|
||||
<ulink url="https://rpm.2ndquadrant.com/">https://rpm.2ndquadrant.com/</ulink>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the repository RPM for your distribution and PostgreSQL version
|
||||
(this enables the 2ndQuadrant repository as a source of &repmgr; packages).
|
||||
</para>
|
||||
<para>
|
||||
For example, for PostgreSQL 10 on CentOS, execute:
|
||||
<programlisting>
|
||||
sudo yum install https://rpm.2ndquadrant.com/site/content/2ndquadrant-repo-10-1-1.el7.noarch.rpm
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Verify that the repository is installed with:
|
||||
<programlisting>
|
||||
sudo yum repolist</programlisting>
|
||||
The output should contain two entries like this:
|
||||
<programlisting>
|
||||
2ndquadrant-repo-10/7/x86_64 2ndQuadrant packages for PG10 for rhel 7 - x86_64 1
|
||||
2ndquadrant-repo-10-debug/7/x86_64 2ndQuadrant packages for PG10 for rhel 7 - x86_64 - Debug 1</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the &repmgr version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
||||
<programlisting>
|
||||
$ yum install repmgr10</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Compatibility with PGDG Repositories</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
The 2ndQuadrant &repmgr; yum repository packages use the same definitions and file system layout as the
|
||||
main PGDG repository.
|
||||
</para>
|
||||
<para>
|
||||
Normally <application>yum</application> will 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 repmgr10
|
||||
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
|
||||
repmgr10.x86_64 4.0.3-1.rhel7 pgdg10
|
||||
repmgr10.x86_64 4.0.4-1.rhel7 pgdg10
|
||||
repmgr10.x86_64 4.0.5-1.el7 2ndquadrant-repo-10</programlisting>
|
||||
then append the appropriate version number to the package name with a hyphen, e.g.:
|
||||
<programlisting>
|
||||
[root@localhost ~]# yum install repmgr10-4.0.3-1.rhel7</programlisting>
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="installation-packages-debian" xreflabel="Installing from packages on Debian or Ubuntu">
|
||||
@@ -38,10 +161,89 @@
|
||||
|
||||
<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>
|
||||
<para>
|
||||
For more information on the package contents, including details of installation
|
||||
paths and relevant <link linkend="configuration-file-service-commands">service commands</link>,
|
||||
see the appendix section <xref linkend="packages-debian-ubuntu">.
|
||||
</para>
|
||||
|
||||
<sect3 id="installation-packages-debian-ubuntu-2ndq">
|
||||
<title>2ndQuadrant public apt repository for Debian/Ubuntu</title>
|
||||
|
||||
<para>
|
||||
Beginning with <ulink url="https://repmgr.org/docs/4.0/release-4.0.5.html">repmgr 4.0.5</ulink>,
|
||||
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a
|
||||
<ulink url="https://apt.2ndquadrant.com/">public apt repository</ulink> for 2ndQuadrant software,
|
||||
including &repmgr;.
|
||||
</para>
|
||||
<para>
|
||||
General instructions for using this repository can be found on its
|
||||
<ulink url="https://apt.2ndquadrant.com/">homepage</ulink>. Specific instructions
|
||||
for installing &repmgr; follow below.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Installation</emphasis>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
If not already present, install the <application>apt-transport-https</application> package:
|
||||
<programlisting>
|
||||
sudo apt-get install apt-transport-https</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Create <filename>/etc/apt/sources.list.d/2ndquadrant.list</filename> as follows:
|
||||
<programlisting>
|
||||
sudo sh -c 'echo "deb https://apt.2ndquadrant.com/ $(lsb_release -cs)-2ndquadrant main" > /etc/apt/sources.list.d/2ndquadrant.list'</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the 2ndQuadrant <ulink url="https://apt.2ndquadrant.com/site/keys/9904CD4BD6BAF0C3.asc">repository key</ulink>:
|
||||
<programlisting>
|
||||
sudo apt-get install curl ca-certificates
|
||||
curl https://apt.2ndquadrant.com/site/keys/9904CD4BD6BAF0C3.asc | sudo apt-key add -</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Update the package list
|
||||
<programlisting>
|
||||
sudo apt-get update</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the &repmgr version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
||||
<programlisting>
|
||||
$ apt-get install postgresql-10-repmgr</programlisting>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
For packages for PostgreSQL 9.6 and earlier, the package name includes
|
||||
a period between major and minor version numbers, e.g.
|
||||
<literal>postgresql-9.6-repmgr</literal>.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are also tags for each &repmgr; release, e.g. <filename>REL4_0_STABLE</filename>.
|
||||
There are also tags for each &repmgr; release, e.g. <filename>4.0.5</filename>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -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>
|
||||
|
||||
|
||||
|
||||
@@ -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 © 2010-2017
|
||||
<productname>repmgr</productname> is Copyright © 2010-2018
|
||||
by 2ndQuadrant, Ltd. All rights reserved.
|
||||
</para>
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<title>repmgr overview</title>
|
||||
|
||||
<para>
|
||||
This chapter provides a high-level overview of repmgr's components and functionality.
|
||||
This chapter provides a high-level overview of &repmgr;'s components and
|
||||
functionality.
|
||||
</para>
|
||||
<sect1 id="repmgr-concepts" xreflabel="Concepts">
|
||||
|
||||
@@ -178,8 +179,8 @@
|
||||
<para>
|
||||
In order to effectively manage a replication cluster, &repmgr; needs to store
|
||||
information about the servers in the cluster in a dedicated database schema.
|
||||
This schema is automatically by the &repmgr; extension, which is installed
|
||||
during the first step in initialising a &repmgr;-administered cluster
|
||||
This schema is automatically created by the &repmgr; extension, which is installed
|
||||
during the first step in initializing a &repmgr;-administered cluster
|
||||
(<command><link linkend="repmgr-primary-register">repmgr primary register</link></command>)
|
||||
and contains the following objects:
|
||||
<variablelist>
|
||||
|
||||
@@ -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">
|
||||
@@ -229,7 +234,7 @@
|
||||
<para>
|
||||
<filename>repmgr.conf</filename> should not be stored inside the PostgreSQL data directory,
|
||||
as it could be overwritten when setting up or reinitialising the PostgreSQL
|
||||
server. See sections on <xref linkend="configuration-file"> and <xref linkend="configuration-file-settings">
|
||||
server. See sections <xref linkend="configuration"> and <xref linkend="configuration-file">
|
||||
for further details about <filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
<tip>
|
||||
@@ -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>
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<chapter id="repmgrd-bdr">
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>BDR</secondary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>BDR</primary>
|
||||
</indexterm>
|
||||
|
||||
<title>BDR failover with repmgrd</title>
|
||||
<para>
|
||||
&repmgr; 4.x provides support for monitoring BDR nodes and taking action in
|
||||
case one of the nodes fails.
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
Due to the nature of BDR, it's only safe to use this solution for
|
||||
a two-node scenario. Introducing additional nodes will create an inherent
|
||||
risk of node desynchronisation if a node goes down without being cleanly
|
||||
removed from the cluster.
|
||||
</simpara>
|
||||
</note>
|
||||
<para>
|
||||
In contrast to streaming replication, there's no concept of "promoting" a new
|
||||
primary node with BDR. Instead, "failover" involves monitoring both nodes
|
||||
with `repmgrd` and redirecting queries from the failed node to the remaining
|
||||
active node. This can be done by using an
|
||||
<link linkend="event-notifications">event notification</link> script
|
||||
which is called by <application>repmgrd</application> to dynamically
|
||||
reconfigure a proxy server/connection pooler such as <application>PgBouncer</application>.
|
||||
</para>
|
||||
|
||||
<sect1 id="prerequisites" xreflable="BDR prequisites">
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
@@ -38,5 +38,34 @@
|
||||
and therefore determine the state of outbound connections from that node.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
<para>
|
||||
Following exit codes can be emitted by <command>repmgr cluster crosscheck</command>:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>SUCCESS (0)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The check completed successfully and all nodes are reachable.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ERR_NODE_STATUS (25)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
One or more nodes could not be reached.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
|
||||
@@ -40,10 +40,29 @@
|
||||
<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>
|
||||
<title>Output format</title>
|
||||
<para>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>--csv</literal>: generate output in CSV format. Note that the <literal>Details</literal>
|
||||
column will currently not be emitted in CSV format.
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
@@ -97,5 +97,35 @@
|
||||
useful result.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
<para>
|
||||
Following exit codes can be emitted by <command>repmgr cluster matrix</command>:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>SUCCESS (0)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The check completed successfully and all nodes are reachable.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ERR_NODE_STATUS (25)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
One or more nodes could not be reached.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
|
||||
@@ -113,4 +113,40 @@
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
<para>
|
||||
Following exit codes can be emitted by <command>repmgr cluster show</command>:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>SUCCESS (0)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
No issues were detected.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ERR_NODE_STATUS (25)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
One or more issues were detected.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-node-status">, <xref linkend="repmgr-node-check">
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -61,7 +61,9 @@
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>--archive-ready</literal>: checks for WAL files which have not yet been archived
|
||||
<literal>--archive-ready</literal>: checks for WAL files which have not yet been archived,
|
||||
and returns <literal>WARNING</literal> or <literal>CRITICAL</literal> if the number
|
||||
exceeds <varname>archive_ready_warning</varname> or <varname>archive_ready_critical</varname> respectively.
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
@@ -77,11 +79,110 @@
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>--missing-slots</literal>: checks there are no missing replication slots
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Individual checks can also be output in a Nagios-compatible format by additionally
|
||||
providing the option <literal>--nagios</literal>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Output format</title>
|
||||
<para>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>--csv</literal>: generate output in CSV format (not available
|
||||
for individual checks)
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>--nagios</literal>: generate output in a Nagios-compatible format
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
|
||||
<para>
|
||||
When executing <command>repmgr node check</command> with one of the individual
|
||||
checks listed above, &repmgr; will emit one of the following Nagios-style exit codes
|
||||
(even if <literal>--nagios</literal> is not supplied):
|
||||
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>0</literal>: OK
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>1</literal>: WARNING
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>2</literal>: ERROR
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>3</literal>: UNKNOWN
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
|
||||
|
||||
<para>
|
||||
Following exit codes can be emitted by <command>repmgr status check</command>
|
||||
if no individual check was specified.
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>SUCCESS (0)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
No issues were detected.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ERR_NODE_STATUS (25)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
One or more issues were detected.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-node-status">, <xref linkend="repmgr-cluster-show">
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -45,6 +45,101 @@
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Check prerequisites but don't actually execute the rejoin.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--force-rewind[=/path/to/pg_rewind]</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Execute <application>pg_rewind</application> if necessary.
|
||||
</para>
|
||||
<para>
|
||||
It is only necessary to provide the <application>pg_rewind</application>
|
||||
if using PostgreSQL 9.3 or 9.4, and <application>pg_rewind</application>
|
||||
is not installed in the PostgreSQL <filename>bin</filename> directory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--config-files</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
comma-separated list of configuration files to retain after
|
||||
executing <application>pg_rewind</application>.
|
||||
</para>
|
||||
<para>
|
||||
Currently <application>pg_rewind</application> will overwrite
|
||||
the local node's configuration files with the files from the source node,
|
||||
so it's advisable to use this option to ensure they are kept.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--config-archive-dir</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Directory to temporarily store configuration files specified with
|
||||
<option>--config-files</option>; default: <filename>/tmp</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-W/--no-wait</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Don't wait for the node to rejoin cluster.
|
||||
</para>
|
||||
<para>
|
||||
If this option is supplied, &repmgr; will restart the node but
|
||||
not wait for it to connect to the primary.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Configuration file settings</title>
|
||||
|
||||
<para>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>node_rejoin_timeout</literal>:
|
||||
the maximum length of time (in seconds) to wait for
|
||||
the node to reconnect to the replication cluster (defaults to
|
||||
the value set in <literal>standby_reconnect_timeout</literal>,
|
||||
60 seconds).
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</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,16 +164,24 @@
|
||||
</tip>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="repmgr-node-rejoin-pg-rewind">
|
||||
<refsect1 id="repmgr-node-rejoin-pg-rewind" xreflabel="Using pg_rewind">
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_rewind</primary>
|
||||
<secondary>using with "repmgr node rejoin"</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>Using <command>pg_rewind</command></title>
|
||||
<para>
|
||||
<command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a
|
||||
node which has diverged from the rest of the cluster, typically a failed primary.
|
||||
<command>pg_rewind</command> is available in PostgreSQL 9.5 and later.
|
||||
<command>pg_rewind</command> is available in PostgreSQL 9.5 and later as part of the core distribution,
|
||||
and can be installed from external sources for PostgreSQL 9.3 and 9.4.
|
||||
</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>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<title>Example</title>
|
||||
<para>
|
||||
<programlisting>
|
||||
$ repmgr -f /etc/repmgr.comf node status
|
||||
$ repmgr -f /etc/repmgr.conf node status
|
||||
Node "node1":
|
||||
PostgreSQL version: 10beta1
|
||||
Total data size: 30 MB
|
||||
@@ -38,10 +38,54 @@
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Output format</title>
|
||||
<para>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>--csv</literal>: generate output in CSV format
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
<para>
|
||||
Following exit codes can be emitted by <command>repmgr node status</command>:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>SUCCESS (0)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
No issues were detected.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ERR_NODE_STATUS (25)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
One or more issues were detected.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
See <xref linkend="repmgr-node-check"> to diagnose issues.
|
||||
See <xref linkend="repmgr-node-check"> to diagnose issues and <xref linkend="repmgr-cluster-show">
|
||||
for an overview of all nodes in the cluster.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<title>Description</title>
|
||||
<para>
|
||||
<command>repmgr primary register</command> registers a primary node in a
|
||||
streaming replication cluster, and configures it for use with repmgr, including
|
||||
streaming replication cluster, and configures it for use with &repmgr;, including
|
||||
installing the &repmgr; extension. This command needs to be executed before any
|
||||
standby nodes are registered.
|
||||
</para>
|
||||
@@ -26,7 +26,7 @@
|
||||
<refsect1>
|
||||
<title>Execution</title>
|
||||
<para>
|
||||
Execute with the <literal>--dry-run</literal> option to check what would happen without
|
||||
Execute with the <option>--dry-run</option> option to check what would happen without
|
||||
actually registering the primary.
|
||||
</para>
|
||||
<para>
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If providing the configuration file location with <literal>-f/--config-file</literal>,
|
||||
If providing the configuration file location with <option>-f/--config-file</option>,
|
||||
avoid using a relative path, as &repmgr; stores the configuration file location
|
||||
in the repmgr metadata for use when &repmgr; is executed remotely (e.g. during
|
||||
<xref linkend="repmgr-standby-switchover">). &repmgr; will attempt to convert the
|
||||
@@ -48,4 +48,38 @@
|
||||
</note>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Check prerequisites but don't actually register the primary.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-F</option>, <option>--force</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Overwrite an existing node record
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</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>
|
||||
|
||||
@@ -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>
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
<refsect1>
|
||||
<title>Execution</title>
|
||||
<para>
|
||||
<command>repmgr primary unregister</command> can be run on any active &repmgr; node,
|
||||
with the ID of the node to unregister passed as <option>--node-id</option>.
|
||||
</para>
|
||||
<para>
|
||||
Execute with the <literal>--dry-run</literal> option to check what would happen without
|
||||
actually unregistering the node.
|
||||
@@ -28,7 +32,43 @@
|
||||
|
||||
<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>Options</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Check prerequisites but don't actually unregister the primary.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--node-id</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
ID of the inactive primary to be unregistered.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</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>
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
<note>
|
||||
<simpara>
|
||||
<command>repmgr standby clone</command> does not start the standby, and after cloning
|
||||
<command>repmgr standby register</command> must be executed to notify &repmgr; of its presence.
|
||||
a standby, the command <command>repmgr standby register</command> must be executed to
|
||||
notify &repmgr; of its existence.
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -65,7 +67,71 @@
|
||||
</tip>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="repmgr-standby-clone-wal-management" xreflabel="Managing WAL during the cloning process">
|
||||
<refsect1 id="repmgr-standby-clone-recovery-conf">
|
||||
<indexterm>
|
||||
<primary>recovery.conf</primary>
|
||||
<secondary>customising with "repmgr standby clone"</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>Customising recovery.conf</title>
|
||||
<para>
|
||||
By default, &repmgr; will create a minimal <filename>recovery.conf</filename>
|
||||
containing following parameters:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara><varname>standby_mode</varname> (always <literal>'on'</literal>)</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara><varname>recovery_target_timeline</varname> (always <literal>'latest'</literal>)</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara><varname>primary_conninfo</varname></simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara><varname>primary_slot_name</varname> (if replication slots in use)</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
The following additional parameters can be specified in <filename>repmgr.conf</filename>
|
||||
for inclusion in <filename>recovery.conf</filename>:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara><varname>restore_command</varname></simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara><varname>archive_cleanup_command</varname></simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara><varname>recovery_min_apply_delay</varname></simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
We recommend using <ulink url="https://www.pgbarman.org/">Barman</ulink> to manage
|
||||
WAL file archiving. For more details on combining &repmgr; and <application>Barman</application>,
|
||||
in particular using <varname>restore_command</varname> to configure Barman as a backup source of
|
||||
WAL files, see <xref linkend="cloning-from-barman">.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="repmgr-standby-clone-wal-management">
|
||||
<title>Managing WAL during the cloning process</title>
|
||||
<para>
|
||||
When initially cloning a standby, you will need to ensure
|
||||
@@ -99,5 +165,186 @@
|
||||
</simpara>
|
||||
</note>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1 id="repmgr-standby-create-recovery-conf">
|
||||
|
||||
<indexterm>
|
||||
<primary>recovery.conf</primary>
|
||||
<secondary>generating for a standby cloned by another method</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>Using a standby cloned by another method</title>
|
||||
<para>
|
||||
&repmgr; supports standbys cloned by another method (e.g. using <application>barman</application>'s
|
||||
<command><ulink url="http://docs.pgbarman.org/release/2.4/#recover">barman recover</ulink></command> command).
|
||||
</para>
|
||||
<para>
|
||||
To integrate the standby as a &repmgr; node, ensure the <filename>repmgr.conf</filename>
|
||||
file is created for the node, and that it has been registered using
|
||||
<command><link linkend="repmgr-standby-register">repmgr standby register</link></command>.
|
||||
Then execute the command <command>repmgr standby clone --recovery-conf-only</command>.
|
||||
This will create the <filename>recovery.conf</filename> file needed to attach
|
||||
the node to its upstream, and will also create a replication slot on the
|
||||
upstream node if required.
|
||||
</para>
|
||||
<para>
|
||||
Note that the upstream node must be running. An existing
|
||||
<filename>recovery.conf</filename> will not be overwritten unless the
|
||||
<option>-F/--force</option> option is provided.
|
||||
</para>
|
||||
<para>
|
||||
Execute <command>repmgr standby clone --recovery-conf-only --dry-run</command>
|
||||
to check the prerequisites for creating the <filename>recovery.conf</filename> file,
|
||||
and display the contents of the file without actually creating it.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
<option>--recovery-conf-only</option> was introduced in &repmgr; <link linkend="release-4.0.4">4.0.4</link>.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
<title>Options</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-d, --dbname=CONNINFO</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Connection string of the upstream node to use for cloning.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Check prerequisites but don't actually clone the standby.
|
||||
</para>
|
||||
<para>
|
||||
If <option>--recovery-conf-only</option> specified, the contents of
|
||||
the generated <filename>recovery.conf</filename> file will be displayed
|
||||
but the file itself not written.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-c, --fast-checkpoint</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Force fast checkpoint (not effective when cloning from Barman).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--copy-external-config-files[={samepath|pgdata}]</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Copy configuration files located outside the data directory on the source
|
||||
node to the same path on the standby (default) or to the
|
||||
PostgreSQL data directory.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-upstream-connection</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
When using Barman, do not connect to upstream node.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-R, --remote-user=USERNAME</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Remote system username for SSH operations (default: current local system username).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option> --recovery-conf-only</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Create <filename>recovery.conf</filename> file for a previously cloned instance. &repmgr 4.0.4 and later.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--replication-user</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
User to make replication connections with (optional, not usually required).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--superuser</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
If the &repmgr; user is not a superuser, the name of a valid superuser must
|
||||
be provided with this option.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--upstream-conninfo</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>primary_conninfo</literal> value to write in recovery.conf
|
||||
when the intended upstream server does not yet exist.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--upstream-node-id</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
ID of the upstream node to replicate from (optional, defaults to primary node)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--without-barman </option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Do not use Barman even if configured.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Event notifications</title>
|
||||
<para>
|
||||
A <literal>standby_clone</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
See <xref linkend="cloning-standbys"> for details about various aspects of cloning.
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
|
||||
@@ -26,10 +26,19 @@
|
||||
running. It can only be used to attach an active standby to the current primary node
|
||||
(and not to another standby).
|
||||
</para>
|
||||
<para>
|
||||
To re-add an inactive node to the replication cluster, see
|
||||
<xref linkend="repmgr-node-rejoin">
|
||||
</para>
|
||||
<tip>
|
||||
<para>
|
||||
To re-add an inactive node to the replication cluster, use
|
||||
<xref linkend="repmgr-node-rejoin">.
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
<para>
|
||||
<command>repmgr standby follow</command> will wait up to
|
||||
<varname>standby_follow_timeout</varname> seconds (default: <literal>30</literal>)
|
||||
to verify the standby has actually connected to the new primary.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@@ -48,7 +57,56 @@
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Check prerequisites but don't actually follow a new standby.
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
This does not guarantee the standby can follow the primary; in
|
||||
particular, whether the primary and standby timelines have diverged,
|
||||
can currently only be determined by actually attempting to
|
||||
attach the standby to the primary.
|
||||
</para>
|
||||
</important>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-w</option></term>
|
||||
<term><option>--wait</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Wait for a primary to appear. &repmgr; will wait for up to
|
||||
<varname>primary_follow_timeout</varname> seconds
|
||||
(default: 60 seconds) to verify that the standby is following the new primary.
|
||||
This value can be defined in <filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Event notifications</title>
|
||||
<para>
|
||||
A <literal>standby_follow</literal> <link linkend="event-notifications">event notification</link> will be generated.
|
||||
</para>
|
||||
<para>
|
||||
If provided, &repmgr; will substitute the placeholders <literal>%p</literal> with the node ID of the primary
|
||||
being followed, <literal>%c</literal> with its <literal>conninfo</literal> string, and
|
||||
<literal>%a</literal> with its node name.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-node-rejoin">
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
by using <xref linkend="repmgr-standby-follow">; if <application>repmgrd</application>
|
||||
is active, it will handle this automatically.
|
||||
</para>
|
||||
<para>
|
||||
Note that &repmgr; will wait for up to <varname>promote_check_timeout</varname> seconds
|
||||
(default: 60 seconds) to verify that the standby has been promoted, and will
|
||||
check the promotion every <varname>promote_check_interval</varname> seconds (default: 1 second).
|
||||
Both values can be defined in <filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@@ -41,4 +48,13 @@
|
||||
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>
|
||||
|
||||
@@ -37,19 +37,36 @@
|
||||
</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
|
||||
the standby's node record to propagate from the primary to the standby. Some
|
||||
actions (such as starting <application>repmgrd</application>) require that the standby's node record
|
||||
Depending on your environment and workload, it may take some time for the standby's node record
|
||||
to propagate from the primary to the standby. Some actions (such as starting
|
||||
<application>repmgrd</application>) require that the standby's node record
|
||||
is present and up-to-date to function correctly.
|
||||
</para>
|
||||
<para>
|
||||
By providing the option <literal>--wait-sync</literal> to the
|
||||
By providing the option <option>--wait-sync</option> to the
|
||||
<command>repmgr standby register</command> command, &repmgr; will wait
|
||||
until the record is synchronised before exiting. An optional timeout (in
|
||||
seconds) can be added to this option (e.g. <literal>--wait-sync=60</literal>).
|
||||
seconds) can be added to this option (e.g. <option>--wait-sync=60</option>).
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@@ -58,20 +75,109 @@
|
||||
<para>
|
||||
Under some circumstances you may wish to register a standby which is not
|
||||
yet running; this can be the case when using provisioning tools to create
|
||||
a complex replication cluster. In this case, by using the <literal>-F/--force</literal>
|
||||
a complex replication cluster. In this case, by using the <option>-F/--force</option>
|
||||
option and providing the connection parameters to the primary server,
|
||||
the standby can be registered.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, with cascading replication it may be necessary to register
|
||||
a standby whose upstream node has not yet been registered - in this case,
|
||||
using <literal>-F/--force</literal> will result in the creation of an inactive placeholder
|
||||
using <option>-F/--force</option> will result in the creation of an inactive placeholder
|
||||
record for the upstream node, which will however later need to be registered
|
||||
with the <literal>-F/--force</literal> option too.
|
||||
with the <option>-F/--force</option> option too.
|
||||
</para>
|
||||
<para>
|
||||
When used with <command>repmgr standby register</command>, care should be taken that use of the
|
||||
<literal>-F/--force</literal> option does not result in an incorrectly configured cluster.
|
||||
<option>-F/--force</option> option does not result in an incorrectly configured cluster.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="repmgr-standby-register-node-cloned-other-source">
|
||||
<title>Registering a node not cloned by repmgr</title>
|
||||
<para>
|
||||
If you've cloned a standby using another method (e.g. <application>barman</application>'s
|
||||
<command>barman recover</command> command), first execute
|
||||
<link linkend="repmgr-standby-create-recovery-conf">repmgr standby clone --recovery-conf-only</link>
|
||||
to add the <filename>recovery.conf</filename> file, then register the standby as usual.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
<title>Options</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Check prerequisites but don't actually register the standby.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-F</option><option>--force</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Overwrite an existing node record
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--upstream-node-id</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
ID of the upstream node to replicate from (optional)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--wait-start</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
wait for the standby to start (timeout in seconds, default 30 seconds)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--wait-sync</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
wait for the node record to synchronise to the standby (optional timeout in seconds)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Event notifications</title>
|
||||
<para>
|
||||
A <literal>standby_register</literal> <link linkend="event-notifications">event notification</link>
|
||||
will be generated immediately after the node record is updated on the primary.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the <option>--wait-sync</option> option is provided, a <literal>standby_register_sync</literal>
|
||||
event notification will be generated immediately after the node record has synchronised to the
|
||||
standby.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If provided, &repmgr; will substitute the placeholders <literal>%p</literal> with the node ID of the
|
||||
primary node, <literal>%c</literal> with its <literal>conninfo</literal> string, and
|
||||
<literal>%a</literal> with its node name.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<refpurpose>promote a standby to primary and demote the existing primary to a standby</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
@@ -22,11 +23,159 @@
|
||||
</para>
|
||||
<para>
|
||||
If other standbys are connected to the demotion candidate, &repmgr; can instruct
|
||||
these to follow the new primary if the option <literal>--siblings-follow</literal>
|
||||
is specified.
|
||||
these to follow the new primary if the option <literal>--siblings-follow</literal>
|
||||
is specified. This requires a passwordless SSH connection between the promotion
|
||||
candidate (new primary) and the standbys attached to the demotion candidate
|
||||
(existing primary).
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Performing a switchover is a non-trivial operation. In particular it
|
||||
relies on the current primary being able to shut down cleanly and quickly.
|
||||
&repmgr; will attempt to check for potential issues but cannot guarantee
|
||||
a successful switchover.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
For more details on performing a switchover, including preparation and configuration,
|
||||
see section <xref linkend="performing-switchover">.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
<application>repmgrd</application> should not be active on any nodes while a switchover is being
|
||||
executed. This restriction may be lifted in a later version.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; will not perform the switchover if an exclusive backup is running on the current primary.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</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>
|
||||
<important>
|
||||
<para>
|
||||
Success of <option>--dry-run</option> does not imply the switchover will
|
||||
complete successfully, only that
|
||||
the prerequisites for performing the operation are met.
|
||||
</para>
|
||||
</important>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-F</option></term>
|
||||
<term><option>--force</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Ignore warnings and continue anyway.
|
||||
</para>
|
||||
<para>
|
||||
Specifically, if a problem is encountered when shutting down the current primary,
|
||||
using <option>-F/--force</option> will cause &repmgr; to continue by promoting
|
||||
the standby to be the new primary, and if <option>--siblings-follow</option> is
|
||||
specified, attach any other standbys to the new primary.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--force-rewind[=/path/to/pg_rewind]</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <application>pg_rewind</application> to reintegrate the old primary if necessary
|
||||
(and the prerequisites for using <application>pg_rewind</application> are met).
|
||||
If using PostgreSQL 9.3 or 9.4, and the <application>pg_rewind</application>
|
||||
binary is not installed in the PostgreSQL <filename>bin</filename> directory,
|
||||
provide its full path. For more details see also <xref linkend="switchover-pg-rewind">.
|
||||
</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>Configuration file settings</title>
|
||||
|
||||
<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>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>standby_reconnect_timeout</literal>:
|
||||
number of seconds to attempt to wait for the demoted primary
|
||||
to reconnect to the promoted primary (default: 60 seconds)
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
<refsect1>
|
||||
<title>Execution</title>
|
||||
|
||||
@@ -34,12 +183,72 @@
|
||||
Execute with the <literal>--dry-run</literal> option to test the switchover as far as
|
||||
possible without actually changing the status of either node.
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
<application>repmgrd</application> must be shut down on all nodes while a switchover is being
|
||||
executed. This restriction will be removed in a future &repmgr; version.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
<application>repmgrd</application> should not be active on any nodes while a switchover is being
|
||||
executed. This restriction may be lifted in a later version.
|
||||
External database connections, e.g. from an application, should not be permitted while
|
||||
the switchover is taking place. In particular, active transactions on the primary
|
||||
can potentially disrupt the shutdown process.
|
||||
</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 primary.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
<para>
|
||||
Following exit codes can be emitted by <command>repmgr standby switchover</command>:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>SUCCESS (0)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The switchover completed successfully.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ERR_SWITCHOVER_FAIL (18)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The switchover could not be executed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>ERR_SWITCHOVER_INCOMPLETE (22)</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The switchover was executed but a problem was encountered.
|
||||
Typically this means the former primary could not be reattached
|
||||
as a standby. Check preceding log messages for more information.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
|
||||
@@ -42,5 +42,29 @@
|
||||
repmgr standby unregister -f /etc/repmgr.conf --node-id=3</programlisting>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--node-id</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>node_id</varname> of the node to unregister (optional)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
</para>
|
||||
<para>
|
||||
The node does not have to be running to be unregistered, however if this is the
|
||||
case then connection information for the primary server must be provided.
|
||||
case then either provide connection information for the primary server, or
|
||||
execute <command>repmgr witness unregister</command> on a running node and
|
||||
provide the parameter <option>--node-id</option> with the node ID of the
|
||||
witness server.
|
||||
</para>
|
||||
<para>
|
||||
Execute with the <literal>--dry-run</literal> option to check what would happen
|
||||
@@ -36,17 +39,17 @@
|
||||
INFO: connecting to witness node "node3" (ID: 3)
|
||||
INFO: unregistering witness node 3
|
||||
INFO: witness unregistration complete
|
||||
DETAIL: witness node with id 3 (conninfo: host=node3 dbname=repmgr user=repmgr port=5499) successfully unregistered</programlisting>
|
||||
DETAIL: witness node with UD 3 successfully unregistered</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Unregistering a non-running witness node:
|
||||
<programlisting>
|
||||
$ repmgr -f /etc/repmgr.conf witness unregister -h localhost -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
|
||||
$ repmgr -f /etc/repmgr.conf witness unregister -h node1 -p 5501 -F
|
||||
INFO: connecting to node "node3" (ID: 3)
|
||||
NOTICE: unable to connect to node "node3" (ID: 3), removing node record on cluster primary only
|
||||
INFO: unregistering witness node 3
|
||||
INFO: witness unregistration complete
|
||||
DETAIL: witness node with id 3 (conninfo: host=node3 dbname=repmgr user=repmgr port=5499) successfully unregistered</programlisting>
|
||||
DETAIL: witness node with id ID 3 successfully unregistered</programlisting>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@@ -61,4 +64,39 @@
|
||||
<link linkend="repmgr-witness-register">repmgr witness register --force</link>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Check prerequisites but don't actually unregister the witness.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--node-id</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Unregister witness server with the specified node ID.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</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>
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
&appendix-release-notes;
|
||||
&appendix-signatures;
|
||||
&appendix-faq;
|
||||
&appendix-packages;
|
||||
|
||||
<![%include-index;[&bookindex;]]>
|
||||
<![%include-xslt-index;[<index id="bookindex"></index>]]>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<para>
|
||||
In contrast to streaming replication, there's no concept of "promoting" a new
|
||||
primary node with BDR. Instead, "failover" involves monitoring both nodes
|
||||
with `repmgrd` and redirecting queries from the failed node to the remaining
|
||||
with <application>repmgrd</application> and redirecting queries from the failed node to the remaining
|
||||
active node. This can be done by using an
|
||||
<link linkend="event-notifications">event notification</link> script
|
||||
which is called by <application>repmgrd</application> to dynamically
|
||||
@@ -99,15 +99,16 @@
|
||||
replication cluster. The database must be the BDR-enabled database.
|
||||
</para>
|
||||
<para>
|
||||
If defined, the evenr <application>event_notifications</application> parameter
|
||||
will restrict execution of <varname>event_notification_command</varname>
|
||||
If defined, the <varname>event_notifications</varname> parameter will restrict
|
||||
execution of the script defined in <varname>event_notification_command</varname>
|
||||
to the specified event(s).
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
<varname>event_notification_command</varname> is the script which does the actual "heavy lifting"
|
||||
of reconfiguring the proxy server/ connection pooler. It is fully
|
||||
user-definable; a reference implementation is documented below.
|
||||
user-definable; see section <xref linkend="bdr-event-notification-command"> for a reference
|
||||
implementation.
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
@@ -169,22 +170,18 @@
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="bdr-event-notification-command" xreflabel="BDR failover event notification command">
|
||||
<title>Defining the "event_notification_command"</title>
|
||||
<sect1 id="bdr-event-notification-command" xreflabel="Defining the BDR failover "event_notification command"">
|
||||
<title>Defining the BDR failover "event_notification_command"</title>
|
||||
<para>
|
||||
Key to "failover" execution is the <literal>event_notification_command</literal>,
|
||||
which is a user-definable script specified in <filename>repmpgr.conf</filename>
|
||||
and which should reconfigure the proxy server/ connection pooler to point
|
||||
to the other, still-active node.
|
||||
and which can use a &repmgr; <link linkend="event-notifications">event notification</link>
|
||||
to reconfigure the proxy server / connection pooler so it points to the other, still-active node.
|
||||
Details of the event will be passed as parameters to the script.
|
||||
</para>
|
||||
<para>
|
||||
Each time &repmgr; (or <application>repmgrd</application>) records an event,
|
||||
it can optionally execute the script defined in
|
||||
<literal>event_notification_command</literal> to take further action;
|
||||
details of the event will be passed as parameters.
|
||||
</para>
|
||||
<para>
|
||||
Following placeholders are available to the script:
|
||||
Following parameter placeholders are available for the script definition in <filename>repmpgr.conf</filename>;
|
||||
these will be replaced with the appropriate value when the script is executed:
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
@@ -231,20 +228,37 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>%c</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
conninfo string of the next available node (<varname>bdr_failover</varname> and <varname>bdr_recovery</varname>)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>%a</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
name of the next available node (<varname>bdr_failover</varname> and <varname>bdr_recovery</varname>)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
Note that <literal>%c</literal> and <literal>%a</literal> will only be provided during
|
||||
<varname>bdr_failover</varname> events, which is what is of interest here.
|
||||
Note that <literal>%c</literal> and <literal>%a</literal> are only provided with
|
||||
particular failover events, in this case <varname>bdr_failover</varname>.
|
||||
</para>
|
||||
<para>
|
||||
The provided sample script (`scripts/bdr-pgbouncer.sh`) is configured like
|
||||
this:
|
||||
The provided sample script
|
||||
(<literal><ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/scripts/bdr-pgbouncer.sh">scripts/bdr-pgbouncer.sh</ulink></literal>)
|
||||
is configured as follows:
|
||||
<programlisting>
|
||||
event_notification_command='/path/to/bdr-pgbouncer.sh %n %e %s "%c" "%a"'</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
and parses the configures parameters like this:
|
||||
and parses the placeholder parameters like this:
|
||||
<programlisting>
|
||||
NODE_ID=$1
|
||||
EVENT_TYPE=$2
|
||||
@@ -252,12 +266,14 @@
|
||||
NEXT_CONNINFO=$4
|
||||
NEXT_NODE_NAME=$5</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The script also contains some hard-coded values about the <application>PgBouncer</application>
|
||||
configuration for both nodes; these will need to be adjusted for your local environment
|
||||
(ideally the scripts would be maintained as templates and generated by some
|
||||
kind of provisioning system).
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
The sample script also contains some hard-coded values for the <application>PgBouncer</application>
|
||||
configuration for both nodes; these will need to be adjusted for your local environment
|
||||
(ideally the scripts would be maintained as templates and generated by some
|
||||
kind of provisioning system).
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The script performs following steps:
|
||||
|
||||
@@ -1,60 +1,298 @@
|
||||
<chapter id="repmgrd-configuration">
|
||||
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>configuration</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>configuration</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>repmgrd configuration</title>
|
||||
<para>
|
||||
To use <application>repmgrd</application>, its associated function library must be
|
||||
included in <filename>postgresql.conf</filename> with:
|
||||
<title>repmgrd configuration</title>
|
||||
|
||||
<programlisting>
|
||||
shared_preload_libraries = 'repmgr'</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Changing this setting requires a restart of PostgreSQL; for more details see
|
||||
the <ulink url="https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-SHARED-PRELOAD-LIBRARIES">PostgreSQL documentation</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Additionally the following <application>repmgrd</application> options *must* be set in
|
||||
<filename>repmgr.conf</filename> (adjust configuration file locations as appropriate):
|
||||
<programlisting>
|
||||
failover=automatic
|
||||
promote_command='repmgr standby promote -f /etc/repmgr.conf --log-to-file'
|
||||
follow_command='repmgr standby follow -f /etc/repmgr.conf --log-to-file --upstream-node-id=%n'</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Note that the <literal>--log-to-file</literal> option will cause
|
||||
output generated by the &repmgr; command, when executed by <application>repmgrd</application>,
|
||||
to be logged to the same destination configured to receive log output for <application>repmgrd</application>.
|
||||
See <filename>repmgr.conf.sample</filename> for further <application>repmgrd</application>-specific settings.
|
||||
</para>
|
||||
<para>
|
||||
When <varname>failover</varname> is set to <literal>automatic</literal>, upon detecting failure
|
||||
of the current primary, <application>repmgrd</application> will execute one of
|
||||
<varname>promote_command</varname> or <varname>follow_command</varname>,
|
||||
depending on whether the current server is to become the new primary, or
|
||||
needs to follow another server which has become the new primary. Note that
|
||||
these commands can be any valid shell script which results in one of these
|
||||
two actions happening, but if &repmgr;'s <command>standby follow</command> or
|
||||
<command>standby promote</command>
|
||||
commands are not executed (either directly as shown here, or from a script which
|
||||
performs other actions), the &repmgr; metadata will not be updated and
|
||||
&repmgr; will no longer function reliably.
|
||||
</para>
|
||||
<para>
|
||||
The <varname>follow_command</varname> should provide the <literal>--upstream-node-id=%n</literal>
|
||||
option to <command>repmgr standby follow</command>; the <literal>%n</literal> will be replaced by
|
||||
<application>repmgrd</application> with the ID of the new primary node. If this is not provided, &repmgr;
|
||||
will attempt to determine the new primary by itself, but if the
|
||||
original primary comes back online after the new primary is promoted, there is a risk that
|
||||
<command>repmgr standby follow</command> will result in the node continuing to follow
|
||||
the original primary.
|
||||
</para>
|
||||
<sect1 id="repmgrd-connection-settings">
|
||||
<title>repmgrd connection settings</title>
|
||||
<para>
|
||||
<application>repmgrd</application> is a daemon which runs on each PostgreSQL node,
|
||||
monitoring the local node, and (unless it's the primary node) the upstream server
|
||||
(the primary server or with cascading replication, another standby) which it's
|
||||
connected to.
|
||||
</para>
|
||||
<para>
|
||||
<application>repmgrd</application> can be configured to provide failover
|
||||
capability in case the primary upstream node becomes unreachable, and/or
|
||||
provide monitoring data to the &repmgr; metadatabase.
|
||||
</para>
|
||||
|
||||
<sect1 id="repmgrd-basic-configuration">
|
||||
<title>repmgrd basic configuration</title>
|
||||
|
||||
<para>
|
||||
To use <application>repmgrd</application>, its associated function library <emphasis>must</emphasis> be
|
||||
included via <filename>postgresql.conf</filename> with:
|
||||
|
||||
<programlisting>
|
||||
shared_preload_libraries = 'repmgr'</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Changing this setting requires a restart of PostgreSQL; for more details see
|
||||
the <ulink url="https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-SHARED-PRELOAD-LIBRARIES">PostgreSQL documentation</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To apply configuration file changes to a running <application>repmgrd</application>
|
||||
daemon, execute the operating system's r<application>repmgrd</application> service reload command
|
||||
(see <xref linkend="appendix-packages"> for examples),
|
||||
or for instances which were manually started, execute <command>kill -HUP</command>, e.g.
|
||||
<command>kill -HUP `cat /tmp/repmgrd.pid`</command>.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Check the <application>repmgrd</application> log to see what changes were
|
||||
applied, or if any issues were encountered when reloading the configuration.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
Note that only a subset of configuration file parameters can be changed on a
|
||||
running <application>repmgrd</application> daemon.
|
||||
</para>
|
||||
|
||||
|
||||
<sect2 id="repmgrd-automatic-failover-configuration">
|
||||
<title>automatic failover configuration</title>
|
||||
<para>
|
||||
If using automatic failover, the following <application>repmgrd</application> options *must* be set in
|
||||
<filename>repmgr.conf</filename> :
|
||||
<programlisting>
|
||||
failover=automatic
|
||||
promote_command='/usr/bin/repmgr standby promote -f /etc/repmgr.conf --log-to-file'
|
||||
follow_command='/usr/bin/repmgr standby follow -f /etc/repmgr.conf --log-to-file --upstream-node-id=%n'</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Adjust file paths as appropriate; we recomment specifying the full path to the &repmgr; binary.
|
||||
</para>
|
||||
<para>
|
||||
Note that the <literal>--log-to-file</literal> option will cause
|
||||
output generated by the &repmgr; command, when executed by <application>repmgrd</application>,
|
||||
to be logged to the same destination configured to receive log output for <application>repmgrd</application>.
|
||||
See <filename><ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink></filename>
|
||||
for further <application>repmgrd</application>-specific settings.
|
||||
</para>
|
||||
<para>
|
||||
When <varname>failover</varname> is set to <literal>automatic</literal>, upon detecting failure
|
||||
of the current primary, <application>repmgrd</application> will execute one of:
|
||||
</para>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<simpara>
|
||||
<varname>promote_command</varname> (if the current server is to become the new primary)
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<varname>follow_command</varname> (if the current server needs to follow another server which has
|
||||
become the new primary)
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<note>
|
||||
<para>
|
||||
These commands can be any valid shell script which results in one of these
|
||||
two actions happening, but if &repmgr;'s <command>standby follow</command> or
|
||||
<command>standby promote</command>
|
||||
commands are not executed (either directly as shown here, or from a script which
|
||||
performs other actions), the &repmgr; metadata will not be updated and
|
||||
&repmgr; will no longer function reliably.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The <varname>follow_command</varname> should provide the <literal>--upstream-node-id=%n</literal>
|
||||
option to <command>repmgr standby follow</command>; the <literal>%n</literal> will be replaced by
|
||||
<application>repmgrd</application> with the ID of the new primary node. If this is not provided, &repmgr;
|
||||
will attempt to determine the new primary by itself, but if the
|
||||
original primary comes back online after the new primary is promoted, there is a risk that
|
||||
<command>repmgr standby follow</command> will result in the node continuing to follow
|
||||
the original primary.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="repmgrd-service-configuration">
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>PostgreSQL service configuration</secondary>
|
||||
</indexterm>
|
||||
<title>PostgreSQL service configuration</title>
|
||||
<para>
|
||||
If using automatic failover, currently <application>repmgrd</application> will need to execute
|
||||
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>
|
||||
to restart PostgreSQL on standbys to have them follow a new primary.
|
||||
</para>
|
||||
<para>
|
||||
To ensure this happens smoothly, it's essential to provide the appropriate system/service restart
|
||||
command appropriate to your operating system via <varname>service_restart_command</varname>
|
||||
in <filename>repmgr.conf</filename>. If you don't do this, <application>repmgrd</application>
|
||||
will default to using <command>pg_ctl</command>, which can result in unexpected problems,
|
||||
particularly on <application>systemd</application>-based systems.
|
||||
</para>
|
||||
<para>
|
||||
For more details, see <xref linkend="configuration-file-service-commands">.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="repmgrd-monitoring-configuration">
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>monitoring configuration</secondary>
|
||||
</indexterm>
|
||||
<title>Monitoring configuration</title>
|
||||
<para>
|
||||
To enable monitoring, set:
|
||||
<programlisting>
|
||||
monitoring_history=yes</programlisting>
|
||||
in <filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
<para>
|
||||
The default monitoring interval is 2 seconds; this value can be explicitly set using:
|
||||
<programlisting>
|
||||
monitor_interval_secs=<seconds></programlisting>
|
||||
in <filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
<para>
|
||||
For more details on monitoring, see <xref linkend="repmgrd-monitoring">.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="repmgrd-daemon">
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>starting and stopping</secondary>
|
||||
</indexterm>
|
||||
<title>repmgrd daemon</title>
|
||||
<para>
|
||||
If installed from a package, the <application>repmgrd</application> can be started
|
||||
via the operating system's service command, e.g. in <application>systemd</application>
|
||||
using <command>systemctl</command>.
|
||||
</para>
|
||||
<para>
|
||||
See appendix <xref linkend="appendix-packages"> for details of service commands
|
||||
for different distributions.
|
||||
</para>
|
||||
<para>
|
||||
<application>repmgrd</application> can be started manually like this:
|
||||
<programlisting>
|
||||
repmgrd -f /etc/repmgr.conf --pid-file /tmp/repmgrd.pid</programlisting>
|
||||
and stopped with <command>kill `cat /tmp/repmgrd.pid`</command>. Adjust paths as appropriate.
|
||||
</para>
|
||||
|
||||
<sect2 id="repmgrd-pid-file" xreflabel="repmgrd's PID file">
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>PID file</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>PID file</primary>
|
||||
<secondary>repmgrd</secondary>
|
||||
</indexterm>
|
||||
<title>repmgrd's PID file</title>
|
||||
<para>
|
||||
<application>repmgrd</application> will generate a PID file by default.
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
This is a behaviour change from previous versions (earlier than 4.1), where
|
||||
the PID file had to be explicitly specified with the command line
|
||||
parameter <option> --pid-file</option>.
|
||||
</simpara>
|
||||
</note>
|
||||
<para>
|
||||
The PID file can be specified in <filename>repmgr.conf</filename> with the configuration
|
||||
parameter <varname>repmgrd_pid_file</varname>.
|
||||
</para>
|
||||
<para>
|
||||
It can also be specified on the command line (as in previous versions) with
|
||||
the command line parameter <option>--pid-file</option>. Note this will override
|
||||
any value set in <filename>repmgr.conf</filename> with <varname>repmgrd_pid_file</varname>.
|
||||
<option>--pid-file</option> may be deprecated in future releases.
|
||||
</para>
|
||||
<para>
|
||||
If a PID file location was specified by the package maintainer, <application>repmgrd</application>
|
||||
will use that. This only applies if &repmgr; was installed from a package and the package
|
||||
maintainer has specified the PID file location.
|
||||
</para>
|
||||
<para>
|
||||
If none of the above apply, <application>repmgrd</application> will create a PID file
|
||||
in the operating system's temporary directory (das etermined by the environment variable
|
||||
<varname>TMPDIR</varname>, or if that is not set, will use <filename>/tmp</filename>).
|
||||
</para>
|
||||
<para>
|
||||
To prevent a PID file being generated at all, provide the command line option
|
||||
<option>--no-pid-file</option>.
|
||||
</para>
|
||||
<para>
|
||||
To see which PID file <application>repmgrd</application> would use, execute <application>repmgrd</application>
|
||||
with the option <option>--show-pid-file</option>. <application>repmgrd</application>
|
||||
will not start if this option is provided. Note that the value shown is the
|
||||
file <application>repmgrd</application> would use next time it starts, and is
|
||||
not necessarily the PID file currently in use.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="repmgrd-configuration-debian-ubuntu">
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>Debian/Ubuntu and daemon configuration</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>Debian/Ubuntu</primary>
|
||||
<secondary>repmgrd daemon configuration</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>repmgrd daemon configuration on Debian/Ubuntu</title>
|
||||
|
||||
<para>
|
||||
If &repmgr; was installed from Debian/Ubuntu packages, additional configuration
|
||||
is required before <application>repmgrd</application> is started as a daemon.
|
||||
</para>
|
||||
<para>
|
||||
This is done via the file <filename>/etc/default/repmgrd</filename>, which by default
|
||||
looks like this:
|
||||
<programlisting>
|
||||
# default settings for repmgrd. This file is source by /bin/sh from
|
||||
# /etc/init.d/repmgrd
|
||||
|
||||
# disable repmgrd by default so it won't get started upon installation
|
||||
# valid values: yes/no
|
||||
REPMGRD_ENABLED=no
|
||||
|
||||
# configuration file (required)
|
||||
#REPMGRD_CONF="/path/to/repmgr.conf"
|
||||
|
||||
# additional options
|
||||
#REPMGRD_OPTS=""
|
||||
|
||||
# user to run repmgrd as
|
||||
#REPMGRD_USER=postgres
|
||||
|
||||
# repmgrd binary
|
||||
#REPMGRD_BIN=/usr/bin/repmgrd
|
||||
|
||||
# pid file
|
||||
#REPMGRD_PIDFILE=/var/run/repmgrd.pid</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Set <varname>REPMGRD_ENABLED</varname> to <literal>yes</literal>, and <varname>REPMGRD_CONF</varname>
|
||||
to the <filename>repmgr.conf</filename> file you are using.
|
||||
</para>
|
||||
<para>
|
||||
If using <application>systemd</application>, you may need to execute <command>systemctl daemon-reload</command>.
|
||||
Also, if you attempted to start <application>repmgrd</application> using <command>systemctl start repmgrd</command>,
|
||||
you'll need to execute <command>systemctl stop repmgrd</command>. Because that's how <application>systemd</application>
|
||||
rolls.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="repmgrd-connection-settings">
|
||||
<title>repmgrd connection settings</title>
|
||||
<para>
|
||||
In addition to the &repmgr; configuration settings, parameters in the
|
||||
<varname>conninfo</varname> string influence how &repmgr; makes a network connection to
|
||||
@@ -76,12 +314,21 @@
|
||||
<ulink url="https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PARAMKEYWORDS">PostgreSQL documentation</ulink>.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
<sect1 id="repmgrd-log-rotation">
|
||||
<indexterm>
|
||||
<primary>log rotation</primary>
|
||||
<secondary>repmgrd</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>repmgrd log rotation</title>
|
||||
<para>
|
||||
To ensure the current <application>repmgrd</application> logfile does not grow
|
||||
indefinitely, configure your system's <command>logrotate</command> to
|
||||
regularly rotate it.
|
||||
To ensure the current <application>repmgrd</application> logfile
|
||||
(specified in <filename>repmgr.conf</filename> with the parameter
|
||||
<option>log_file</option> does not grow indefinitely, configure your
|
||||
system's <command>logrotate</command> to regularly rotate it.
|
||||
</para>
|
||||
<para>
|
||||
Sample configuration to rotate logfiles weekly with retention for
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>repmgrd is monitoring the primary node, but it is not available</simpara>
|
||||
<simpara>repmgrd is monitoring the primary node, but it is not available (and no other node has been promoted as primary)</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
@@ -69,7 +69,15 @@
|
||||
By default, <literal>repmgrd</literal> will continue in degraded monitoring mode indefinitely.
|
||||
However a timeout (in seconds) can be set with <varname>degraded_monitoring_timeout</varname>,
|
||||
after which <application>repmgrd</application> will terminate.
|
||||
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If <application>repmgrd</application> is monitoring a primary mode which has been stopped
|
||||
and manually restarted as a standby attached to a new primary, it will automatically detect
|
||||
the status change and update the node record to reflect the node's new status
|
||||
as an active standby. It will then resume monitoring the node as a standby.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>monitoring</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>monitoring</primary>
|
||||
<secondary>with repmgrd</secondary>
|
||||
</indexterm>
|
||||
|
||||
<title>Monitoring with repmgrd</title>
|
||||
<para>
|
||||
|
||||
@@ -54,45 +54,106 @@
|
||||
<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>
|
||||
Ensure that a passwordless SSH connection is possible from the promotion candidate
|
||||
(standby) to the demotion candidate (current primary). If <literal>--siblings-follow</literal>
|
||||
will be used, ensure that passwordless SSH connections are possible from the
|
||||
promotion candidate to all standbys attached to the demotion candidate.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<simpara>
|
||||
&repmgr; expects to find the &repmgr; binary in the same path on the remote
|
||||
server as on the local server.
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
Double-check which commands will be used to stop/start/restart the current
|
||||
primary; on the primary execute:
|
||||
primary; on the current 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, particularly when executed on a remote
|
||||
server.
|
||||
</para>
|
||||
<para>
|
||||
For more details, see <xref linkend="configuration-file-service-commands">.
|
||||
</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.
|
||||
Check that access from applications is minimalized or preferably blocked
|
||||
completely, so applications are not unexpectedly interrupted.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If an exclusive backup is running on the current primary, &repmgr; will not perform the
|
||||
switchover.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
Check there is no significant replication lag on standbys attached to the
|
||||
current primary.
|
||||
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>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Ensure that <application>repmgrd</application> is *not* running anywhere to prevent it unintentionally
|
||||
promoting a node. This restriction will be removed in a future &repmgr; version.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
|
||||
<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 +162,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 +171,74 @@
|
||||
"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>
|
||||
|
||||
|
||||
<note>
|
||||
<simpara>
|
||||
See <xref linkend="repmgr-standby-switchover"> for a full list of available
|
||||
command line options and <filename>repmgr.conf</filename> settings relevant
|
||||
to performing a switchover.
|
||||
</simpara>
|
||||
</note>
|
||||
|
||||
<sect2 id="switchover-pg-rewind" xreflabel="Switchover and pg_rewind">
|
||||
<indexterm>
|
||||
<primary>pg_rewind</primary>
|
||||
<secondary>using with "repmgr standby switchover"</secondary>
|
||||
</indexterm>
|
||||
<title>Switchover and pg_rewind</title>
|
||||
<para>
|
||||
If the demotion candidate does not shut down smoothly or cleanly, there's a risk it
|
||||
will have a slightly divergent timeline and will not be able to attach to the new
|
||||
primary. To fix this situation without needing to reclone the old primary, it's
|
||||
possible to use the <application>pg_rewind</application> utility, which will usually be
|
||||
able to resync the two servers.
|
||||
</para>
|
||||
<para>
|
||||
To have &repmgr; execute <application>pg_rewind</application> if it detects this
|
||||
situation after promoting the new primary, add the <option>--force-rewind</option>
|
||||
option.
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
If &repmgr; detects a situation where it needs to execute <application>pg_rewind</application>,
|
||||
it will execute a <literal>CHECKPOINT</literal> on the new primary before executing
|
||||
<application>pg_rewind</application>.
|
||||
</simpara>
|
||||
</note>
|
||||
<para>
|
||||
For more details on <application>pg_rewind</application>, see:
|
||||
<ulink url="https://www.postgresql.org/docs/current/static/app-pgrewind.html">https://www.postgresql.org/docs/current/static/app-pgrewind.html</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
<application>pg_rewind</application> has been part of the core PostgreSQL distribution since
|
||||
version 9.5. Users of versions 9.3 and 9.4 will need to manually install it; the source code is available here:
|
||||
<ulink url="https://github.com/vmware/pg_rewind">https://github.com/vmware/pg_rewind</ulink>.
|
||||
If the <application>pg_rewind</application>
|
||||
binary is not installed in the PostgreSQL <filename>bin</filename> directory, provide
|
||||
its full path on the demotion candidate with <option>--force-rewind</option>.
|
||||
</para>
|
||||
<para>
|
||||
Note that building the 9.3/9.4 version of <application>pg_rewind</application> requires the PostgreSQL
|
||||
source code. Also, PostgreSQL 9.3 does not provide <varname>wal_log_hints</varname>,
|
||||
meaning data checksums must have been enabled when the database was initialized.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="switchover-execution" xreflabel="Executing the switchover command">
|
||||
@@ -133,7 +262,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
|
||||
|
||||
@@ -11,22 +11,92 @@
|
||||
containing bugfixes and other minor improvements. Any substantial new
|
||||
functionality will be included in a feature release (e.g. 4.0.x to 4.1.x).
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; is implemented as a PostgreSQL extension; to upgrade it, first
|
||||
install the updated package (or compile the updated source), then in the
|
||||
database where the &repmgr; extension is installed, execute
|
||||
<command>ALTER EXTENSION repmgr UPDATE</command>.
|
||||
</para>
|
||||
<para>
|
||||
If <application>repmgrd</application> is running, it may be necessary to restart
|
||||
the PostgreSQL server if the upgrade contains changes to the shared object
|
||||
file used by <application>repmgrd</application>; check the release notes for details.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Please check the <link linkend="appendix-release-notes">release notes</link> for every
|
||||
release as they may contain upgrade instructions particular to individual versions.
|
||||
</para>
|
||||
<sect1 id="upgrading-repmgr-extension" xreflabel="Upgrading repmgr 4.x and later">
|
||||
<indexterm>
|
||||
<primary>upgrading</primary>
|
||||
<secondary>repmgr 4.x and later</secondary>
|
||||
</indexterm>
|
||||
<title>Upgrading repmgr 4.x and later</title>
|
||||
<para>
|
||||
&repmgr; 4.x is implemented as a PostgreSQL extension; normally the upgrade consists
|
||||
of the two following steps:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<simpara>
|
||||
Install the updated package (or compile the updated source)
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<application>repmgrd</application> (if running) must be restarted.
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
For major releases, e.g. from <literal>4.0.x</literal> to <literal>4.1</literal>,
|
||||
execute <command>ALTER EXTENSION repmgr UPDATE</command>
|
||||
on the primary node in the database where the &repmgr; extension is installed.
|
||||
</simpara>
|
||||
<simpara>
|
||||
This will update the extension metadata and, if necessary, apply
|
||||
changes to the &repmgr; extension objects.
|
||||
</simpara>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Always check the <link linkend="appendix-release-notes">release notes</link> for every
|
||||
release as they may contain upgrade instructions particular to individual versions.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that it may be necessary to restart the PostgreSQL server if the upgrade contains
|
||||
changes to the shared object file used by <application>repmgrd</application>; check the
|
||||
release notes for details.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="upgrading-and-pg-upgrade" xreflabel="pg_upgrade and repmgr">
|
||||
<indexterm>
|
||||
<primary>upgrading</primary>
|
||||
<secondary>pg_upgrade</secondary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>pg_upgrade</primary>
|
||||
</indexterm>
|
||||
<title>pg_upgrade and repmgr</title>
|
||||
|
||||
<para>
|
||||
<application>pg_upgrade</application> requires that if any functions are
|
||||
dependent on a shared library, this library must be present in both
|
||||
the old and new installations before <application>pg_upgrade</application>
|
||||
can be executed.
|
||||
</para>
|
||||
<para>
|
||||
To minimize the risk of any upgrade issues (particularly if an upgrade to
|
||||
a new major &repmgr; version is involved), we recommend upgrading
|
||||
&repmgr; on the old server <emphasis>before</emphasis> running
|
||||
<application>pg_upgrade</application> to ensure that old and new
|
||||
versions are the same.
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
This issue applies to any PostgreSQL extension which has
|
||||
dependencies on a shared library.
|
||||
</simpara>
|
||||
</note>
|
||||
<para>
|
||||
For further details please see the <ulink url="https://www.postgresql.org/docs/current/static/pgupgrade.html">pg_upgrade documentation</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
If replication slots are in use, bear in mind these will <emphasis>not</emphasis>
|
||||
be recreated by <application>pg_upgrade</application>. These will need to
|
||||
be recreated manually.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="upgrading-from-repmgr-3" xreflabel="Upgrading from repmgr 3.x">
|
||||
<indexterm>
|
||||
@@ -45,7 +115,7 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
upgrading the repmgr schema
|
||||
upgrading the repmgr schema using <command>CREATE EXTENSION</command>
|
||||
</simpara>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
@@ -58,11 +128,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 +229,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 +245,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
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!ENTITY repmgrversion "4.0.0">
|
||||
<!ENTITY repmgrversion "4.1.0">
|
||||
|
||||
@@ -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
|
||||
@@ -43,5 +43,9 @@
|
||||
#define ERR_BARMAN 19
|
||||
#define ERR_REGISTRATION_SYNC 20
|
||||
#define ERR_OUT_OF_MEMORY 21
|
||||
#define ERR_SWITCHOVER_INCOMPLETE 22
|
||||
#define ERR_FOLLOW_FAIL 23
|
||||
#define ERR_REJOIN_FAIL 24
|
||||
#define ERR_NODE_STATUS 25
|
||||
|
||||
#endif /* _ERRCODE_H_ */
|
||||
|
||||
21
log.c
21
log.c
@@ -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
|
||||
@@ -42,7 +42,7 @@ _stderr_log_with_level(const char *level_name, int level, const char *fmt, va_li
|
||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
|
||||
|
||||
int log_type = REPMGR_STDERR;
|
||||
int log_level = LOG_NOTICE;
|
||||
int log_level = LOG_INFO;
|
||||
int last_log_level = LOG_INFO;
|
||||
int verbose_logging = false;
|
||||
int terse_logging = false;
|
||||
@@ -70,7 +70,7 @@ _stderr_log_with_level(const char *level_name, int level, const char *fmt, va_li
|
||||
|
||||
/*
|
||||
* Store the requested level so that if there's a subsequent log_hint() or
|
||||
* log_detail(), we can suppress that if appropriate.
|
||||
* log_detail(), we can suppress that if --terse was specified,
|
||||
*/
|
||||
last_log_level = level;
|
||||
|
||||
@@ -329,6 +329,21 @@ logger_set_terse(void)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
logger_set_level(int new_log_level)
|
||||
{
|
||||
log_level = new_log_level;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
logger_set_min_level(int min_log_level)
|
||||
{
|
||||
if (min_log_level > log_level)
|
||||
log_level = min_log_level;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
detect_log_level(const char *level)
|
||||
{
|
||||
|
||||
4
log.h
4
log.h
@@ -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
|
||||
@@ -128,6 +128,8 @@ bool logger_shutdown(void);
|
||||
|
||||
void logger_set_verbose(void);
|
||||
void logger_set_terse(void);
|
||||
void logger_set_min_level(int min_log_level);
|
||||
void logger_set_level(int new_log_level);
|
||||
|
||||
void
|
||||
log_detail(const char *fmt,...)
|
||||
|
||||
2
repmgr--4.0--4.1.sql
Normal file
2
repmgr--4.0--4.1.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
@@ -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 */
|
||||
|
||||
167
repmgr--4.1.sql
Normal file
167
repmgr--4.1.sql
Normal file
@@ -0,0 +1,167 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
||||
|
||||
CREATE TABLE repmgr.nodes (
|
||||
node_id INTEGER PRIMARY KEY,
|
||||
upstream_node_id INTEGER NULL REFERENCES nodes (node_id) DEFERRABLE,
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
node_name TEXT NOT NULL,
|
||||
type TEXT NOT NULL CHECK (type IN('primary','standby','witness','bdr')),
|
||||
location TEXT NOT NULL DEFAULT 'default',
|
||||
priority INT NOT NULL DEFAULT 100,
|
||||
conninfo TEXT NOT NULL,
|
||||
repluser VARCHAR(63) NOT NULL,
|
||||
slot_name TEXT NULL,
|
||||
config_file TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE repmgr.events (
|
||||
node_id INTEGER NOT NULL,
|
||||
event TEXT NOT NULL,
|
||||
successful BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
event_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
details TEXT NULL
|
||||
);
|
||||
|
||||
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,
|
||||
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
last_apply_time TIMESTAMP WITH TIME ZONE,
|
||||
last_wal_primary_location PG_LSN NOT NULL,
|
||||
last_wal_standby_location PG_LSN,
|
||||
replication_lag BIGINT NOT NULL,
|
||||
apply_lag BIGINT NOT NULL
|
||||
)
|
||||
$repmgr_func$;
|
||||
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$;
|
||||
END IF;
|
||||
END$repmgr$;
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_monitoring_history_time
|
||||
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
|
||||
|
||||
CREATE VIEW repmgr.show_nodes AS
|
||||
SELECT n.node_id,
|
||||
n.node_name,
|
||||
n.active,
|
||||
n.upstream_node_id,
|
||||
un.node_name AS upstream_node_name,
|
||||
n.type,
|
||||
n.priority,
|
||||
n.conninfo
|
||||
FROM repmgr.nodes n
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
|
||||
/* XXX update upgrade scripts! */
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX voting_term_restrict
|
||||
ON repmgr.voting_term ((TRUE));
|
||||
|
||||
CREATE RULE voting_term_delete AS
|
||||
ON DELETE TO repmgr.voting_term
|
||||
DO INSTEAD NOTHING;
|
||||
|
||||
|
||||
/* ================= */
|
||||
/* repmgrd functions */
|
||||
/* ================= */
|
||||
|
||||
/* monitoring functions */
|
||||
|
||||
CREATE FUNCTION set_local_node_id(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'set_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_local_node_id()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_local_node_id'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_set_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'standby_set_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION standby_get_last_updated()
|
||||
RETURNS TIMESTAMP WITH TIME ZONE
|
||||
AS 'MODULE_PATHNAME', 'standby_get_last_updated'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* failover functions */
|
||||
|
||||
CREATE FUNCTION notify_follow_primary(INT)
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'notify_follow_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION get_new_primary()
|
||||
RETURNS INT
|
||||
AS 'MODULE_PATHNAME', 'get_new_primary'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION reset_voting_status()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'reset_voting_status'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION am_bdr_failover_handler(INT)
|
||||
RETURNS BOOL
|
||||
AS 'MODULE_PATHNAME', 'am_bdr_failover_handler'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION unset_bdr_failover_handler()
|
||||
RETURNS VOID
|
||||
AS 'MODULE_PATHNAME', 'unset_bdr_failover_handler'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
|
||||
CREATE VIEW repmgr.replication_status AS
|
||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
||||
n.type AS node_type, n.active, last_monitor_time,
|
||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
||||
m.last_wal_standby_location,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
||||
CASE WHEN n.type='standby' THEN
|
||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
||||
ELSE NULL
|
||||
END AS replication_time_lag,
|
||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
||||
FROM repmgr.monitoring_history m
|
||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -83,16 +83,49 @@ do_bdr_register(void)
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
if (bdr_nodes.node_count > 2)
|
||||
/* BDR 2 implementation is for 2 nodes only */
|
||||
if (get_bdr_version_num() < 3 && bdr_nodes.node_count > 2)
|
||||
{
|
||||
log_error(_("repmgr can only support BDR clusters with 2 nodes"));
|
||||
log_error(_("repmgr can only support BDR 2.x clusters with 2 nodes"));
|
||||
log_detail(_("this BDR cluster has %i nodes"), bdr_nodes.node_count);
|
||||
PQfinish(conn);
|
||||
pfree(dbname);
|
||||
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 +175,10 @@ 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);
|
||||
}
|
||||
log_debug("bdr_node_has_repmgr_set() = false");
|
||||
bdr_node_set_repmgr_set(conn, config_file_options.node_name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -177,6 +203,7 @@ do_bdr_register(void)
|
||||
if (bdr_nodes.node_count == 0)
|
||||
{
|
||||
log_error(_("unable to retrieve any BDR node records"));
|
||||
log_detail("%s", PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
@@ -228,7 +255,35 @@ do_bdr_register(void)
|
||||
}
|
||||
|
||||
/* Add the repmgr extension tables to a replication set */
|
||||
add_extension_tables_to_bdr_replication_set(conn);
|
||||
|
||||
if (get_bdr_version_num() < 3)
|
||||
{
|
||||
add_extension_tables_to_bdr_replication_set(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this is the only table we need to replicate */
|
||||
char *replication_set = get_default_bdr_replication_set(conn);
|
||||
|
||||
/*
|
||||
* this probably won't happen, but we need to be sure we're using
|
||||
* the replication set metadata correctly...
|
||||
*/
|
||||
if (conn == NULL)
|
||||
{
|
||||
log_error(_("unable to retrieve default BDR replication set"));
|
||||
log_hint(_("see preceding messages"));
|
||||
log_debug("check query in get_default_bdr_replication_set()");
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
if (is_table_in_bdr_replication_set(conn, "nodes", replication_set) == false)
|
||||
{
|
||||
add_table_to_bdr_replication_set(conn, "nodes", replication_set);
|
||||
}
|
||||
|
||||
pfree(replication_set);
|
||||
}
|
||||
|
||||
initPQExpBuffer(&event_details);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -82,6 +82,8 @@ do_cluster_show(void)
|
||||
NodeInfoListCell *cell = NULL;
|
||||
int i = 0;
|
||||
ItemList warnings = {NULL, NULL};
|
||||
bool success = false;
|
||||
bool error_found = false;
|
||||
|
||||
/* Connect to local database to obtain cluster connection data */
|
||||
log_verbose(LOG_INFO, _("connecting to database"));
|
||||
@@ -91,11 +93,19 @@ do_cluster_show(void)
|
||||
else
|
||||
conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||
|
||||
get_all_node_records_with_upstream(conn, &nodes);
|
||||
success = get_all_node_records_with_upstream(conn, &nodes);
|
||||
|
||||
if (success == false)
|
||||
{
|
||||
/* get_all_node_records_with_upstream() will print error message */
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
if (nodes.node_count == 0)
|
||||
{
|
||||
log_error(_("unable to retrieve any node records"));
|
||||
log_error(_("no node records were found"));
|
||||
log_hint(_("ensure at least one node is registered"));
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
@@ -131,8 +141,14 @@ do_cluster_show(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
char error[MAXLEN];
|
||||
|
||||
strncpy(error, PQerrorMessage(cell->node_info->conn), MAXLEN);
|
||||
cell->node_info->node_status = NODE_STATUS_DOWN;
|
||||
cell->node_info->recovery_type = RECTYPE_UNKNOWN;
|
||||
item_list_append_format(&warnings,
|
||||
"when attempting to connect to node \"%s\" (ID: %i), following error encountered :\n\"%s\"",
|
||||
cell->node_info->node_name, cell->node_info->node_id, trim(error));
|
||||
}
|
||||
|
||||
initPQExpBuffer(&details);
|
||||
@@ -158,15 +174,13 @@ do_cluster_show(void)
|
||||
break;
|
||||
case RECTYPE_STANDBY:
|
||||
appendPQExpBuffer(&details, "! running as standby");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is registered as primary but running as standby",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
break;
|
||||
case RECTYPE_UNKNOWN:
|
||||
appendPQExpBuffer(&details, "! unknown");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) has unknown replication status",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
break;
|
||||
@@ -177,16 +191,14 @@ do_cluster_show(void)
|
||||
if (cell->node_info->recovery_type == RECTYPE_PRIMARY)
|
||||
{
|
||||
appendPQExpBuffer(&details, "! running");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is running but the repmgr node record is inactive",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&details, "! running as standby");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is registered as an inactive primary but running as standby",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
}
|
||||
@@ -199,8 +211,7 @@ do_cluster_show(void)
|
||||
if (cell->node_info->active == true)
|
||||
{
|
||||
appendPQExpBuffer(&details, "? unreachable");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is registered as an active primary but is unreachable",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
}
|
||||
@@ -208,6 +219,7 @@ do_cluster_show(void)
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&details, "- failed");
|
||||
error_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,8 +238,7 @@ do_cluster_show(void)
|
||||
break;
|
||||
case RECTYPE_PRIMARY:
|
||||
appendPQExpBuffer(&details, "! running as primary");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is registered as standby but running as primary",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
break;
|
||||
@@ -245,16 +256,14 @@ do_cluster_show(void)
|
||||
if (cell->node_info->recovery_type == RECTYPE_STANDBY)
|
||||
{
|
||||
appendPQExpBuffer(&details, "! running");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is running but the repmgr node record is inactive",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&details, "! running as primary");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is running as primary but the repmgr node record is inactive",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
}
|
||||
@@ -267,14 +276,14 @@ do_cluster_show(void)
|
||||
if (cell->node_info->active == true)
|
||||
{
|
||||
appendPQExpBuffer(&details, "? unreachable");
|
||||
item_list_append_format(
|
||||
&warnings,
|
||||
item_list_append_format(&warnings,
|
||||
"node \"%s\" (ID: %i) is registered as an active standby but is unreachable",
|
||||
cell->node_info->node_name, cell->node_info->node_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&details, "- failed");
|
||||
error_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,17 +295,27 @@ do_cluster_show(void)
|
||||
if (cell->node_info->node_status == NODE_STATUS_UP)
|
||||
{
|
||||
if (cell->node_info->active == true)
|
||||
{
|
||||
appendPQExpBuffer(&details, "* running");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&details, "! running");
|
||||
error_found = true;
|
||||
}
|
||||
}
|
||||
/* node is unreachable */
|
||||
else
|
||||
{
|
||||
if (cell->node_info->active == true)
|
||||
{
|
||||
appendPQExpBuffer(&details, "? unreachable");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&details, "- failed");
|
||||
error_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -304,6 +323,7 @@ do_cluster_show(void)
|
||||
{
|
||||
/* this should never happen */
|
||||
appendPQExpBuffer(&details, "? unknown node type");
|
||||
error_found = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -408,7 +428,6 @@ do_cluster_show(void)
|
||||
PQfinish(conn);
|
||||
|
||||
/* emit any warnings */
|
||||
|
||||
if (warnings.head != NULL && runtime_options.terse == false && runtime_options.output_mode != OM_CSV)
|
||||
{
|
||||
ItemListCell *cell = NULL;
|
||||
@@ -416,9 +435,23 @@ do_cluster_show(void)
|
||||
printf(_("\nWARNING: following issues were detected\n"));
|
||||
for (cell = warnings.head; cell; cell = cell->next)
|
||||
{
|
||||
printf(_(" %s\n"), cell->string);
|
||||
printf(_(" - %s\n"), cell->string);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If warnings were noted, even if they're not displayed (e.g. in --csv node),
|
||||
* that means something's not right so we need to emit a non-zero exit code.
|
||||
*/
|
||||
if (warnings.head != NULL)
|
||||
{
|
||||
error_found = true;
|
||||
}
|
||||
|
||||
if (error_found == true)
|
||||
{
|
||||
exit(ERR_NODE_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -430,88 +463,25 @@ do_cluster_show(void)
|
||||
* --all
|
||||
* --node-[id|name]
|
||||
* --event
|
||||
* --csv
|
||||
*/
|
||||
|
||||
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 +508,15 @@ 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 or --csv provided, simply omit the "Details" column.
|
||||
* In --csv mode we'd need to quote/escape the contents "Details" column,
|
||||
* which is doable but which will remain a TODO for now.
|
||||
*/
|
||||
if (runtime_options.terse == true || runtime_options.output_mode == OM_CSV)
|
||||
column_count --;
|
||||
|
||||
for (i = 0; i < column_count; i++)
|
||||
{
|
||||
headers_event[i].max_length = strlen(headers_event[i].title);
|
||||
}
|
||||
@@ -547,7 +525,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,47 +536,64 @@ do_cluster_event(void)
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < EVENT_HEADER_COUNT; i++)
|
||||
if (runtime_options.output_mode == OM_TEXT)
|
||||
{
|
||||
if (i == 0)
|
||||
printf(" ");
|
||||
else
|
||||
printf(" | ");
|
||||
for (i = 0; i < column_count; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
printf(" ");
|
||||
else
|
||||
printf(" | ");
|
||||
|
||||
printf("%-*s",
|
||||
headers_event[i].max_length,
|
||||
headers_event[i].title);
|
||||
printf("%-*s",
|
||||
headers_event[i].max_length,
|
||||
headers_event[i].title);
|
||||
}
|
||||
printf("\n");
|
||||
printf("-");
|
||||
for (i = 0; i < column_count; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < headers_event[i].max_length; j++)
|
||||
printf("-");
|
||||
|
||||
if (i < (column_count - 1))
|
||||
printf("-+-");
|
||||
else
|
||||
printf("-");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
printf("-");
|
||||
for (i = 0; i < EVENT_HEADER_COUNT; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < headers_event[i].max_length; j++)
|
||||
printf("-");
|
||||
|
||||
if (i < (EVENT_HEADER_COUNT - 1))
|
||||
printf("-+-");
|
||||
else
|
||||
printf("-");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (i = 0; i < PQntuples(res); i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
printf(" ");
|
||||
for (j = 0; j < EVENT_HEADER_COUNT; j++)
|
||||
if (runtime_options.output_mode == OM_CSV)
|
||||
{
|
||||
printf("%-*s",
|
||||
headers_event[j].max_length,
|
||||
PQgetvalue(res, i, j));
|
||||
for (j = 0; j < column_count; j++)
|
||||
{
|
||||
printf("%s", PQgetvalue(res, i, j));
|
||||
if ((j + 1) < column_count)
|
||||
{
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
for (j = 0; j < column_count; j++)
|
||||
{
|
||||
printf("%-*s",
|
||||
headers_event[j].max_length,
|
||||
PQgetvalue(res, i, j));
|
||||
|
||||
if (j < (EVENT_HEADER_COUNT - 1))
|
||||
printf(" | ");
|
||||
if (j < (column_count - 1))
|
||||
printf(" | ");
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
@@ -608,7 +603,8 @@ do_cluster_event(void)
|
||||
|
||||
PQfinish(conn);
|
||||
|
||||
puts("");
|
||||
if (runtime_options.output_mode == OM_TEXT)
|
||||
puts("");
|
||||
}
|
||||
|
||||
|
||||
@@ -623,6 +619,8 @@ do_cluster_crosscheck(void)
|
||||
|
||||
t_node_status_cube **cube;
|
||||
|
||||
bool error_found = false;
|
||||
|
||||
n = build_cluster_crosscheck(&cube, &name_length);
|
||||
if (runtime_options.output_mode == OM_CSV)
|
||||
{
|
||||
@@ -702,9 +700,11 @@ do_cluster_crosscheck(void)
|
||||
{
|
||||
case -2:
|
||||
c = '?';
|
||||
error_found = true;
|
||||
break;
|
||||
case -1:
|
||||
c = 'x';
|
||||
error_found = true;
|
||||
break;
|
||||
case 0:
|
||||
c = '*';
|
||||
@@ -743,6 +743,11 @@ do_cluster_crosscheck(void)
|
||||
|
||||
free(cube);
|
||||
}
|
||||
|
||||
if (error_found == true)
|
||||
{
|
||||
exit(ERR_NODE_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -758,6 +763,8 @@ do_cluster_matrix()
|
||||
|
||||
t_node_matrix_rec **matrix_rec_list;
|
||||
|
||||
bool error_found = false;
|
||||
|
||||
n = build_cluster_matrix(&matrix_rec_list, &name_length);
|
||||
|
||||
if (runtime_options.output_mode == OM_CSV)
|
||||
@@ -796,9 +803,11 @@ do_cluster_matrix()
|
||||
{
|
||||
case -2:
|
||||
c = '?';
|
||||
error_found = true;
|
||||
break;
|
||||
case -1:
|
||||
c = 'x';
|
||||
error_found = true;
|
||||
break;
|
||||
case 0:
|
||||
c = '*';
|
||||
@@ -824,6 +833,11 @@ do_cluster_matrix()
|
||||
}
|
||||
|
||||
free(matrix_rec_list);
|
||||
|
||||
if (error_found == true)
|
||||
{
|
||||
exit(ERR_NODE_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1018,8 +1032,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length)
|
||||
|
||||
initPQExpBuffer(&command_output);
|
||||
|
||||
(void) remote_command(
|
||||
host,
|
||||
(void) remote_command(host,
|
||||
runtime_options.remote_user,
|
||||
command.data,
|
||||
&command_output);
|
||||
@@ -1198,13 +1211,12 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
||||
/* fix to work with --node-id */
|
||||
if (cube[i]->node_id == config_file_options.node_id)
|
||||
{
|
||||
(void) local_command(
|
||||
command.data,
|
||||
&command_output);
|
||||
(void) local_command_simple(command.data,
|
||||
&command_output);
|
||||
}
|
||||
else
|
||||
{
|
||||
t_conninfo_param_list remote_conninfo;
|
||||
t_conninfo_param_list remote_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||
char *host = NULL;
|
||||
PQExpBufferData quoted_command;
|
||||
|
||||
@@ -1224,8 +1236,7 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length)
|
||||
|
||||
log_verbose(LOG_DEBUG, "build_cluster_crosscheck(): executing\n %s", quoted_command.data);
|
||||
|
||||
(void) remote_command(
|
||||
host,
|
||||
(void) remote_command(host,
|
||||
runtime_options.remote_user,
|
||||
quoted_command.data,
|
||||
&command_output);
|
||||
@@ -1386,6 +1397,7 @@ do_cluster_help(void)
|
||||
printf(_(" %s [OPTIONS] cluster matrix\n"), progname());
|
||||
printf(_(" %s [OPTIONS] cluster crosscheck\n"), progname());
|
||||
printf(_(" %s [OPTIONS] cluster event\n"), progname());
|
||||
printf(_(" %s [OPTIONS] cluster cleanup\n"), progname());
|
||||
puts("");
|
||||
|
||||
printf(_("CLUSTER SHOW\n"));
|
||||
@@ -1425,6 +1437,7 @@ do_cluster_help(void)
|
||||
printf(_(" --event filter specific event\n"));
|
||||
printf(_(" --node-id restrict entries to node with this ID\n"));
|
||||
printf(_(" --node-name restrict entries to node with this name\n"));
|
||||
printf(_(" --csv emit output as CSV\n"));
|
||||
puts("");
|
||||
|
||||
printf(_("CLUSTER CLEANUP\n"));
|
||||
|
||||
@@ -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
|
||||
|
||||
1623
repmgr-action-node.c
1623
repmgr-action-node.c
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
|
||||
@@ -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, ¤t_primary_id, NULL);
|
||||
@@ -543,7 +548,8 @@ do_primary_help(void)
|
||||
printf(_(" \"primary unregister\" unregisters an inactive primary node.\n"));
|
||||
puts("");
|
||||
printf(_(" --dry-run check what would happen, but don't actually unregister the primary\n"));
|
||||
printf(_(" -F, --force force removal of the record\n"));
|
||||
printf(_(" --node-id ID of the inactive primary node to unregister.\n"));
|
||||
printf(_(" -F, --force force removal of an active record\n"));
|
||||
|
||||
puts("");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -28,7 +28,7 @@ extern void do_standby_switchover(void);
|
||||
|
||||
extern void do_standby_help(void);
|
||||
|
||||
extern bool do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_record, PQExpBufferData *output);
|
||||
extern bool do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_record, PQExpBufferData *output, int *error_code);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -65,7 +65,7 @@ do_witness_register(void)
|
||||
if (recovery_type == RECTYPE_STANDBY)
|
||||
{
|
||||
log_error(_("provided node is a standby"));
|
||||
log_error(_("a witness node must run on an independent primary server"));
|
||||
log_hint(_("a witness node must run on an independent primary server"));
|
||||
|
||||
PQfinish(witness_conn);
|
||||
|
||||
@@ -86,6 +86,7 @@ do_witness_register(void)
|
||||
|
||||
/* connect to primary with provided parameters */
|
||||
log_info(_("connecting to primary node"));
|
||||
|
||||
/*
|
||||
* Extract the repmgr user and database names from the conninfo string
|
||||
* provided in repmgr.conf
|
||||
@@ -110,12 +111,12 @@ do_witness_register(void)
|
||||
}
|
||||
|
||||
/* check primary node's recovery type */
|
||||
recovery_type = get_recovery_type(witness_conn);
|
||||
recovery_type = get_recovery_type(primary_conn);
|
||||
|
||||
if (recovery_type == RECTYPE_STANDBY)
|
||||
{
|
||||
log_error(_("provided primary node is a standby"));
|
||||
log_error(_("provide the connection details of the cluster's primary server"));
|
||||
log_hint(_("provide the connection details of the cluster's primary server"));
|
||||
|
||||
PQfinish(witness_conn);
|
||||
PQfinish(primary_conn);
|
||||
@@ -135,8 +136,11 @@ do_witness_register(void)
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* XXX sanity check witness node is not part of main cluster */
|
||||
|
||||
/*
|
||||
* TODO: sanity check witness node is not part of main cluster; we could
|
||||
* add a random application_name to the respective connections,
|
||||
* and do a simple check of pg_stat_activity
|
||||
*/
|
||||
|
||||
/* create repmgr extension, if does not exist */
|
||||
if (runtime_options.dry_run == false && !create_repmgr_extension(witness_conn))
|
||||
@@ -182,7 +186,6 @@ do_witness_register(void)
|
||||
log_error(_("witness node is already registered"));
|
||||
log_hint(_("use option -F/--force to reregister the node"));
|
||||
|
||||
|
||||
PQfinish(witness_conn);
|
||||
PQfinish(primary_conn);
|
||||
|
||||
@@ -190,8 +193,26 @@ do_witness_register(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that an active node with the same node_name doesn't exist already
|
||||
*/
|
||||
|
||||
// XXX check other node with same name does not exist
|
||||
record_status = get_node_record_by_name(primary_conn,
|
||||
config_file_options.node_name,
|
||||
&node_record);
|
||||
|
||||
|
||||
if (record_status == RECORD_FOUND)
|
||||
{
|
||||
if (node_record.active == true && node_record.node_id != config_file_options.node_id)
|
||||
{
|
||||
log_error(_("node %i exists already with node_name \"%s\""),
|
||||
node_record.node_id,
|
||||
config_file_options.node_name);
|
||||
PQfinish(primary_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if repmgr.nodes contains entries, delete if -F/--force provided,
|
||||
@@ -222,6 +243,7 @@ do_witness_register(void)
|
||||
PQfinish(witness_conn);
|
||||
exit(SUCCESS);
|
||||
}
|
||||
|
||||
/* create record on primary */
|
||||
|
||||
/*
|
||||
@@ -288,55 +310,59 @@ do_witness_register(void)
|
||||
void
|
||||
do_witness_unregister(void)
|
||||
{
|
||||
PGconn *witness_conn = NULL;
|
||||
PGconn *local_conn = NULL;
|
||||
PGconn *primary_conn = NULL;
|
||||
t_node_info node_record = T_NODE_INFO_INITIALIZER;
|
||||
RecordStatus record_status = RECORD_NOT_FOUND;
|
||||
bool node_record_deleted = false;
|
||||
bool witness_available = true;
|
||||
bool local_node_available = true;
|
||||
int witness_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
log_info(_("connecting to witness node \"%s\" (ID: %i)"),
|
||||
if (runtime_options.node_id != UNKNOWN_NODE_ID)
|
||||
{
|
||||
/* user has specified the witness node id */
|
||||
witness_node_id = runtime_options.node_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* assume witness node is local node */
|
||||
witness_node_id = config_file_options.node_id;
|
||||
}
|
||||
|
||||
log_info(_("connecting to node \"%s\" (ID: %i)"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id);
|
||||
|
||||
witness_conn = establish_db_connection_quiet(config_file_options.conninfo);
|
||||
local_conn = establish_db_connection_quiet(config_file_options.conninfo);
|
||||
|
||||
if (PQstatus(witness_conn) != CONNECTION_OK)
|
||||
if (PQstatus(local_conn) != CONNECTION_OK)
|
||||
{
|
||||
if (!runtime_options.force)
|
||||
{
|
||||
log_error(_("unable to connect to witness node \"%s\" (ID: %i)"),
|
||||
log_error(_("unable to connect to node \"%s\" (ID: %i)"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id);
|
||||
log_detail("%s", PQerrorMessage(witness_conn));
|
||||
log_hint(_("provide -F/--force to remove the witness record if the server is not running"));
|
||||
log_detail("%s", PQerrorMessage(local_conn));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
log_notice(_("unable to connect to witness node \"%s\" (ID: %i), removing node record on cluster primary only"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id);
|
||||
witness_available = false;
|
||||
local_node_available = false;
|
||||
}
|
||||
|
||||
if (witness_available == true)
|
||||
if (local_node_available == true)
|
||||
{
|
||||
primary_conn = get_primary_connection_quiet(witness_conn, NULL, NULL);
|
||||
primary_conn = get_primary_connection_quiet(local_conn, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Extract the repmgr user and database names from the conninfo string
|
||||
* provided in repmgr.conf
|
||||
* Assume user has provided connection details for the primary server
|
||||
*/
|
||||
get_conninfo_value(config_file_options.conninfo, "user", repmgr_user);
|
||||
get_conninfo_value(config_file_options.conninfo, "dbname", repmgr_db);
|
||||
|
||||
param_set_ine(&source_conninfo, "user", repmgr_user);
|
||||
param_set_ine(&source_conninfo, "dbname", repmgr_db);
|
||||
|
||||
primary_conn = establish_db_connection_by_params(&source_conninfo, false);
|
||||
|
||||
}
|
||||
|
||||
if (PQstatus(primary_conn) != CONNECTION_OK)
|
||||
@@ -344,26 +370,26 @@ do_witness_unregister(void)
|
||||
log_error(_("unable to connect to primary"));
|
||||
log_detail("%s", PQerrorMessage(primary_conn));
|
||||
|
||||
if (witness_available == true)
|
||||
if (local_node_available == true)
|
||||
{
|
||||
PQfinish(witness_conn);
|
||||
PQfinish(local_conn);
|
||||
}
|
||||
else
|
||||
else if (runtime_options.connection_param_provided == false)
|
||||
{
|
||||
log_hint(_("provide connection details to primary server"));
|
||||
log_hint(_("provide connection details for the primary server"));
|
||||
}
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* Check node exists and is really a witness */
|
||||
record_status = get_node_record(primary_conn, config_file_options.node_id, &node_record);
|
||||
record_status = get_node_record(primary_conn, witness_node_id, &node_record);
|
||||
|
||||
if (record_status != RECORD_FOUND)
|
||||
{
|
||||
log_error(_("no record found for node %i"), config_file_options.node_id);
|
||||
log_error(_("no record found for node %i"), witness_node_id);
|
||||
|
||||
if (witness_available == true)
|
||||
PQfinish(witness_conn);
|
||||
if (local_node_available == true)
|
||||
PQfinish(local_conn);
|
||||
PQfinish(primary_conn);
|
||||
|
||||
exit(ERR_BAD_CONFIG);
|
||||
@@ -371,11 +397,17 @@ do_witness_unregister(void)
|
||||
|
||||
if (node_record.type != WITNESS)
|
||||
{
|
||||
/*
|
||||
* The node (either explicitly provided with --node-id, or the local node)
|
||||
* is not a witness.
|
||||
*
|
||||
* TODO: scan node list and print hint about identity of known witness servers.
|
||||
*/
|
||||
log_error(_("node %i is not a witness node"), config_file_options.node_id);
|
||||
log_detail(_("node %i is a %s node"), config_file_options.node_id, get_node_type_string(node_record.type));
|
||||
|
||||
if (witness_available == true)
|
||||
PQfinish(witness_conn);
|
||||
if (local_node_available == true)
|
||||
PQfinish(local_conn);
|
||||
PQfinish(primary_conn);
|
||||
|
||||
exit(ERR_BAD_CONFIG);
|
||||
@@ -384,49 +416,43 @@ do_witness_unregister(void)
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
log_info(_("prerequisites for unregistering the witness node are met"));
|
||||
if (witness_available == true)
|
||||
PQfinish(witness_conn);
|
||||
if (local_node_available == true)
|
||||
PQfinish(local_conn);
|
||||
PQfinish(primary_conn);
|
||||
|
||||
exit(SUCCESS);
|
||||
}
|
||||
|
||||
log_info(_("unregistering witness node %i"), config_file_options.node_id);
|
||||
log_info(_("unregistering witness node %i"), witness_node_id);
|
||||
node_record_deleted = delete_node_record(primary_conn,
|
||||
config_file_options.node_id);
|
||||
witness_node_id);
|
||||
|
||||
if (node_record_deleted == false)
|
||||
{
|
||||
PQfinish(primary_conn);
|
||||
PQfinish(witness_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* sync records from primary */
|
||||
if (witness_available == true && witness_copy_node_records(primary_conn, witness_conn) == false)
|
||||
{
|
||||
log_error(_("unable to copy repmgr node records from primary"));
|
||||
PQfinish(primary_conn);
|
||||
PQfinish(witness_conn);
|
||||
if (local_node_available == true)
|
||||
PQfinish(local_conn);
|
||||
PQfinish(local_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* Log the event */
|
||||
create_event_record(primary_conn,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
witness_node_id,
|
||||
"witness_unregister",
|
||||
true,
|
||||
NULL);
|
||||
|
||||
PQfinish(primary_conn);
|
||||
|
||||
if (witness_available == true)
|
||||
PQfinish(witness_conn);
|
||||
if (local_node_available == true)
|
||||
PQfinish(local_conn);
|
||||
|
||||
log_info(_("witness unregistration complete"));
|
||||
log_detail(_("witness node with id %i (conninfo: %s) successfully unregistered"),
|
||||
config_file_options.node_id, config_file_options.conninfo);
|
||||
log_detail(_("witness node with ID %i successfully unregistered"),
|
||||
witness_node_id);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -446,16 +472,19 @@ void do_witness_help(void)
|
||||
puts("");
|
||||
printf(_(" Requires provision of connection information for the primary\n"));
|
||||
puts("");
|
||||
printf(_(" --dry-run check prerequisites but don't make any changes\n"));
|
||||
printf(_(" -F, --force overwrite an existing node record\n"));
|
||||
printf(_(" --dry-run check prerequisites but don't make any changes\n"));
|
||||
printf(_(" -F, --force overwrite an existing node record\n"));
|
||||
puts("");
|
||||
|
||||
printf(_("WITNESS UNREGISTER\n"));
|
||||
puts("");
|
||||
printf(_(" \"witness register\" unregisters a witness node.\n"));
|
||||
puts("");
|
||||
printf(_(" --dry-run check prerequisites but don't make any changes\n"));
|
||||
printf(_(" -F, --force unregister when witness node not running\n"));
|
||||
printf(_(" --dry-run check prerequisites but don't make any changes\n"));
|
||||
printf(_(" -F, --force unregister when witness node not running\n"));
|
||||
printf(_(" --node-id node ID of the witness node (provide if executing on\n"));
|
||||
printf(_(" another node)\n"));
|
||||
|
||||
puts("");
|
||||
|
||||
return;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -42,10 +42,12 @@ typedef struct
|
||||
bool force;
|
||||
char pg_bindir[MAXLEN]; /* overrides setting in repmgr.conf */
|
||||
bool wait;
|
||||
bool no_wait;
|
||||
|
||||
/* logging options */
|
||||
char log_level[MAXLEN]; /* overrides setting in repmgr.conf */
|
||||
bool log_to_file;
|
||||
bool quiet;
|
||||
bool terse;
|
||||
bool verbose;
|
||||
|
||||
@@ -68,6 +70,7 @@ typedef struct
|
||||
int node_id;
|
||||
char node_name[MAXLEN];
|
||||
char data_dir[MAXPGPATH];
|
||||
int remote_node_id;
|
||||
|
||||
/* "standby clone" options */
|
||||
bool copy_external_config_files;
|
||||
@@ -79,6 +82,7 @@ typedef struct
|
||||
char replication_user[MAXLEN];
|
||||
char upstream_conninfo[MAXLEN];
|
||||
bool without_barman;
|
||||
bool recovery_conf_only;
|
||||
|
||||
/* "standby clone"/"standby follow" options */
|
||||
int upstream_node_id;
|
||||
@@ -86,10 +90,12 @@ typedef struct
|
||||
/* "standby register" options */
|
||||
bool wait_register_sync;
|
||||
int wait_register_sync_seconds;
|
||||
int wait_start;
|
||||
|
||||
/* "standby switchover" options */
|
||||
bool always_promote;
|
||||
bool force_rewind;
|
||||
bool force_rewind_used;
|
||||
char force_rewind_path[MAXPGPATH];
|
||||
bool siblings_follow;
|
||||
|
||||
/* "node status" options */
|
||||
@@ -101,6 +107,9 @@ typedef struct
|
||||
bool replication_lag;
|
||||
bool role;
|
||||
bool slots;
|
||||
bool missing_slots;
|
||||
bool has_passfile;
|
||||
bool replication_connection;
|
||||
|
||||
/* "node join" options */
|
||||
char config_files[MAXLEN];
|
||||
@@ -128,30 +137,30 @@ typedef struct
|
||||
/* configuration metadata */ \
|
||||
false, false, false, false, \
|
||||
/* general configuration options */ \
|
||||
"", false, false, "", false, \
|
||||
"", false, false, "", false, false, \
|
||||
/* logging options */ \
|
||||
"", false, false, false, \
|
||||
"", false, false, false, false, \
|
||||
/* output options */ \
|
||||
false, false, false, \
|
||||
/* database connection options */ \
|
||||
"", "", "", "", \
|
||||
"", "", "", "", \
|
||||
/* other connection options */ \
|
||||
"", "", \
|
||||
/* node options */ \
|
||||
UNKNOWN_NODE_ID, "", "", \
|
||||
"", "", \
|
||||
/* general node options */ \
|
||||
UNKNOWN_NODE_ID, "", "", UNKNOWN_NODE_ID, \
|
||||
/* "standby clone" options */ \
|
||||
false, CONFIG_FILE_SAMEPATH, false, false, false, "", "", "", \
|
||||
false, \
|
||||
false, false, \
|
||||
/* "standby clone"/"standby follow" options */ \
|
||||
NO_UPSTREAM_NODE, \
|
||||
/* "standby register" options */ \
|
||||
false, 0, \
|
||||
false, -1, DEFAULT_WAIT_START, \
|
||||
/* "standby switchover" options */ \
|
||||
false, false, false, \
|
||||
false, false, "", false, \
|
||||
/* "node status" options */ \
|
||||
false, \
|
||||
/* "node check" options */ \
|
||||
false, false, false, false, false, \
|
||||
false, false, false, false, false, false, false, false, \
|
||||
/* "node join" options */ \
|
||||
"", \
|
||||
/* "node service" options */ \
|
||||
@@ -160,7 +169,7 @@ typedef struct
|
||||
false, "", CLUSTER_EVENT_LIMIT, \
|
||||
/* "cluster cleanup" options */ \
|
||||
0, \
|
||||
/* Following options for internal use */ \
|
||||
/* following options for internal use */ \
|
||||
"/tmp", OM_TEXT \
|
||||
}
|
||||
|
||||
@@ -177,6 +186,7 @@ typedef enum
|
||||
ACTION_NONE,
|
||||
ACTION_START,
|
||||
ACTION_STOP,
|
||||
ACTION_STOP_WAIT,
|
||||
ACTION_RESTART,
|
||||
ACTION_RELOAD,
|
||||
ACTION_PROMOTE
|
||||
@@ -202,6 +212,7 @@ extern void check_93_config(void);
|
||||
extern bool create_repmgr_extension(PGconn *conn);
|
||||
extern int test_ssh_connection(char *host, char *remote_user);
|
||||
extern bool local_command(const char *command, PQExpBufferData *outputbuf);
|
||||
extern bool local_command_simple(const char *command, PQExpBufferData *outputbuf);
|
||||
|
||||
extern standy_clone_mode get_standby_clone_mode(void);
|
||||
|
||||
@@ -222,7 +233,9 @@ extern void print_help_header(void);
|
||||
/* server control functions */
|
||||
extern void get_server_action(t_server_action action, char *script, char *data_dir);
|
||||
extern bool data_dir_required_for_action(t_server_action action);
|
||||
extern void get_node_config_directory(char *config_dir_buf);
|
||||
extern void get_node_data_directory(char *data_dir_buf);
|
||||
extern void init_node_record(t_node_info *node_record);
|
||||
extern bool can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason);
|
||||
|
||||
#endif /* _REPMGR_CLIENT_GLOBAL_H_ */
|
||||
|
||||
550
repmgr-client.c
550
repmgr-client.c
@@ -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
|
||||
@@ -53,6 +53,7 @@
|
||||
|
||||
#include "repmgr.h"
|
||||
#include "compat.h"
|
||||
#include "controldata.h"
|
||||
#include "repmgr-client.h"
|
||||
#include "repmgr-client-global.h"
|
||||
#include "repmgr-action-primary.h"
|
||||
@@ -60,7 +61,6 @@
|
||||
#include "repmgr-action-witness.h"
|
||||
#include "repmgr-action-bdr.h"
|
||||
#include "repmgr-action-node.h"
|
||||
|
||||
#include "repmgr-action-cluster.h"
|
||||
|
||||
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
|
||||
@@ -73,7 +73,7 @@ t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER;
|
||||
t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER;
|
||||
|
||||
/* conninfo params for the node we're operating on */
|
||||
t_conninfo_param_list source_conninfo;
|
||||
t_conninfo_param_list source_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||
|
||||
bool config_file_required = true;
|
||||
char pg_bindir[MAXLEN] = "";
|
||||
@@ -91,13 +91,14 @@ t_node_info target_node_info = T_NODE_INFO_INITIALIZER;
|
||||
static ItemList cli_errors = {NULL, NULL};
|
||||
static ItemList cli_warnings = {NULL, NULL};
|
||||
|
||||
static bool _local_command(const char *command, PQExpBufferData *outputbuf, bool simple);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
t_conninfo_param_list default_conninfo;
|
||||
t_conninfo_param_list default_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||
|
||||
int optindex;
|
||||
int optindex = 0;
|
||||
int c;
|
||||
|
||||
char *repmgr_command = NULL;
|
||||
@@ -107,6 +108,7 @@ main(int argc, char **argv)
|
||||
char *dummy_action = "";
|
||||
|
||||
bool help_option = false;
|
||||
bool option_error_found = false;
|
||||
|
||||
set_progname(argv[0]);
|
||||
|
||||
@@ -177,7 +179,10 @@ 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,
|
||||
/* Make getopt emitting errors */
|
||||
opterr = 1;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "?Vb:f:FwWd:h:p:U:R:S:D:ck:L:qtvC:", long_options,
|
||||
&optindex)) != -1)
|
||||
{
|
||||
/*
|
||||
@@ -195,13 +200,7 @@ main(int argc, char **argv)
|
||||
case OPT_HELP: /* --help */
|
||||
help_option = true;
|
||||
break;
|
||||
case '?':
|
||||
/* Actual help option given */
|
||||
if (strcmp(argv[optind - 1], "-?") == 0)
|
||||
{
|
||||
help_option = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
|
||||
/*
|
||||
@@ -242,11 +241,16 @@ main(int argc, char **argv)
|
||||
strncpy(runtime_options.replication_user, optarg, MAXLEN);
|
||||
break;
|
||||
|
||||
/* -W/--wait */
|
||||
case 'W':
|
||||
/* -w/--wait */
|
||||
case 'w':
|
||||
runtime_options.wait = true;
|
||||
break;
|
||||
|
||||
/* -W/--no-wait */
|
||||
case 'W':
|
||||
runtime_options.no_wait = true;
|
||||
break;
|
||||
|
||||
/*----------------------------
|
||||
* database connection options
|
||||
*----------------------------
|
||||
@@ -329,6 +333,11 @@ main(int argc, char **argv)
|
||||
strncpy(runtime_options.node_name, optarg, MAXLEN);
|
||||
break;
|
||||
|
||||
/* --remote-node-id */
|
||||
case OPT_REMOTE_NODE_ID:
|
||||
runtime_options.remote_node_id = repmgr_atoi(optarg, "--remote-node-id", &cli_errors, false);
|
||||
break;
|
||||
|
||||
/*
|
||||
* standby options * ---------------
|
||||
*/
|
||||
@@ -384,12 +393,21 @@ main(int argc, char **argv)
|
||||
runtime_options.without_barman = true;
|
||||
break;
|
||||
|
||||
case OPT_RECOVERY_CONF_ONLY:
|
||||
runtime_options.recovery_conf_only = true;
|
||||
break;
|
||||
|
||||
|
||||
/*---------------------------
|
||||
* "standby register" options
|
||||
*---------------------------
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -407,7 +425,13 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case OPT_FORCE_REWIND:
|
||||
runtime_options.force_rewind = true;
|
||||
runtime_options.force_rewind_used = true;
|
||||
|
||||
if (optarg != NULL)
|
||||
{
|
||||
strncpy(runtime_options.force_rewind_path, optarg, MAXPGPATH);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OPT_SIBLINGS_FOLLOW:
|
||||
@@ -447,6 +471,18 @@ main(int argc, char **argv)
|
||||
runtime_options.slots = true;
|
||||
break;
|
||||
|
||||
case OPT_MISSING_SLOTS:
|
||||
runtime_options.missing_slots = true;
|
||||
break;
|
||||
|
||||
case OPT_HAS_PASSFILE:
|
||||
runtime_options.has_passfile = true;
|
||||
break;
|
||||
|
||||
case OPT_REPL_CONN:
|
||||
runtime_options.replication_connection = true;
|
||||
break;
|
||||
|
||||
/*--------------------
|
||||
* "node rejoin" options
|
||||
*--------------------
|
||||
@@ -538,6 +574,12 @@ main(int argc, char **argv)
|
||||
logger_output_mode = OM_DAEMON;
|
||||
break;
|
||||
|
||||
|
||||
/* --quiet */
|
||||
case 'q':
|
||||
runtime_options.quiet = true;
|
||||
break;
|
||||
|
||||
/* --terse */
|
||||
case 't':
|
||||
runtime_options.terse = true;
|
||||
@@ -593,14 +635,29 @@ main(int argc, char **argv)
|
||||
_("--recovery-min-apply-delay is now a configuration file parameter, \"recovery_min_apply_delay\""));
|
||||
break;
|
||||
|
||||
case ':': /* missing option argument */
|
||||
option_error_found = true;
|
||||
break;
|
||||
case '?':
|
||||
/* Actual help option given? */
|
||||
if (strcmp(argv[optind - 1], "-?") == 0)
|
||||
{
|
||||
help_option = true;
|
||||
break;
|
||||
}
|
||||
/* otherwise fall through to default */
|
||||
default: /* invalid option */
|
||||
option_error_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If -d/--dbname appears to be a conninfo string, validate by attempting
|
||||
* to parse it (and if successful, store the parsed parameters)
|
||||
*/
|
||||
if (runtime_options.dbname)
|
||||
if (runtime_options.dbname[0])
|
||||
{
|
||||
if (strncmp(runtime_options.dbname, "postgresql://", 13) == 0 ||
|
||||
strncmp(runtime_options.dbname, "postgres://", 11) == 0 ||
|
||||
@@ -696,9 +753,10 @@ main(int argc, char **argv)
|
||||
if (cli_errors.head != NULL)
|
||||
{
|
||||
free_conninfo_params(&source_conninfo);
|
||||
exit_with_cli_errors(&cli_errors);
|
||||
exit_with_cli_errors(&cli_errors, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*----------
|
||||
* Determine the node type and action; following are valid:
|
||||
*
|
||||
@@ -729,7 +787,6 @@ main(int argc, char **argv)
|
||||
|
||||
if (repmgr_command != NULL)
|
||||
{
|
||||
#ifndef BDR_ONLY
|
||||
if (strcasecmp(repmgr_command, "PRIMARY") == 0 || strcasecmp(repmgr_command, "MASTER") == 0)
|
||||
{
|
||||
if (help_option == true)
|
||||
@@ -786,9 +843,6 @@ main(int argc, char **argv)
|
||||
action = WITNESS_UNREGISTER;
|
||||
}
|
||||
else if (strcasecmp(repmgr_command, "BDR") == 0)
|
||||
#else
|
||||
if (strcasecmp(repmgr_command, "BDR") == 0)
|
||||
#endif
|
||||
{
|
||||
if (help_option == true)
|
||||
{
|
||||
@@ -949,9 +1003,30 @@ main(int argc, char **argv)
|
||||
if (cli_errors.head != NULL)
|
||||
{
|
||||
free_conninfo_params(&source_conninfo);
|
||||
exit_with_cli_errors(&cli_errors);
|
||||
|
||||
exit_with_cli_errors(&cli_errors, valid_repmgr_command_found == true ? repmgr_command : NULL);
|
||||
}
|
||||
|
||||
/* no errors detected by repmgr, but getopt might have */
|
||||
if (option_error_found == true)
|
||||
{
|
||||
if (valid_repmgr_command_found == true)
|
||||
{
|
||||
printf(_("Try \"%s --help\" or \"%s %s --help\" for more information.\n"),
|
||||
progname(),
|
||||
progname(),
|
||||
repmgr_command);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(_("Try \"repmgr --help\" for more information.\n"));
|
||||
}
|
||||
|
||||
free_conninfo_params(&source_conninfo);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print any warnings about inappropriate command line options, unless
|
||||
* -t/--terse set
|
||||
@@ -980,32 +1055,10 @@ main(int argc, char **argv)
|
||||
runtime_options.output_mode = OM_OPTFORMAT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* check for conflicts between runtime options and configuration file */
|
||||
/* ================================================================== */
|
||||
|
||||
if (action == STANDBY_CLONE)
|
||||
{
|
||||
standy_clone_mode mode = get_standby_clone_mode();
|
||||
|
||||
if (mode == barman && runtime_options.without_barman == false
|
||||
&& config_file_options.use_replication_slots == true)
|
||||
{
|
||||
log_error(_("STANDBY CLONE in Barman mode is incompatible with configuration option \"use_replication_slots\""));
|
||||
log_hint(_("set \"use_replication_slots\" to \"no\" in repmgr.conf, or use --without-barman fo clone directly from the upstream server"));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for configuration file items which can be overriden by runtime
|
||||
* options
|
||||
*/
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* =====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -1059,6 +1112,28 @@ main(int argc, char **argv)
|
||||
if (runtime_options.terse)
|
||||
logger_set_terse();
|
||||
|
||||
/*
|
||||
* If --dry-run specified, ensure log_level is at least LOG_INFO, regardless
|
||||
* of what's in the configuration file or -L/--log-level paremeter, otherwise
|
||||
* some or output might not be displayed.
|
||||
*/
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
logger_set_min_level(LOG_INFO);
|
||||
}
|
||||
|
||||
/*
|
||||
* If -q/--quiet supplied, suppress any non-ERROR log output.
|
||||
* This overrides everything else; we'll leave it up to the user to deal with the
|
||||
* consequences of e.g. running --dry-run together with -q/--quiet.
|
||||
*/
|
||||
if (runtime_options.quiet == true)
|
||||
{
|
||||
logger_set_level(LOG_ERROR);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Node configuration information is not needed for all actions, with
|
||||
* STANDBY CLONE being the main exception.
|
||||
@@ -1149,7 +1224,6 @@ main(int argc, char **argv)
|
||||
|
||||
switch (action)
|
||||
{
|
||||
#ifndef BDR_ONLY
|
||||
/* PRIMARY */
|
||||
case PRIMARY_REGISTER:
|
||||
do_primary_register();
|
||||
@@ -1185,21 +1259,6 @@ main(int argc, char **argv)
|
||||
case WITNESS_UNREGISTER:
|
||||
do_witness_unregister();
|
||||
break;
|
||||
#else
|
||||
/* we won't ever reach here, but stop the compiler complaining */
|
||||
case PRIMARY_REGISTER:
|
||||
case PRIMARY_UNREGISTER:
|
||||
case STANDBY_CLONE:
|
||||
case STANDBY_REGISTER:
|
||||
case STANDBY_UNREGISTER:
|
||||
case STANDBY_PROMOTE:
|
||||
case STANDBY_FOLLOW:
|
||||
case STANDBY_SWITCHOVER:
|
||||
case WITNESS_REGISTER:
|
||||
case WITNESS_UNREGISTER:
|
||||
break;
|
||||
|
||||
#endif
|
||||
/* BDR */
|
||||
case BDR_REGISTER:
|
||||
do_bdr_register();
|
||||
@@ -1316,7 +1375,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
|
||||
*/
|
||||
|
||||
@@ -1335,6 +1394,15 @@ check_cli_parameters(const int action)
|
||||
_("--no-upstream-connection only effective in Barman mode"));
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(config_file_options.config_directory))
|
||||
{
|
||||
if (runtime_options.copy_external_config_files == false)
|
||||
{
|
||||
item_list_append(&cli_warnings,
|
||||
_("\"config_directory\" set in repmgr.conf, but --copy-external-config-files not provided"));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1356,6 +1424,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)
|
||||
{
|
||||
@@ -1445,6 +1519,7 @@ check_cli_parameters(const int action)
|
||||
{
|
||||
case PRIMARY_UNREGISTER:
|
||||
case STANDBY_UNREGISTER:
|
||||
case WITNESS_UNREGISTER:
|
||||
case CLUSTER_EVENT:
|
||||
case CLUSTER_MATRIX:
|
||||
case CLUSTER_CROSSCHECK:
|
||||
@@ -1485,6 +1560,7 @@ check_cli_parameters(const int action)
|
||||
case STANDBY_CLONE:
|
||||
case STANDBY_REGISTER:
|
||||
case STANDBY_FOLLOW:
|
||||
case BDR_REGISTER:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
@@ -1493,6 +1569,39 @@ check_cli_parameters(const int action)
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.replication_user[0])
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case PRIMARY_REGISTER:
|
||||
case STANDBY_REGISTER:
|
||||
case STANDBY_CLONE:
|
||||
break;
|
||||
|
||||
case STANDBY_FOLLOW:
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--replication-user ignored when executing %s"),
|
||||
action_name(action));
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--replication-user not required when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.recovery_conf_only == true)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case STANDBY_CLONE:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--create-recovery-conf will be ignored when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.event[0])
|
||||
{
|
||||
switch (action)
|
||||
@@ -1506,25 +1615,6 @@ check_cli_parameters(const int action)
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.replication_user[0])
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case PRIMARY_REGISTER:
|
||||
case STANDBY_REGISTER:
|
||||
break;
|
||||
case STANDBY_CLONE:
|
||||
case STANDBY_FOLLOW:
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--replication-user ignored when executing %s)"),
|
||||
action_name(action));
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--replication-user not required when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.limit_provided)
|
||||
{
|
||||
switch (action)
|
||||
@@ -1563,6 +1653,41 @@ check_cli_parameters(const int action)
|
||||
}
|
||||
}
|
||||
|
||||
/* --wait/--no-wait */
|
||||
|
||||
if (runtime_options.wait == true && runtime_options.no_wait == true)
|
||||
{
|
||||
item_list_append_format(&cli_errors,
|
||||
_("both --wait and --no-wait options provided"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (runtime_options.wait)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case STANDBY_FOLLOW:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--wait will be ignored when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
}
|
||||
else if (runtime_options.wait)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case NODE_REJOIN:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--no-wait will be ignored when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* repmgr node service --action */
|
||||
if (runtime_options.action[0] != '\0')
|
||||
{
|
||||
@@ -1585,8 +1710,7 @@ check_cli_parameters(const int action)
|
||||
case NODE_STATUS:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(
|
||||
&cli_warnings,
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--is-shutdown-cleanly will be ignored when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
@@ -1599,14 +1723,13 @@ check_cli_parameters(const int action)
|
||||
case STANDBY_SWITCHOVER:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(
|
||||
&cli_warnings,
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--always-promote will be ignored when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.force_rewind == true)
|
||||
if (runtime_options.force_rewind_used == true)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
@@ -1614,8 +1737,7 @@ check_cli_parameters(const int action)
|
||||
case NODE_REJOIN:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(
|
||||
&cli_warnings,
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--force-rewind will be ignored when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
@@ -1629,8 +1751,7 @@ check_cli_parameters(const int action)
|
||||
case NODE_REJOIN:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(
|
||||
&cli_warnings,
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--config-files will be ignored when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
@@ -1644,6 +1765,7 @@ check_cli_parameters(const int action)
|
||||
case PRIMARY_UNREGISTER:
|
||||
case STANDBY_CLONE:
|
||||
case STANDBY_REGISTER:
|
||||
case STANDBY_FOLLOW:
|
||||
case STANDBY_SWITCHOVER:
|
||||
case WITNESS_REGISTER:
|
||||
case WITNESS_UNREGISTER:
|
||||
@@ -1651,8 +1773,7 @@ check_cli_parameters(const int action)
|
||||
case NODE_SERVICE:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(
|
||||
&cli_warnings,
|
||||
item_list_append_format(&cli_warnings,
|
||||
_("--dry-run is not effective when executing %s"),
|
||||
action_name(action));
|
||||
}
|
||||
@@ -1674,8 +1795,7 @@ check_cli_parameters(const int action)
|
||||
if (used_options > 1)
|
||||
{
|
||||
/* TODO: list which options were used */
|
||||
item_list_append(
|
||||
&cli_errors,
|
||||
item_list_append(&cli_errors,
|
||||
"only one of --csv, --nagios and --optformat can be used");
|
||||
}
|
||||
}
|
||||
@@ -1779,13 +1899,12 @@ do_help(void)
|
||||
print_help_header();
|
||||
|
||||
printf(_("Usage:\n"));
|
||||
#ifndef BDR_ONLY
|
||||
printf(_(" %s [OPTIONS] primary {register|unregister}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] standby {register|unregister|clone|promote|follow}\n"), progname());
|
||||
#endif
|
||||
printf(_(" %s [OPTIONS] standby {register|unregister|clone|promote|follow|switchover}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] bdr {register|unregister}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] node status\n"), progname());
|
||||
printf(_(" %s [OPTIONS] cluster {show|event|matrix|crosscheck}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] node {status|check|rejoin|service}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] cluster {show|event|matrix|crosscheck|cleanup}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] witness {register|unregister}\n"), progname());
|
||||
|
||||
puts("");
|
||||
|
||||
@@ -1833,6 +1952,7 @@ do_help(void)
|
||||
printf(_(" --dry-run show what would happen for action, but don't execute it\n"));
|
||||
printf(_(" -L, --log-level set log level (overrides configuration file; default: NOTICE)\n"));
|
||||
printf(_(" --log-to-file log to file (or logging facility) defined in repmgr.conf\n"));
|
||||
printf(_(" -q, --quiet suppress all log output apart from errors\n"));
|
||||
printf(_(" -t, --terse don't display detail, hints and other non-critical output\n"));
|
||||
printf(_(" -v, --verbose display additional log output (useful for debugging)\n"));
|
||||
|
||||
@@ -2102,6 +2222,8 @@ test_ssh_connection(char *host, char *remote_user)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Execute a command locally. "outputbuf" should either be an
|
||||
* initialised PQexpbuffer, or NULL
|
||||
@@ -2109,9 +2231,26 @@ test_ssh_connection(char *host, char *remote_user)
|
||||
bool
|
||||
local_command(const char *command, PQExpBufferData *outputbuf)
|
||||
{
|
||||
FILE *fp;
|
||||
return _local_command(command, outputbuf, false);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
local_command_simple(const char *command, PQExpBufferData *outputbuf)
|
||||
{
|
||||
return _local_command(command, outputbuf, true);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
_local_command(const char *command, PQExpBufferData *outputbuf, bool simple)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char output[MAXLEN];
|
||||
int retval = 0;
|
||||
bool success;
|
||||
|
||||
log_verbose(LOG_DEBUG, "executing:\n %s", command);
|
||||
|
||||
if (outputbuf == NULL)
|
||||
{
|
||||
@@ -2127,27 +2266,46 @@ local_command(const char *command, PQExpBufferData *outputbuf)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: better error handling */
|
||||
|
||||
while (fgets(output, MAXLEN, fp) != NULL)
|
||||
{
|
||||
appendPQExpBuffer(outputbuf, "%s", output);
|
||||
|
||||
if (!feof(fp) && simple == false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
retval = pclose(fp);
|
||||
|
||||
/* */
|
||||
success = (WEXITSTATUS(retval) == 0 || WEXITSTATUS(retval) == 141) ? true : false;
|
||||
|
||||
log_verbose(LOG_DEBUG, "result of command was %i (%i)", WEXITSTATUS(retval), retval);
|
||||
|
||||
if (outputbuf->data != NULL)
|
||||
log_verbose(LOG_DEBUG, "local_command(): output returned was:\n%s", outputbuf->data);
|
||||
else
|
||||
log_verbose(LOG_DEBUG, "local_command(): no output returned");
|
||||
|
||||
return true;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_superuser_connection()
|
||||
*
|
||||
* Check if provided connection "conn" is a superuser connection, if not attempt to
|
||||
* make a superuser connection "superuser_conn" with the provided --superuser parameter.
|
||||
*
|
||||
* "privileged_conn" is set to whichever connection is the superuser connection.
|
||||
*/
|
||||
void
|
||||
get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privileged_conn)
|
||||
{
|
||||
t_connection_user userinfo = T_CONNECTION_USER_INITIALIZER;
|
||||
t_conninfo_param_list conninfo_params = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||
bool is_superuser = false;
|
||||
|
||||
/* this should never happen */
|
||||
@@ -2156,6 +2314,7 @@ get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privil
|
||||
log_error(_("no database connection available"));
|
||||
exit(ERR_INTERNAL);
|
||||
}
|
||||
|
||||
is_superuser = is_superuser_connection(*conn, &userinfo);
|
||||
|
||||
if (is_superuser == true)
|
||||
@@ -2173,9 +2332,11 @@ get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privil
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
*superuser_conn = establish_db_connection_as_user(config_file_options.conninfo,
|
||||
runtime_options.superuser,
|
||||
false);
|
||||
initialize_conninfo_params(&conninfo_params, false);
|
||||
conn_to_param_list(*conn, &conninfo_params);
|
||||
param_set(&conninfo_params, "user", runtime_options.superuser);
|
||||
|
||||
*superuser_conn = establish_db_connection_by_params(&conninfo_params, false);
|
||||
|
||||
if (PQstatus(*superuser_conn) != CONNECTION_OK)
|
||||
{
|
||||
@@ -2195,6 +2356,8 @@ get_superuser_connection(PGconn **conn, PGconn **superuser_conn, PGconn **privil
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
log_debug("established superuser connection as \"%s\"", runtime_options.superuser);
|
||||
|
||||
*privileged_conn = *superuser_conn;
|
||||
return;
|
||||
}
|
||||
@@ -2336,9 +2499,6 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Execute a command via ssh on the remote host.
|
||||
*
|
||||
@@ -2402,7 +2562,12 @@ remote_command(const char *host, const char *user, const char *command, PQExpBuf
|
||||
pclose(fp);
|
||||
|
||||
if (outputbuf != NULL)
|
||||
log_verbose(LOG_DEBUG, "remote_command(): output returned was:\n %s", outputbuf->data);
|
||||
{
|
||||
if (strlen(outputbuf->data))
|
||||
log_verbose(LOG_DEBUG, "remote_command(): output returned was:\n%s", outputbuf->data);
|
||||
else
|
||||
log_verbose(LOG_DEBUG, "remote_command(): no output returned");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2448,18 +2613,15 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(
|
||||
&command,
|
||||
appendShellString(&command,
|
||||
data_dir);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
" start");
|
||||
|
||||
strncpy(script, command.data, MAXLEN);
|
||||
@@ -2471,6 +2633,7 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
}
|
||||
|
||||
case ACTION_STOP:
|
||||
case ACTION_STOP_WAIT:
|
||||
{
|
||||
if (config_file_options.service_stop_command[0] != '\0')
|
||||
{
|
||||
@@ -2480,19 +2643,23 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
"%s %s -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(
|
||||
&command,
|
||||
appendShellString(&command,
|
||||
data_dir);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
" -m fast -W stop");
|
||||
if (action == ACTION_STOP_WAIT)
|
||||
appendPQExpBuffer(&command,
|
||||
" -w");
|
||||
else
|
||||
appendPQExpBuffer(&command,
|
||||
" -W");
|
||||
|
||||
appendPQExpBuffer(&command,
|
||||
" -m fast stop");
|
||||
|
||||
strncpy(script, command.data, MAXLEN);
|
||||
|
||||
@@ -2511,18 +2678,15 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(
|
||||
&command,
|
||||
appendShellString(&command,
|
||||
data_dir);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
" restart");
|
||||
|
||||
strncpy(script, command.data, MAXLEN);
|
||||
@@ -2542,18 +2706,15 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(
|
||||
&command,
|
||||
appendShellString(&command,
|
||||
data_dir);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
" reload");
|
||||
|
||||
strncpy(script, command.data, MAXLEN);
|
||||
@@ -2574,18 +2735,15 @@ get_server_action(t_server_action action, char *script, char *data_dir)
|
||||
else
|
||||
{
|
||||
initPQExpBuffer(&command);
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
"%s %s -w -D ",
|
||||
make_pg_path("pg_ctl"),
|
||||
config_file_options.pg_ctl_options);
|
||||
|
||||
appendShellString(
|
||||
&command,
|
||||
appendShellString(&command,
|
||||
data_dir);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&command,
|
||||
appendPQExpBuffer(&command,
|
||||
" promote");
|
||||
|
||||
strncpy(script, command.data, MAXLEN);
|
||||
@@ -2619,6 +2777,7 @@ data_dir_required_for_action(t_server_action action)
|
||||
return true;
|
||||
|
||||
case ACTION_STOP:
|
||||
case ACTION_STOP_WAIT:
|
||||
if (config_file_options.service_stop_command[0] != '\0')
|
||||
{
|
||||
return false;
|
||||
@@ -2654,6 +2813,33 @@ data_dir_required_for_action(t_server_action action)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copy the location of the configuration file directory into the
|
||||
* provided buffer; if "config_directory" provided, use that, otherwise
|
||||
* default to the data directory.
|
||||
*
|
||||
* This is primarily intended for use with "pg_ctl" (which itself shouldn't
|
||||
* be used outside of development environments).
|
||||
*/
|
||||
void
|
||||
get_node_config_directory(char *config_dir_buf)
|
||||
{
|
||||
if (config_file_options.config_directory[0] != '\0')
|
||||
{
|
||||
strncpy(config_dir_buf, config_file_options.config_directory, MAXPGPATH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (config_file_options.data_directory[0] != '\0')
|
||||
{
|
||||
strncpy(config_dir_buf, config_file_options.data_directory, MAXPGPATH);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
get_node_data_directory(char *data_dir_buf)
|
||||
{
|
||||
@@ -2701,7 +2887,7 @@ init_node_record(t_node_info *node_record)
|
||||
|
||||
if (config_file_options.replication_user[0] != '\0')
|
||||
{
|
||||
/* replication user explicitly provided */
|
||||
/* replication user explicitly provided in configuration file */
|
||||
strncpy(node_record->repluser, config_file_options.replication_user, NAMEDATALEN);
|
||||
}
|
||||
else
|
||||
@@ -2715,6 +2901,80 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason)
|
||||
{
|
||||
bool can_use = true;
|
||||
int server_version_num = get_server_version(conn, NULL);
|
||||
|
||||
/* wal_log_hints not available in 9.3, so just determine if data checksums enabled */
|
||||
if (server_version_num < 90400)
|
||||
{
|
||||
int data_checksum_version = get_data_checksum_version(data_directory);
|
||||
|
||||
if (data_checksum_version < 0)
|
||||
{
|
||||
appendPQExpBuffer(reason,
|
||||
_("unable to determine data checksum version"));
|
||||
can_use = false;
|
||||
}
|
||||
else if (data_checksum_version == 0)
|
||||
{
|
||||
appendPQExpBuffer(reason,
|
||||
_("this cluster was initialised without data checksums"));
|
||||
can_use = false;
|
||||
}
|
||||
|
||||
return can_use;
|
||||
}
|
||||
|
||||
/* "full_page_writes" must be on in any case */
|
||||
if (guc_set(conn, "full_page_writes", "=", "off"))
|
||||
{
|
||||
if (can_use == false)
|
||||
appendPQExpBuffer(reason, "; ");
|
||||
|
||||
appendPQExpBuffer(reason,
|
||||
_("\"full_page_writes\" must be set to \"on\""));
|
||||
|
||||
can_use = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* "wal_log_hints" off - are data checksums available? Note: we're
|
||||
* checking the local pg_control file here as the value will be the same
|
||||
* throughout the cluster and saves a round-trip to the demotion
|
||||
* candidate.
|
||||
*/
|
||||
if (guc_set(conn, "wal_log_hints", "=", "on") == false)
|
||||
{
|
||||
int data_checksum_version = get_data_checksum_version(data_directory);
|
||||
|
||||
if (data_checksum_version < 0)
|
||||
{
|
||||
if (can_use == false)
|
||||
appendPQExpBuffer(reason, "; ");
|
||||
|
||||
appendPQExpBuffer(reason,
|
||||
_("\"wal_log_hints\" is set to \"off\" but unable to determine data checksum version"));
|
||||
can_use = false;
|
||||
}
|
||||
else if (data_checksum_version == 0)
|
||||
{
|
||||
if (can_use == false)
|
||||
appendPQExpBuffer(reason, "; ");
|
||||
|
||||
appendPQExpBuffer(reason,
|
||||
_("\"wal_log_hints\" is set to \"off\" and data checksums are disabled"));
|
||||
|
||||
can_use = false;
|
||||
}
|
||||
}
|
||||
|
||||
return can_use;
|
||||
}
|
||||
|
||||
@@ -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,14 @@
|
||||
#define OPT_DOWNSTREAM 1032
|
||||
#define OPT_SLOTS 1033
|
||||
#define OPT_CONFIG_ARCHIVE_DIR 1034
|
||||
#define OPT_HAS_PASSFILE 1035
|
||||
#define OPT_WAIT_START 1036
|
||||
#define OPT_REPL_CONN 1037
|
||||
#define OPT_REMOTE_NODE_ID 1038
|
||||
#define OPT_RECOVERY_CONF_ONLY 1039
|
||||
#define OPT_NO_WAIT 1040
|
||||
#define OPT_MISSING_SLOTS 1041
|
||||
|
||||
/* deprecated since 3.3 */
|
||||
#define OPT_DATA_DIR 999
|
||||
#define OPT_NO_CONNINFO_PASSWORD 998
|
||||
@@ -98,7 +106,8 @@ static struct option long_options[] =
|
||||
{"dry-run", no_argument, NULL, OPT_DRY_RUN},
|
||||
{"force", no_argument, NULL, 'F'},
|
||||
{"pg_bindir", required_argument, NULL, 'b'},
|
||||
{"wait", no_argument, NULL, 'W'},
|
||||
{"wait", no_argument, NULL, 'w'},
|
||||
{"no-wait", no_argument, NULL, 'W'},
|
||||
|
||||
/* connection options */
|
||||
{"dbname", required_argument, NULL, 'd'},
|
||||
@@ -112,10 +121,12 @@ static struct option long_options[] =
|
||||
{"pgdata", required_argument, NULL, 'D'},
|
||||
{"node-id", required_argument, NULL, OPT_NODE_ID},
|
||||
{"node-name", required_argument, NULL, OPT_NODE_NAME},
|
||||
{"remote-node-id", required_argument, NULL, OPT_REMOTE_NODE_ID},
|
||||
|
||||
/* logging options */
|
||||
{"log-level", required_argument, NULL, 'L'},
|
||||
{"log-to-file", no_argument, NULL, OPT_LOG_TO_FILE},
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"terse", no_argument, NULL, 't'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
|
||||
@@ -133,9 +144,11 @@ static struct option long_options[] =
|
||||
{"upstream-conninfo", required_argument, NULL, OPT_UPSTREAM_CONNINFO},
|
||||
{"upstream-node-id", required_argument, NULL, OPT_UPSTREAM_NODE_ID},
|
||||
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
|
||||
{"recovery-conf-only", no_argument, NULL, OPT_RECOVERY_CONF_ONLY},
|
||||
|
||||
/* "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,11 +166,14 @@ 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},
|
||||
{"missing-slots", no_argument, NULL, OPT_MISSING_SLOTS},
|
||||
{"has-passfile", no_argument, NULL, OPT_HAS_PASSFILE},
|
||||
{"replication-connection", no_argument, NULL, OPT_REPL_CONN},
|
||||
|
||||
/* "node rejoin" options */
|
||||
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},
|
||||
{"config-archive-dir", required_argument, NULL, OPT_CONFIG_ARCHIVE_DIR},
|
||||
{"force-rewind", no_argument, NULL, OPT_FORCE_REWIND},
|
||||
{"force-rewind", optional_argument, NULL, OPT_FORCE_REWIND},
|
||||
|
||||
/* "node service" options */
|
||||
{"action", required_argument, NULL, OPT_ACTION},
|
||||
|
||||
10
repmgr.c
10
repmgr.c
@@ -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
|
||||
@@ -288,7 +288,6 @@ standby_get_last_updated(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#ifndef BDR_ONLY
|
||||
int primary_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
if (!shared_state)
|
||||
@@ -316,7 +315,7 @@ notify_follow_primary(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
LWLockRelease(shared_state->lock);
|
||||
#endif
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
@@ -329,14 +328,12 @@ get_new_primary(PG_FUNCTION_ARGS)
|
||||
if (!shared_state)
|
||||
PG_RETURN_NULL();
|
||||
|
||||
#ifndef BDR_ONLY
|
||||
LWLockAcquire(shared_state->lock, LW_SHARED);
|
||||
|
||||
if (shared_state->follow_new_primary == true)
|
||||
new_primary_node_id = shared_state->candidate_node_id;
|
||||
|
||||
LWLockRelease(shared_state->lock);
|
||||
#endif
|
||||
|
||||
if (new_primary_node_id == UNKNOWN_NODE_ID)
|
||||
PG_RETURN_NULL();
|
||||
@@ -348,7 +345,6 @@ get_new_primary(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
reset_voting_status(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#ifndef BDR_ONLY
|
||||
if (!shared_state)
|
||||
PG_RETURN_NULL();
|
||||
|
||||
@@ -366,7 +362,7 @@ reset_voting_status(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
LWLockRelease(shared_state->lock);
|
||||
#endif
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,67 +13,74 @@
|
||||
# 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".
|
||||
|
||||
# =============================================================================
|
||||
|
||||
# Optional configuration items
|
||||
# =============================================================================
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Server settings
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#config_directory='' # If configuration files are located outside the data
|
||||
# directory, specify the directory where the main
|
||||
# postgresql.conf file is located.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Replication settings
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#replication_type=physical # Must be one of 'physical' or 'bdr'.
|
||||
#replication_user='repmgr' # User to make replication connections with, if not set defaults
|
||||
# to the user defined in "conninfo".
|
||||
|
||||
#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.
|
||||
#replication_type=physical # Must be one of 'physical' or 'bdr'.
|
||||
|
||||
#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.
|
||||
#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.
|
||||
|
||||
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" in recovery.conf
|
||||
# will be set to this value.
|
||||
#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.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# 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 +92,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 +125,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,16 +160,15 @@
|
||||
# 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"
|
||||
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Standby clone settings
|
||||
# "standby clone" settings
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# These settings apply when cloning a standby ("repmgr standby clone").
|
||||
@@ -172,33 +178,78 @@ 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.
|
||||
|
||||
#archive_cleanup_command='' # This will be placed in the recovery.conf file generated
|
||||
# by repmgr. Note we recommend using Barman for managing
|
||||
# WAL archives (see: https://www.pgbarman.org )
|
||||
|
||||
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" in recovery.conf
|
||||
# will be set to this value (PostgreSQL 9.4 and later).
|
||||
|
||||
#restore_command='' # This will be placed in the recovery.conf
|
||||
# file generated by repmgr
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Standby follow settings
|
||||
# "standby promote" settings
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# These settings apply when instructing a standby to promote itself to the
|
||||
# new primary ("repmgr standby promote").
|
||||
|
||||
#promote_check_timeout=60 # The length of time (in seconds) to wait
|
||||
# for the new primary to finish promoting
|
||||
#promote_check_interval=1 # The interval (in seconds) to check whether
|
||||
# the new primary has finished promoting
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# "standby follow" settings
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# 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 max length of time (in seconds) to wait
|
||||
# for the new primary to become available
|
||||
#standby_follow_timeout=15 # The max length of time (in seconds) to wait
|
||||
# for the standby to connect to the primary
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# "standby switchover" settings
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# These settings apply when switching roles between a primary and a standby
|
||||
# ("repmgr standby switchover").
|
||||
|
||||
#standby_reconnect_timeout=60 # The max length of time (in seconds) to wait
|
||||
# for the demoted standby to reconnect to the promoted
|
||||
# primary (note: this value should be equal to or greater
|
||||
# than that set for "node_rejoin_timeout")
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# "node rejoin" settings
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# These settings apply when reintegrating a node into a replication cluster
|
||||
# with "repmgrd_node_rejoin"
|
||||
|
||||
#node_rejoin_timeout=60 # The maximum length of time (in seconds) to wait for
|
||||
# the node to reconnect to the replication cluster
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# 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 +258,51 @@ 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)
|
||||
#repmgrd_pid_file= # Path of PID file to use for repmgrd; if not set, a PID file will
|
||||
# be generated in a temporary directory specified by the environment
|
||||
# variable $TMPDIR, or if not set, in "/tmp". This value can be overridden
|
||||
# by the command line option "-p/--pid-file"; the command line option
|
||||
# "--no-pid-file" will force PID file creation to be skipped.
|
||||
#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 priority 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
|
||||
#monitoring_history=no
|
||||
#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 repmgrd executes when promoting a new primary; use something like:
|
||||
#
|
||||
# repmgr standby promote -f /etc/repmgr.conf
|
||||
#
|
||||
#follow_command= # command repmgrd executes 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
|
||||
#repmgrd_standby_startup_timeout=60 # Interval (in seconds) which repmgrd on a standby will wait
|
||||
# for the the local node to restart and become ready to accept connections after
|
||||
# executing "follow_command" (defaults to the value set in "standby_reconnect_timeout")
|
||||
|
||||
#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.
|
||||
#monitoring_history=no # Whether to write monitoring data to the "montoring_history" table
|
||||
#monitor_interval_secs=2 # Interval (in seconds) at which to write monitoring data
|
||||
#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
|
||||
@@ -270,16 +330,19 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# /usr/bin/systemctl start postgresql-9.6, \
|
||||
# /usr/bin/systemctl restart postgresql-9.6
|
||||
#
|
||||
# Debian/Ubuntu users: use "sudo pg_ctlcluster" to execute service control commands.
|
||||
#
|
||||
# For more details, see: https://repmgr.org/docs/4.0/configuration-service-commands.html
|
||||
|
||||
#service_start_command = ''
|
||||
#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 = '' # This parameter is intended for systems which provide a
|
||||
# package-level promote command, such as Debian's
|
||||
# "pg_ctlcluster". *IMPORTANT*: it is *not* a substitute
|
||||
# for "promote_command"; do not use "repmgr standby promote"
|
||||
# (or a script which executes "repmgr standby promote") here.
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Status check thresholds
|
||||
@@ -287,25 +350,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.
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# repmgr extension
|
||||
comment = 'Replication manager for PostgreSQL'
|
||||
default_version = '4.0'
|
||||
default_version = '4.1'
|
||||
module_pathname = '$libdir/repmgr'
|
||||
relocatable = false
|
||||
schema = repmgr
|
||||
|
||||
13
repmgr.h
13
repmgr.h
@@ -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
|
||||
@@ -49,6 +49,8 @@
|
||||
#define REPLICATION_TYPE_BDR 2
|
||||
|
||||
#define UNKNOWN_SERVER_VERSION_NUM -1
|
||||
#define UNKNOWN_BDR_VERSION_NUM -1
|
||||
|
||||
#define UNKNOWN_TIMELINE_ID -1
|
||||
#define UNKNOWN_SYSTEM_IDENTIFIER 0
|
||||
|
||||
@@ -56,6 +58,9 @@
|
||||
#define NO_UPSTREAM_NODE -1
|
||||
#define UNKNOWN_NODE_ID -1
|
||||
|
||||
#define VOTING_TERM_NOT_SET -1
|
||||
|
||||
#define BDR2_REPLICATION_SET_NAME "repmgr"
|
||||
|
||||
/*
|
||||
* various default values - ensure repmgr.conf.sample is update
|
||||
@@ -69,12 +74,18 @@
|
||||
#define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_PRIMARY_FOLLOW_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */
|
||||
#define DEFAULT_BDR_RECOVERY_TIMEOUT 30 /* seconds */
|
||||
#define DEFAULT_ARCHIVE_READY_WARNING 16 /* WAL files */
|
||||
#define DEFAULT_ARCHIVE_READY_CRITICAL 128 /* WAL files */
|
||||
#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 */
|
||||
#define DEFAULT_PROMOTE_CHECK_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_PROMOTE_CHECK_INTERVAL 1 /* seconds */
|
||||
#define DEFAULT_STANDBY_RECONNECT_TIMEOUT 60 /* seconds */
|
||||
#define DEFAULT_NODE_REJOIN_TIMEOUT 60 /* seconds */
|
||||
|
||||
#ifndef RECOVERY_COMMAND_FILE
|
||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
#define REPMGR_VERSION_DATE ""
|
||||
#define REPMGR_VERSION "4.0.0"
|
||||
|
||||
#define REPMGR_VERSION "4.1.0"
|
||||
|
||||
@@ -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
|
||||
@@ -35,6 +35,29 @@ do_bdr_node_check(void)
|
||||
/* nothing to do at the moment */
|
||||
}
|
||||
|
||||
void
|
||||
handle_sigint_bdr(SIGNAL_ARGS)
|
||||
{
|
||||
PQExpBufferData event_details;
|
||||
|
||||
initPQExpBuffer(&event_details);
|
||||
|
||||
appendPQExpBuffer(&event_details,
|
||||
"%s signal received",
|
||||
postgres_signal_arg == SIGTERM
|
||||
? "TERM" : "INT");
|
||||
|
||||
create_event_notification(local_conn,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
"repmgrd_shutdown",
|
||||
true,
|
||||
event_details.data);
|
||||
termPQExpBuffer(&event_details);
|
||||
|
||||
terminate(SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
monitor_bdr(void)
|
||||
@@ -98,23 +121,6 @@ monitor_bdr(void)
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* Retrieve record for this node from the local database */
|
||||
record_status = get_node_record(local_conn, config_file_options.node_id, &local_node_info);
|
||||
|
||||
/*
|
||||
* Terminate if we can't find the local node record. This is a
|
||||
* "fix-the-config" situation, not a lot else we can do.
|
||||
*/
|
||||
if (record_status != RECORD_FOUND)
|
||||
{
|
||||
log_error(_("unable to retrieve record for local node (ID: %i), terminating"),
|
||||
local_node_info.node_id);
|
||||
log_hint(_("check that \"repmgr bdr register\" was executed for this node"));
|
||||
PQfinish(local_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
|
||||
if (local_node_info.active == false)
|
||||
{
|
||||
log_error(_("local node (ID: %i) is marked as inactive in repmgr"),
|
||||
@@ -124,9 +130,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);
|
||||
@@ -152,15 +158,16 @@ monitor_bdr(void)
|
||||
cell->node_info->node_status = NODE_STATUS_UP;
|
||||
}
|
||||
|
||||
log_debug("main_loop_bdr() monitoring local node %i", config_file_options.node_id);
|
||||
log_info(_("starting continuous BDR node monitoring on node %i"),
|
||||
config_file_options.node_id);
|
||||
|
||||
log_info(_("starting continuous BDR node monitoring"));
|
||||
INSTR_TIME_SET_CURRENT(log_status_interval_start);
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
||||
/* monitoring loop */
|
||||
log_verbose(LOG_DEBUG, "BDR check loop...");
|
||||
log_verbose(LOG_DEBUG, "BDR check loop - checking %i nodes", nodes.node_count);
|
||||
|
||||
for (cell = nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
@@ -262,7 +269,6 @@ loop:
|
||||
if (config_file_options.log_status_interval > 0)
|
||||
{
|
||||
int log_status_interval_elapsed = calculate_elapsed(log_status_interval_start);
|
||||
|
||||
if (log_status_interval_elapsed >= config_file_options.log_status_interval)
|
||||
{
|
||||
log_info(_("monitoring BDR replication status on node \"%s\" (ID: %i)"),
|
||||
@@ -273,8 +279,7 @@ loop:
|
||||
{
|
||||
if (cell->node_info->monitoring_state == MS_DEGRADED)
|
||||
{
|
||||
log_detail(
|
||||
_("monitoring node \"%s\" (ID: %i) in degraded mode"),
|
||||
log_detail(_("monitoring node \"%s\" (ID: %i) in degraded mode"),
|
||||
cell->node_info->node_name,
|
||||
cell->node_info->node_id);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -22,4 +22,5 @@
|
||||
extern void do_bdr_node_check(void);
|
||||
extern void monitor_bdr(void);
|
||||
|
||||
extern void handle_sigint_bdr(SIGNAL_ARGS);
|
||||
#endif /* _REPMGRD_BDR_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -24,6 +24,7 @@ void do_physical_node_check(void);
|
||||
void monitor_streaming_primary(void);
|
||||
void monitor_streaming_standby(void);
|
||||
void monitor_streaming_witness(void);
|
||||
void close_connections_physical(void);
|
||||
|
||||
void handle_sigint_physical(SIGNAL_ARGS);
|
||||
|
||||
#endif /* _REPMGRD_PHYSICAL_H_ */
|
||||
|
||||
232
repmgrd.c
232
repmgrd.c
@@ -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
|
||||
@@ -35,8 +35,10 @@
|
||||
|
||||
static char *config_file = NULL;
|
||||
static bool verbose = false;
|
||||
static char *pid_file = NULL;
|
||||
static bool daemonize = false;
|
||||
static char pid_file[MAXPGPATH];
|
||||
static bool daemonize = true;
|
||||
static bool show_pid_file = false;
|
||||
static bool no_pid_file = false;
|
||||
|
||||
t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER;
|
||||
|
||||
@@ -53,9 +55,6 @@ bool startup_event_logged = false;
|
||||
MonitoringState monitoring_state = MS_NORMAL;
|
||||
instr_time degraded_monitoring_start;
|
||||
|
||||
static void close_connections(void);
|
||||
void (*_close_connections) (void) = NULL;
|
||||
|
||||
/*
|
||||
* Record receipt of SIGHUP; will cause configuration file to be reread
|
||||
* at the appropriate point in the main loop.
|
||||
@@ -73,7 +72,6 @@ static void start_monitoring(void);
|
||||
#ifndef WIN32
|
||||
static void setup_event_handlers(void);
|
||||
static void handle_sighup(SIGNAL_ARGS);
|
||||
static void handle_sigint(SIGNAL_ARGS);
|
||||
#endif
|
||||
|
||||
int calculate_elapsed(instr_time start_time);
|
||||
@@ -89,6 +87,7 @@ main(int argc, char **argv)
|
||||
bool cli_monitoring_history = false;
|
||||
|
||||
RecordStatus record_status;
|
||||
ExtensionStatus extension_status = REPMGR_UNKNOWN;
|
||||
|
||||
FILE *fd;
|
||||
|
||||
@@ -102,8 +101,10 @@ main(int argc, char **argv)
|
||||
{"config-file", required_argument, NULL, 'f'},
|
||||
|
||||
/* daemon options */
|
||||
{"daemonize", no_argument, NULL, 'd'},
|
||||
{"daemonize", optional_argument, NULL, 'd'},
|
||||
{"pid-file", required_argument, NULL, 'p'},
|
||||
{"show-pid-file", no_argument, NULL, 's'},
|
||||
{"no-pid-file", no_argument, NULL, OPT_NO_PID_FILE},
|
||||
|
||||
/* logging options */
|
||||
{"log-level", required_argument, NULL, 'L'},
|
||||
@@ -116,8 +117,6 @@ main(int argc, char **argv)
|
||||
|
||||
set_progname(argv[0]);
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
/* Disallow running as root */
|
||||
if (geteuid() == 0)
|
||||
{
|
||||
@@ -131,6 +130,10 @@ main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
memset(pid_file, 0, MAXPGPATH);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "?Vf:L:vdp:m", long_options, &optindex)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -172,11 +175,22 @@ main(int argc, char **argv)
|
||||
/* daemon options */
|
||||
|
||||
case 'd':
|
||||
daemonize = true;
|
||||
if (optarg != NULL)
|
||||
{
|
||||
daemonize = parse_bool(optarg, "-d/--daemonize", &cli_errors);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pid_file = optarg;
|
||||
strncpy(pid_file, optarg, MAXPGPATH);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
show_pid_file = true;
|
||||
break;
|
||||
|
||||
case OPT_NO_PID_FILE:
|
||||
no_pid_file = true;
|
||||
break;
|
||||
|
||||
/* logging options */
|
||||
@@ -223,7 +237,7 @@ main(int argc, char **argv)
|
||||
/* Exit here already if errors in command line options found */
|
||||
if (cli_errors.head != NULL)
|
||||
{
|
||||
exit_with_cli_errors(&cli_errors);
|
||||
exit_with_cli_errors(&cli_errors, NULL);
|
||||
}
|
||||
|
||||
startup_event_logged = false;
|
||||
@@ -242,6 +256,58 @@ main(int argc, char **argv)
|
||||
*/
|
||||
load_config(config_file, verbose, false, &config_file_options, argv[0]);
|
||||
|
||||
/* Determine pid file location, unless --no-pid-file supplied */
|
||||
|
||||
if (no_pid_file == false)
|
||||
{
|
||||
if (config_file_options.repmgrd_pid_file[0] != '\0')
|
||||
{
|
||||
if (pid_file[0] != '\0')
|
||||
{
|
||||
log_warning(_("\"repmgrd_pid_file\" will be overridden by --pid-file"));
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(pid_file, config_file_options.repmgrd_pid_file, MAXPGPATH);
|
||||
}
|
||||
}
|
||||
|
||||
/* no pid file provided - determine location */
|
||||
if (pid_file[0] == '\0')
|
||||
{
|
||||
/* packagers: if feasible, patch PID file path into "package_pid_file" */
|
||||
char package_pid_file[MAXPGPATH] = "";
|
||||
|
||||
if (package_pid_file[0] != '\0')
|
||||
{
|
||||
maxpath_snprintf(pid_file, "%s", package_pid_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *tmpdir = getenv("TMPDIR");
|
||||
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
|
||||
maxpath_snprintf(pid_file, "%s/repmgrd.pid", tmpdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* --no-pid-file supplied - overwrite any value provided with --pid-file ... */
|
||||
memset(pid_file, 0, MAXPGPATH);
|
||||
}
|
||||
|
||||
|
||||
/* If --show-pid-file supplied, output the location (if set) and exit */
|
||||
|
||||
if (show_pid_file == true)
|
||||
{
|
||||
printf("%s\n", pid_file);
|
||||
exit(SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/* Some configuration file items can be overriden by command line options */
|
||||
|
||||
@@ -254,6 +320,8 @@ main(int argc, char **argv)
|
||||
strncpy(config_file_options.log_level, cli_log_level, MAXLEN);
|
||||
}
|
||||
|
||||
log_notice(_("repmgrd (repmgr %s) starting up"), REPMGR_VERSION);
|
||||
|
||||
/*
|
||||
* -m/--monitoring-history, if provided, will override repmgr.conf's
|
||||
* monitoring_history; this is for backwards compatibility as it's
|
||||
@@ -318,15 +386,60 @@ main(int argc, char **argv)
|
||||
* repmgr has not been properly configured.
|
||||
*/
|
||||
|
||||
/* Check "repmgr" the extension is installed */
|
||||
extension_status = get_repmgr_extension_status(local_conn);
|
||||
|
||||
if (extension_status != REPMGR_INSTALLED)
|
||||
{
|
||||
/* this is unlikely to happen */
|
||||
if (extension_status == REPMGR_UNKNOWN)
|
||||
{
|
||||
log_error(_("unable to determine status of \"repmgr\" extension"));
|
||||
log_detail("%s", PQerrorMessage(local_conn));
|
||||
close_connection(&local_conn);
|
||||
exit(ERR_DB_QUERY);
|
||||
}
|
||||
|
||||
log_error(_("repmgr extension not found on this node"));
|
||||
|
||||
if (extension_status == REPMGR_AVAILABLE)
|
||||
{
|
||||
log_detail(_("repmgr extension is available but not installed in database \"%s\""),
|
||||
PQdb(local_conn));
|
||||
}
|
||||
else if (extension_status == REPMGR_UNAVAILABLE)
|
||||
{
|
||||
log_detail(_("repmgr extension is not available on this node"));
|
||||
}
|
||||
|
||||
log_hint(_("check that this node is part of a repmgr cluster"));
|
||||
close_connection(&local_conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* Retrieve record for this node from the local database */
|
||||
record_status = get_node_record(local_conn, config_file_options.node_id, &local_node_info);
|
||||
|
||||
/*
|
||||
* Terminate if we can't find the local node record. This is a
|
||||
* "fix-the-config" situation, not a lot else we can do.
|
||||
*/
|
||||
|
||||
if (record_status != RECORD_FOUND)
|
||||
{
|
||||
log_error(_("no metadata record found for this node - terminating"));
|
||||
log_hint(_("check that 'repmgr (primary|standby) register' was executed for this node"));
|
||||
|
||||
PQfinish(local_conn);
|
||||
switch (config_file_options.replication_type)
|
||||
{
|
||||
case REPLICATION_TYPE_PHYSICAL:
|
||||
log_hint(_("check that 'repmgr (primary|standby) register' was executed for this node"));
|
||||
break;
|
||||
case REPLICATION_TYPE_BDR:
|
||||
log_hint(_("check that 'repmgr bdr register' was executed for this node"));
|
||||
break;
|
||||
}
|
||||
|
||||
close_connection(&local_conn);
|
||||
terminate(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
@@ -345,7 +458,7 @@ main(int argc, char **argv)
|
||||
{
|
||||
log_error(_("unable to write to shared memory"));
|
||||
log_hint(_("ensure \"shared_preload_libraries\" includes \"repmgr\""));
|
||||
PQfinish(local_conn);
|
||||
close_connection(&local_conn);
|
||||
terminate(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
@@ -357,7 +470,6 @@ main(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
_close_connections = close_connections_physical;
|
||||
log_debug("node id is %i, upstream node id is %i",
|
||||
local_node_info.node_id,
|
||||
local_node_info.upstream_node_id);
|
||||
@@ -371,7 +483,7 @@ main(int argc, char **argv)
|
||||
daemonize_process();
|
||||
}
|
||||
|
||||
if (pid_file != NULL)
|
||||
if (pid_file[0] != '\0')
|
||||
{
|
||||
check_and_create_pid_file(pid_file);
|
||||
}
|
||||
@@ -400,7 +512,6 @@ start_monitoring(void)
|
||||
{
|
||||
switch (local_node_info.type)
|
||||
{
|
||||
#ifndef BDR_ONLY
|
||||
case PRIMARY:
|
||||
monitor_streaming_primary();
|
||||
break;
|
||||
@@ -410,11 +521,6 @@ start_monitoring(void)
|
||||
case WITNESS:
|
||||
monitor_streaming_witness();
|
||||
break;
|
||||
#else
|
||||
case PRIMARY:
|
||||
case STANDBY:
|
||||
return;
|
||||
#endif
|
||||
case BDR:
|
||||
monitor_bdr();
|
||||
return;
|
||||
@@ -587,11 +693,6 @@ check_and_create_pid_file(const char *pid_file)
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
static void
|
||||
handle_sigint(SIGNAL_ARGS)
|
||||
{
|
||||
terminate(SUCCESS);
|
||||
}
|
||||
|
||||
/* SIGHUP: set flag to re-read config file at next convenient time */
|
||||
static void
|
||||
@@ -604,8 +705,23 @@ static void
|
||||
setup_event_handlers(void)
|
||||
{
|
||||
pqsignal(SIGHUP, handle_sighup);
|
||||
pqsignal(SIGINT, handle_sigint);
|
||||
pqsignal(SIGTERM, handle_sigint);
|
||||
|
||||
/*
|
||||
* we want to be able to write a "repmgrd_shutdown" event, so delegate
|
||||
* signal handling to the respective replication type handler, as it
|
||||
* will know best which database connection to use
|
||||
*/
|
||||
switch (config_file_options.replication_type)
|
||||
{
|
||||
case REPLICATION_TYPE_BDR:
|
||||
pqsignal(SIGINT, handle_sigint_bdr);
|
||||
pqsignal(SIGTERM, handle_sigint_bdr);
|
||||
break;
|
||||
case REPLICATION_TYPE_PHYSICAL:
|
||||
pqsignal(SIGINT, handle_sigint_physical);
|
||||
pqsignal(SIGTERM, handle_sigint_physical);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -622,6 +738,8 @@ show_help(void)
|
||||
{
|
||||
printf(_("%s: replication management daemon for PostgreSQL\n"), progname());
|
||||
puts("");
|
||||
printf(_("%s monitors a cluster of servers and optionally performs failover.\n"), progname());
|
||||
puts("");
|
||||
|
||||
printf(_("Usage:\n"));
|
||||
printf(_(" %s [OPTIONS]\n"), progname());
|
||||
@@ -641,12 +759,14 @@ show_help(void)
|
||||
|
||||
puts("");
|
||||
|
||||
printf(_("General configuration options:\n"));
|
||||
printf(_(" -d, --daemonize detach process from foreground\n"));
|
||||
printf(_(" -p, --pid-file=PATH write a PID file\n"));
|
||||
printf(_("Daemon configuration options:\n"));
|
||||
printf(_(" -d, --daemonize[=true/false]\n"));
|
||||
printf(_(" detach process from foreground (default: true)\n"));
|
||||
printf(_(" -p, --pid-file=PATH use the specified PID file\n"));
|
||||
printf(_(" -s, --show-pid-file show PID file which would be used by the current configuration\n"));
|
||||
printf(_(" --no-pid-file don't write a PID file\n"));
|
||||
puts("");
|
||||
|
||||
printf(_("%s monitors a cluster of servers and optionally performs failover.\n"), progname());
|
||||
}
|
||||
|
||||
|
||||
@@ -654,17 +774,29 @@ PGconn *
|
||||
try_reconnect(t_node_info *node_info)
|
||||
{
|
||||
PGconn *conn;
|
||||
t_conninfo_param_list conninfo_params = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||
|
||||
int i;
|
||||
|
||||
int max_attempts = config_file_options.reconnect_attempts;
|
||||
|
||||
initialize_conninfo_params(&conninfo_params, false);
|
||||
|
||||
|
||||
/* we assume by now the conninfo string is parseable */
|
||||
(void) parse_conninfo_string(node_info->conninfo, &conninfo_params, NULL, false);
|
||||
|
||||
/* set some default values if not explicitly provided */
|
||||
param_set_ine(&conninfo_params, "connect_timeout", "2");
|
||||
param_set_ine(&conninfo_params, "fallback_application_name", "repmgr");
|
||||
|
||||
for (i = 0; i < max_attempts; i++)
|
||||
{
|
||||
log_info(_("checking state of node %i, %i of %i attempts"),
|
||||
node_info->node_id, i + 1, max_attempts);
|
||||
if (is_server_available(node_info->conninfo) == true)
|
||||
if (is_server_available_params(&conninfo_params) == true)
|
||||
{
|
||||
|
||||
log_notice(_("node has recovered, reconnecting"));
|
||||
|
||||
/*
|
||||
@@ -672,14 +804,18 @@ try_reconnect(t_node_info *node_info)
|
||||
* connection denied due to connection exhaustion - fall back to
|
||||
* degraded monitoring? - make that configurable
|
||||
*/
|
||||
conn = establish_db_connection(node_info->conninfo, false);
|
||||
|
||||
conn = establish_db_connection_by_params(&conninfo_params, false);
|
||||
|
||||
if (PQstatus(conn) == CONNECTION_OK)
|
||||
{
|
||||
free_conninfo_params(&conninfo_params);
|
||||
|
||||
node_info->node_status = NODE_STATUS_UP;
|
||||
return conn;
|
||||
}
|
||||
|
||||
PQfinish(conn);
|
||||
close_connection(&conn);
|
||||
log_notice(_("unable to reconnect to node"));
|
||||
}
|
||||
|
||||
@@ -691,13 +827,14 @@ try_reconnect(t_node_info *node_info)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log_warning(_("unable to reconnect to node %i after %i attempts"),
|
||||
node_info->node_id,
|
||||
max_attempts);
|
||||
|
||||
node_info->node_status = NODE_STATUS_DOWN;
|
||||
|
||||
free_conninfo_params(&conninfo_params);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -733,27 +870,12 @@ print_monitoring_state(MonitoringState monitoring_state)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
close_connections()
|
||||
{
|
||||
if (_close_connections != NULL)
|
||||
_close_connections();
|
||||
|
||||
if (local_conn != NULL && PQstatus(local_conn) == CONNECTION_OK)
|
||||
{
|
||||
PQfinish(local_conn);
|
||||
local_conn = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
terminate(int retval)
|
||||
{
|
||||
close_connections();
|
||||
logger_shutdown();
|
||||
|
||||
if (pid_file)
|
||||
if (pid_file[0] != '\0')
|
||||
{
|
||||
unlink(pid_file);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* repmgrd.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||
* Copyright (c) 2ndQuadrant, 2010-2018
|
||||
*/
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <time.h>
|
||||
#include "portability/instr_time.h"
|
||||
|
||||
#define OPT_NO_PID_FILE 1000
|
||||
|
||||
extern volatile sig_atomic_t got_SIGHUP;
|
||||
extern MonitoringState monitoring_state;
|
||||
extern instr_time degraded_monitoring_start;
|
||||
@@ -26,4 +28,6 @@ const char *print_monitoring_state(MonitoringState monitoring_state);
|
||||
|
||||
void update_registration(PGconn *conn);
|
||||
void terminate(int retval);
|
||||
|
||||
|
||||
#endif /* _REPMGRD_H_ */
|
||||
|
||||
@@ -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
|
||||
|
||||
15
strutil.h
15
strutil.h
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user