mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-25 16:16:29 +00:00
Merge remote-tracking branch 'origin/master' into heroku
The Great Whitespace Reconciliation Conflicts: check_dir.c config.c dbutils.c repmgr.c repmgr.h repmgrd.c Signed-off-by: Dan Farina <drfarina@acm.org>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -0,0 +1,4 @@
|
|||||||
|
*~
|
||||||
|
*.o
|
||||||
|
repmgr
|
||||||
|
repmgrd
|
||||||
|
|||||||
7
CREDITS
Normal file
7
CREDITS
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Code and documentation contributors to repmgr include:
|
||||||
|
|
||||||
|
Jaime Casanova <jaime@2ndQuadrant.com>
|
||||||
|
Simon Riggs <simon@2ndQuadrant.com>
|
||||||
|
Greg Smith <greg@2ndQuadrant.com>
|
||||||
|
Robert J. Noles <rj@2ndQuadrant.com>
|
||||||
|
Gabriele Bartolini <gabriele@2ndQuadrant.com>
|
||||||
3
HISTORY
Normal file
3
HISTORY
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
1.0.0 2010-12-05 First public release
|
||||||
|
|
||||||
|
1.0.1 2010-12-XX Fix missing "--force" option in help
|
||||||
15
README.rst
15
README.rst
@@ -212,6 +212,8 @@ If you give a password to the user, you need to create a ``.pgpass`` file for
|
|||||||
them as well to allow automatic login. In this case you might use the
|
them as well to allow automatic login. In this case you might use the
|
||||||
``md5`` authentication method instead of ``trust`` for the repmgr user.
|
``md5`` authentication method instead of ``trust`` for the repmgr user.
|
||||||
|
|
||||||
|
Don't forget to restart the database server after making all these changes.
|
||||||
|
|
||||||
Configuration File
|
Configuration File
|
||||||
==================
|
==================
|
||||||
|
|
||||||
@@ -627,3 +629,16 @@ and on “prime."
|
|||||||
|
|
||||||
The servers are now again acting as primary on “prime" and standby on “standby".
|
The servers are now again acting as primary on “prime" and standby on “standby".
|
||||||
|
|
||||||
|
License and Contributions
|
||||||
|
=========================
|
||||||
|
|
||||||
|
repmgr is licensed under the GPL v3. All of its code and documentation is
|
||||||
|
Copyright 2010, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for
|
||||||
|
details.
|
||||||
|
|
||||||
|
Contributions to repmgr are welcome, and listed in the file CREDITS.
|
||||||
|
2ndQuadrant Limited requires that any contributions provide a copyright
|
||||||
|
assignment and a disclaimer of any work-for-hire ownership claims from the
|
||||||
|
employer of the developer. This lets us make sure that all of the repmgr
|
||||||
|
distribution remains free code. Please contact info@2ndQuadrant.com for a
|
||||||
|
copy of the relevant Copyright Assignment Form.
|
||||||
|
|||||||
41
check_dir.c
41
check_dir.c
@@ -1,10 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* check_dir.c
|
* check_dir.c - Directories management functions
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (C) 2ndQuadrant, 2010
|
||||||
* Copyright (c) Heroku, 2010
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Directories management functions
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -36,9 +47,9 @@ static int mkdir_p(char *path, mode_t omode);
|
|||||||
int
|
int
|
||||||
check_dir(char *dir)
|
check_dir(char *dir)
|
||||||
{
|
{
|
||||||
DIR *chkdir;
|
DIR *chkdir;
|
||||||
struct dirent *file;
|
struct dirent *file;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
@@ -50,7 +61,7 @@ check_dir(char *dir)
|
|||||||
while ((file = readdir(chkdir)) != NULL)
|
while ((file = readdir(chkdir)) != NULL)
|
||||||
{
|
{
|
||||||
if (strcmp(".", file->d_name) == 0 ||
|
if (strcmp(".", file->d_name) == 0 ||
|
||||||
strcmp("..", file->d_name) == 0)
|
strcmp("..", file->d_name) == 0)
|
||||||
{
|
{
|
||||||
/* skip this and parent directory */
|
/* skip this and parent directory */
|
||||||
continue;
|
continue;
|
||||||
@@ -74,7 +85,7 @@ check_dir(char *dir)
|
|||||||
closedir(chkdir);
|
closedir(chkdir);
|
||||||
|
|
||||||
if (errno != 0)
|
if (errno != 0)
|
||||||
return -1; /* some kind of I/O error? */
|
return -1; /* some kind of I/O error? */
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -90,7 +101,7 @@ create_directory(char *dir)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
fprintf(stderr, _("Could not create directory \"%s\": %s\n"),
|
fprintf(stderr, _("Could not create directory \"%s\": %s\n"),
|
||||||
dir, strerror(errno));
|
dir, strerror(errno));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -119,10 +130,10 @@ mkdir_p(char *path, mode_t omode)
|
|||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
mode_t numask,
|
mode_t numask,
|
||||||
oumask;
|
oumask;
|
||||||
int first,
|
int first,
|
||||||
last,
|
last,
|
||||||
retval;
|
retval;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
p = path;
|
p = path;
|
||||||
@@ -141,8 +152,8 @@ mkdir_p(char *path, mode_t omode)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (p[1] == ':' &&
|
else if (p[1] == ':' &&
|
||||||
((p[0] >= 'a' && p[0] <= 'z') ||
|
((p[0] >= 'a' && p[0] <= 'z') ||
|
||||||
(p[0] >= 'A' && p[0] <= 'Z')))
|
(p[0] >= 'A' && p[0] <= 'Z')))
|
||||||
{
|
{
|
||||||
/* local drive */
|
/* local drive */
|
||||||
p += 2;
|
p += 2;
|
||||||
|
|||||||
13
check_dir.h
13
check_dir.h
@@ -2,6 +2,19 @@
|
|||||||
* check_dir.h
|
* check_dir.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
*
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int check_dir(char *dir);
|
int check_dir(char *dir);
|
||||||
|
|||||||
18
config.c
18
config.c
@@ -1,10 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* config.c
|
* config.c - Functions to parse the config file
|
||||||
|
* Copyright (C) 2ndQuadrant, 2010
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* Copyright (c) Heroku, 2010
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Functions to parse the config file
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
|
|||||||
13
config.h
13
config.h
@@ -2,6 +2,19 @@
|
|||||||
* config.h
|
* config.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
*
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void parse_config(const char *config_file, char *cluster_name, int *node,
|
void parse_config(const char *config_file, char *cluster_name, int *node,
|
||||||
|
|||||||
23
dbutils.c
23
dbutils.c
@@ -1,10 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
* dbutils.c
|
* dbutils.c - Database connection/management functions
|
||||||
|
* Copyright (C) 2ndQuadrant, 2010
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* Copyright (c) Heroku, 2010
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Database connection/management functions
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -113,8 +122,8 @@ guc_setted(PGconn *conn, const char *parameter, const char *op,
|
|||||||
char sqlquery[QUERY_STR_LEN];
|
char sqlquery[QUERY_STR_LEN];
|
||||||
|
|
||||||
sqlquery_snprintf(sqlquery, "SELECT true FROM pg_settings "
|
sqlquery_snprintf(sqlquery, "SELECT true FROM pg_settings "
|
||||||
" WHERE name = '%s' AND setting %s '%s'",
|
" WHERE name = '%s' AND setting %s '%s'",
|
||||||
parameter, op, value);
|
parameter, op, value);
|
||||||
|
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
@@ -190,7 +199,7 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster,
|
|||||||
/* find all nodes belonging to this cluster */
|
/* find all nodes belonging to this cluster */
|
||||||
sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
||||||
" WHERE cluster = '%s' and id <> %d",
|
" WHERE cluster = '%s' and id <> %d",
|
||||||
cluster, cluster, id);
|
cluster, cluster, id);
|
||||||
|
|
||||||
res1 = PQexec(standby_conn, sqlquery);
|
res1 = PQexec(standby_conn, sqlquery);
|
||||||
if (PQresultStatus(res1) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res1) != PGRES_TUPLES_OK)
|
||||||
|
|||||||
13
dbutils.h
13
dbutils.h
@@ -2,6 +2,19 @@
|
|||||||
* dbutils.h
|
* dbutils.h
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
*
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PGconn *establishDBConnection(const char *conninfo, const bool exit_on_error);
|
PGconn *establishDBConnection(const char *conninfo, const bool exit_on_error);
|
||||||
|
|||||||
325
repmgr.c
325
repmgr.c
@@ -1,16 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr.c
|
* repmgr.c - Command interpreter for the repmgr
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
|
||||||
* Copyright (c) Heroku, 2010
|
|
||||||
*
|
*
|
||||||
* Command interpreter for the repmgr
|
|
||||||
* This module is a command-line utility to easily setup a cluster of
|
* This module is a command-line utility to easily setup a cluster of
|
||||||
* hot standby servers for an HA environment
|
* hot standby servers for an HA environment
|
||||||
*
|
*
|
||||||
* Commands implemented are.
|
* Commands implemented are.
|
||||||
* MASTER REGISTER, STANDBY REGISTER, STANDBY CLONE, STANDBY FOLLOW,
|
* MASTER REGISTER, STANDBY REGISTER, STANDBY CLONE, STANDBY FOLLOW,
|
||||||
* STANDBY PROMOTE
|
* STANDBY PROMOTE
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
@@ -71,7 +82,8 @@ char *server_cmd = NULL;
|
|||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
{"dbname", required_argument, NULL, 'd'},
|
{"dbname", required_argument, NULL, 'd'},
|
||||||
{"host", required_argument, NULL, 'h'},
|
{"host", required_argument, NULL, 'h'},
|
||||||
{"port", required_argument, NULL, 'p'},
|
{"port", required_argument, NULL, 'p'},
|
||||||
@@ -111,40 +123,40 @@ main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case 'd':
|
case 'd':
|
||||||
dbname = optarg;
|
dbname = optarg;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
host = optarg;
|
host = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
masterport = optarg;
|
masterport = optarg;
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'U':
|
||||||
username = optarg;
|
username = optarg;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
dest_dir = optarg;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'f':
|
||||||
dest_dir = optarg;
|
config_file = optarg;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'R':
|
||||||
config_file = optarg;
|
remote_user = optarg;
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'w':
|
||||||
remote_user = optarg;
|
wal_keep_segments = optarg;
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'F':
|
||||||
wal_keep_segments = optarg;
|
force = true;
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'v':
|
||||||
force = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
default:
|
||||||
verbose = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,14 +226,14 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
switch (optind < argc)
|
switch (optind < argc)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
|
fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
|
||||||
progname, argv[optind + 1]);
|
progname, argv[optind + 1]);
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check_parameters_for_action(action))
|
if (!check_parameters_for_action(action))
|
||||||
@@ -262,25 +274,25 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case MASTER_REGISTER:
|
case MASTER_REGISTER:
|
||||||
do_master_register();
|
do_master_register();
|
||||||
break;
|
break;
|
||||||
case STANDBY_REGISTER:
|
case STANDBY_REGISTER:
|
||||||
do_standby_register();
|
do_standby_register();
|
||||||
break;
|
break;
|
||||||
case STANDBY_CLONE:
|
case STANDBY_CLONE:
|
||||||
do_standby_clone();
|
do_standby_clone();
|
||||||
break;
|
break;
|
||||||
case STANDBY_PROMOTE:
|
case STANDBY_PROMOTE:
|
||||||
do_standby_promote();
|
do_standby_promote();
|
||||||
break;
|
break;
|
||||||
case STANDBY_FOLLOW:
|
case STANDBY_FOLLOW:
|
||||||
do_standby_follow();
|
do_standby_follow();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -641,29 +653,29 @@ do_standby_clone(void)
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
/* dest_dir not there, must create it */
|
/* dest_dir not there, must create it */
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf(_("creating directory %s ... "), dest_dir);
|
printf(_("creating directory %s ... "), dest_dir);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if (!create_directory(dest_dir))
|
if (!create_directory(dest_dir))
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: couldn't create directory %s ... "),
|
fprintf(stderr, _("%s: couldn't create directory %s ... "),
|
||||||
progname, dest_dir);
|
progname, dest_dir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* Present but empty, fix permissions and use it */
|
/* Present but empty, fix permissions and use it */
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf(_("fixing permissions on existing directory %s ... "),
|
printf(_("fixing permissions on existing directory %s ... "),
|
||||||
dest_dir);
|
dest_dir);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if (!set_directory_permissions(dest_dir))
|
if (!set_directory_permissions(dest_dir))
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
|
fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
|
||||||
progname, dest_dir, strerror(errno));
|
progname, dest_dir, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -674,20 +686,20 @@ do_standby_clone(void)
|
|||||||
|
|
||||||
pg_dir = is_pg_dir(dest_dir);
|
pg_dir = is_pg_dir(dest_dir);
|
||||||
if (pg_dir && !force)
|
if (pg_dir && !force)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("\nThis looks like a PostgreSQL directroy.\n"
|
fprintf(stderr, _("\nThis looks like a PostgreSQL directroy.\n"
|
||||||
"If you are sure you want to clone here, "
|
"If you are sure you want to clone here, "
|
||||||
"please check there is no PostgreSQL server "
|
"please check there is no PostgreSQL server "
|
||||||
"running and use the --force option\n"));
|
"running and use the --force option\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (pg_dir && force)
|
else if (pg_dir && force)
|
||||||
{
|
{
|
||||||
/* Let it continue */
|
/* Let it continue */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
/* Trouble accessing directory */
|
/* Trouble accessing directory */
|
||||||
fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
|
fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
|
||||||
@@ -775,23 +787,23 @@ do_standby_clone(void)
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
/* tblspc_dir not there, must create it */
|
/* tblspc_dir not there, must create it */
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf(_("creating directory \"%s\"... "), tblspc_dir);
|
printf(_("creating directory \"%s\"... "), tblspc_dir);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if (!create_directory(tblspc_dir))
|
if (!create_directory(tblspc_dir))
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
_("%s: couldn't create directory \"%s\"... "),
|
_("%s: couldn't create directory \"%s\"... "),
|
||||||
progname, tblspc_dir);
|
progname, tblspc_dir);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* Present but empty, fix permissions and use it */
|
/* Present but empty, fix permissions and use it */
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf(_("fixing permissions on existing directory \"%s\"... "),
|
printf(_("fixing permissions on existing directory \"%s\"... "),
|
||||||
tblspc_dir);
|
tblspc_dir);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -800,9 +812,9 @@ do_standby_clone(void)
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
|
fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
|
||||||
progname, tblspc_dir, strerror(errno));
|
progname, tblspc_dir, strerror(errno));
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -1426,12 +1438,12 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
strcat(options,
|
strcat(options,
|
||||||
" --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid");
|
" --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid");
|
||||||
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
||||||
options, host_string, remote_path, local_path);
|
options, host_string, remote_path, local_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
maxlen_snprintf(script, "rsync %s %s:%s %s/.",
|
maxlen_snprintf(script, "rsync %s %s:%s %s/.",
|
||||||
options, host_string, remote_path, local_path);
|
options, host_string, remote_path, local_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
@@ -1458,105 +1470,110 @@ check_parameters_for_action(const int action)
|
|||||||
|
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case MASTER_REGISTER:
|
case MASTER_REGISTER:
|
||||||
/*
|
/*
|
||||||
* To register a master we only need the repmgr.conf
|
* To register a master we only need the repmgr.conf
|
||||||
* all other parameters are at least useless and could be
|
* all other parameters are at least useless and could be
|
||||||
* confusing so reject them
|
* confusing so reject them
|
||||||
*/
|
*/
|
||||||
if ((host != NULL) || (masterport != NULL) ||
|
if ((host != NULL) || (masterport != NULL) ||
|
||||||
(username != NULL) || (dbname != NULL))
|
(username != NULL) || (dbname != NULL))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a MASTER REGISTER command.");
|
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a MASTER REGISTER command.");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if (dest_dir != NULL) {
|
if (dest_dir != NULL)
|
||||||
fprintf(stderr, "\nYou don't need a destination directory for MASTER REGISTER command");
|
{
|
||||||
|
fprintf(stderr, "\nYou don't need a destination directory for MASTER REGISTER command");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STANDBY_REGISTER:
|
case STANDBY_REGISTER:
|
||||||
/*
|
/*
|
||||||
* To register a standby we only need the repmgr.conf
|
* To register a standby we only need the repmgr.conf
|
||||||
* we don't need connection parameters to the master
|
* we don't need connection parameters to the master
|
||||||
* because we can detect the master in repl_nodes
|
* because we can detect the master in repl_nodes
|
||||||
*/
|
*/
|
||||||
if ((host != NULL) || (masterport != NULL) ||
|
if ((host != NULL) || (masterport != NULL) ||
|
||||||
(username != NULL) || (dbname != NULL))
|
(username != NULL) || (dbname != NULL))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY REGISTER command.");
|
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY REGISTER command.");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if (dest_dir != NULL) {
|
if (dest_dir != NULL)
|
||||||
fprintf(stderr, "\nYou don't need a destination directory for STANDBY REGISTER command");
|
{
|
||||||
|
fprintf(stderr, "\nYou don't need a destination directory for STANDBY REGISTER command");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STANDBY_PROMOTE:
|
case STANDBY_PROMOTE:
|
||||||
/*
|
/*
|
||||||
* To promote a standby we only need the repmgr.conf
|
* To promote a standby we only need the repmgr.conf
|
||||||
* we don't want connection parameters to the master
|
* we don't want connection parameters to the master
|
||||||
* because we will try to detect the master in repl_nodes
|
* because we will try to detect the master in repl_nodes
|
||||||
* if we can't find it then the promote action will be cancelled
|
* if we can't find it then the promote action will be cancelled
|
||||||
*/
|
*/
|
||||||
if ((host != NULL) || (masterport != NULL) ||
|
if ((host != NULL) || (masterport != NULL) ||
|
||||||
(username != NULL) || (dbname != NULL))
|
(username != NULL) || (dbname != NULL))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY PROMOTE command.");
|
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY PROMOTE command.");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if (dest_dir != NULL) {
|
if (dest_dir != NULL)
|
||||||
fprintf(stderr, "\nYou don't need a destination directory for STANDBY PROMOTE command");
|
{
|
||||||
|
fprintf(stderr, "\nYou don't need a destination directory for STANDBY PROMOTE command");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STANDBY_FOLLOW:
|
case STANDBY_FOLLOW:
|
||||||
/*
|
/*
|
||||||
* To make a standby follow a master we only need the repmgr.conf
|
* To make a standby follow a master we only need the repmgr.conf
|
||||||
* we don't want connection parameters to the new master
|
* we don't want connection parameters to the new master
|
||||||
* because we will try to detect the master in repl_nodes
|
* because we will try to detect the master in repl_nodes
|
||||||
* if we can't find it then the follow action will be cancelled
|
* if we can't find it then the follow action will be cancelled
|
||||||
*/
|
*/
|
||||||
if ((host != NULL) || (masterport != NULL) ||
|
if ((host != NULL) || (masterport != NULL) ||
|
||||||
(username != NULL) || (dbname != NULL))
|
(username != NULL) || (dbname != NULL))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY FOLLOW command.");
|
fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY FOLLOW command.");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
if (dest_dir != NULL) {
|
if (dest_dir != NULL)
|
||||||
fprintf(stderr, "\nYou don't need a destination directory for STANDBY FOLLOW command");
|
{
|
||||||
|
fprintf(stderr, "\nYou don't need a destination directory for STANDBY FOLLOW command");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STANDBY_CLONE:
|
case STANDBY_CLONE:
|
||||||
/*
|
/*
|
||||||
* To clone a master into a standby we need connection parameters
|
* To clone a master into a standby we need connection parameters
|
||||||
* repmgr.conf is useless because we don't have a server running
|
* repmgr.conf is useless because we don't have a server running
|
||||||
* in the standby
|
* in the standby
|
||||||
*/
|
*/
|
||||||
if (config_file != NULL) {
|
if (config_file != NULL)
|
||||||
fprintf(stderr, "\nYou need to use connection parameters to the master when issuing a STANDBY CLONE command.");
|
{
|
||||||
|
fprintf(stderr, "\nYou need to use connection parameters to the master when issuing a STANDBY CLONE command.");
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
|
|||||||
14
repmgr.h
14
repmgr.h
@@ -2,7 +2,19 @@
|
|||||||
* repmgr.h
|
* repmgr.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
* Copyright (c) Heroku, 2010
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
52
repmgrd.c
52
repmgrd.c
@@ -1,12 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* repmgrd.c
|
* repmgrd.c - Replication manager daemon
|
||||||
*
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (C) 2ndQuadrant, 2010
|
||||||
* Copyright (c) Heroku, 2010
|
|
||||||
*
|
*
|
||||||
* Replication manager daemon
|
|
||||||
* This module connects to the nodes of a replication cluster and monitors
|
* This module connects to the nodes of a replication cluster and monitors
|
||||||
* how far are they from master
|
* how far are they from master
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@@ -74,7 +86,8 @@ static void setup_cancel_handler(void);
|
|||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
{"config", required_argument, NULL, 'f'},
|
{"config", required_argument, NULL, 'f'},
|
||||||
{"verbose", no_argument, NULL, 'v'},
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
{NULL, 0, NULL, 0}
|
{NULL, 0, NULL, 0}
|
||||||
@@ -107,16 +120,16 @@ main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case 'f':
|
case 'f':
|
||||||
config_file = optarg;
|
config_file = optarg;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
progname);
|
progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +248,6 @@ MonitorExecute(void)
|
|||||||
{
|
{
|
||||||
fprintf(stderr, "\n%s: We couldn't reconnect to master, checking if ",
|
fprintf(stderr, "\n%s: We couldn't reconnect to master, checking if ",
|
||||||
progname);
|
progname);
|
||||||
fprintf(stderr, "%s: another node has been promoted.\n", progname);
|
|
||||||
for (connection_retries = 0; connection_retries < 6;
|
for (connection_retries = 0; connection_retries < 6;
|
||||||
connection_retries++)
|
connection_retries++)
|
||||||
{
|
{
|
||||||
@@ -265,7 +277,7 @@ MonitorExecute(void)
|
|||||||
if (!is_standby(myLocalConn))
|
if (!is_standby(myLocalConn))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\n%s: seems like we have been promoted, so exit from monitoring...\n",
|
fprintf(stderr, "\n%s: seems like we have been promoted, so exit from monitoring...\n",
|
||||||
progname);
|
progname);
|
||||||
CloseConnections();
|
CloseConnections();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -324,7 +336,7 @@ MonitorExecute(void)
|
|||||||
"INSERT INTO repmgr_%s.repl_monitor "
|
"INSERT INTO repmgr_%s.repl_monitor "
|
||||||
"VALUES(%d, %d, '%s'::timestamp with time zone, "
|
"VALUES(%d, %d, '%s'::timestamp with time zone, "
|
||||||
" '%s', '%s', "
|
" '%s', '%s', "
|
||||||
" %lld, %lld)", myClusterName,
|
" %lld, %lld)", myClusterName,
|
||||||
primaryId, myLocalId, monitor_standby_timestamp,
|
primaryId, myLocalId, monitor_standby_timestamp,
|
||||||
last_wal_primary_location,
|
last_wal_primary_location,
|
||||||
last_wal_standby_received,
|
last_wal_standby_received,
|
||||||
@@ -347,8 +359,8 @@ checkClusterConfiguration(void)
|
|||||||
PGresult *res;
|
PGresult *res;
|
||||||
|
|
||||||
sqlquery_snprintf(sqlquery, "SELECT oid FROM pg_class "
|
sqlquery_snprintf(sqlquery, "SELECT oid FROM pg_class "
|
||||||
" WHERE oid = 'repmgr_%s.repl_nodes'::regclass",
|
" WHERE oid = 'repmgr_%s.repl_nodes'::regclass",
|
||||||
myClusterName);
|
myClusterName);
|
||||||
res = PQexec(myLocalConn, sqlquery);
|
res = PQexec(myLocalConn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
@@ -386,7 +398,7 @@ checkNodeConfiguration(char *conninfo)
|
|||||||
/* Check if we have my node information in repl_nodes */
|
/* Check if we have my node information in repl_nodes */
|
||||||
sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
||||||
" WHERE id = %d AND cluster = '%s' ",
|
" WHERE id = %d AND cluster = '%s' ",
|
||||||
myClusterName, myLocalId, myClusterName);
|
myClusterName, myLocalId, myClusterName);
|
||||||
|
|
||||||
res = PQexec(myLocalConn, sqlquery);
|
res = PQexec(myLocalConn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
@@ -408,7 +420,7 @@ checkNodeConfiguration(char *conninfo)
|
|||||||
|
|
||||||
/* Adding the node */
|
/* Adding the node */
|
||||||
sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
||||||
"VALUES (%d, '%s', '%s')",
|
"VALUES (%d, '%s', '%s')",
|
||||||
myClusterName, myLocalId, myClusterName, conninfo);
|
myClusterName, myLocalId, myClusterName, conninfo);
|
||||||
|
|
||||||
if (!PQexec(primaryConn, sqlquery))
|
if (!PQexec(primaryConn, sqlquery))
|
||||||
|
|||||||
Reference in New Issue
Block a user