mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 07:06:30 +00:00
first alpha version for syslog support
This commit is contained in:
committed by
Greg Smith
parent
1787cf1c21
commit
2c1eafd7a9
4
Makefile
4
Makefile
@@ -2,8 +2,8 @@
|
||||
# Makefile
|
||||
# Copyright (c) 2ndQuadrant, 2010
|
||||
|
||||
repmgrd_OBJS = dbutils.o config.o repmgrd.o
|
||||
repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o
|
||||
repmgrd_OBJS = dbutils.o config.o repmgrd.o log.o
|
||||
repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o log.o
|
||||
|
||||
PG_CPPFLAGS = -I$(libpq_srcdir)
|
||||
PG_LIBS = $(libpq_pgport)
|
||||
|
||||
@@ -622,13 +622,13 @@ and it should contain::
|
||||
|
||||
cluster=test
|
||||
node=1
|
||||
conninfo='host=127.0.0.1 dbname=dbtest'
|
||||
conninfo='host=127.0.0.1 dbname=testdb'
|
||||
|
||||
On “standby" create the file ``/home/standby/repmgr/repmgr.conf`` with::
|
||||
|
||||
cluster=test
|
||||
node=2
|
||||
conninfo='host=127.0.0.1 dbname=dbtest'
|
||||
conninfo='host=127.0.0.1 dbname=testdb'
|
||||
|
||||
Next, with “prime" server running, we want to use the ``clone standby`` command
|
||||
in repmgr to copy over the entire PostgreSQL database cluster onto the
|
||||
@@ -692,7 +692,7 @@ Bringing the former Primary up as a Standby
|
||||
To make the former primary act as a standby, which is necessary before
|
||||
restoring the original roles, type::
|
||||
|
||||
repmgr -U standby -R prime -h 127.0.0.1 -p 5433 -d dbtest --force --verbose standby clone
|
||||
repmgr -U standby -R prime -h 127.0.0.1 -p 5433 -d testdb --force --verbose standby clone
|
||||
|
||||
Stop and restart the “prime" server, which is now acting as a standby server.
|
||||
|
||||
|
||||
11
config.c
11
config.c
@@ -17,12 +17,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "repmgr.h"
|
||||
|
||||
#define MAXLINELENGTH 4096
|
||||
#include "config.h"
|
||||
|
||||
void
|
||||
parse_config(const char *config_file, repmgr_config *config)
|
||||
parse_config(const char* config_file, configuration_options* options)
|
||||
{
|
||||
char *s, buff[MAXLINELENGTH];
|
||||
char name[MAXLEN];
|
||||
@@ -60,6 +58,11 @@ parse_config(const char *config_file, repmgr_config *config)
|
||||
strncpy (config->conninfo, value, MAXLEN);
|
||||
else if (strcmp(name, "rsync_options") == 0)
|
||||
strncpy (config->rsync_options, value, QUERY_STR_LEN);
|
||||
strncpy (options->cluster_name, value, MAXLEN);
|
||||
else if (strcmp(name, "loglevel") == 0)
|
||||
strncpy (options->loglevel, value, MAXLEN);
|
||||
else if (strcmp(name, "logfacility") == 0)
|
||||
strncpy (options->logfacility, value, MAXLEN);
|
||||
else
|
||||
printf ("WARNING: %s/%s: Unknown name/value pair!\n", name, value);
|
||||
}
|
||||
|
||||
16
config.h
16
config.h
@@ -17,14 +17,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char cluster_name[MAXLEN];
|
||||
int node;
|
||||
char conninfo[MAXLEN];
|
||||
char rsync_options[QUERY_STR_LEN];
|
||||
} repmgr_config;
|
||||
#include "repmgr.h"
|
||||
|
||||
typedef struct {
|
||||
char cluster_name[MAXLEN];
|
||||
int node;
|
||||
char conninfo[MAXLEN];
|
||||
char loglevel[MAXLEN];
|
||||
char logfacility[MAXLEN];
|
||||
char rsync_options[QUERY_STR_LEN];
|
||||
} configuration_options;
|
||||
void parse_config(const char *config_file, repmgr_config *config);
|
||||
void parse_line(char *buff, char *name, char *value);
|
||||
char *trim(char *s);
|
||||
|
||||
167
log.c
Normal file
167
log.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* log.c - Logging methods
|
||||
* Copyright (C) 2ndQuadrant, 2010
|
||||
*
|
||||
* This module is a set of methods for logging (currently only syslog)
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#define DEFAULT_IDENT "repmgr"
|
||||
#ifdef HAVE_SYSLOG
|
||||
#define DEFAULT_SYSLOG_FACILITY LOG_LOCAL0
|
||||
#endif
|
||||
|
||||
static int detect_log_level(const char* level);
|
||||
static int detect_log_facility(const char* facility);
|
||||
|
||||
int log_type = REPMGR_STDERR;
|
||||
int log_level = LOG_NOTICE;
|
||||
|
||||
bool logger_init(const char* ident, const char* level, const char* facility)
|
||||
{
|
||||
|
||||
int l;
|
||||
int f;
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
int syslog_facility = DEFAULT_SYSLOG_FACILITY;
|
||||
#endif
|
||||
printf("Logger init: detect stuff: %s, %s\n", level, facility);
|
||||
|
||||
if (!ident) {
|
||||
ident = DEFAULT_IDENT;
|
||||
}
|
||||
|
||||
if (level) {
|
||||
l = detect_log_level(level);
|
||||
printf("Logger level: %d\n", l);
|
||||
|
||||
if (l > 0)
|
||||
log_level = l;
|
||||
else
|
||||
stderr_log_warning(_("Cannot detect log level %s (use any of DEBUG, INFO, NOTICE, WARNING, ERR, ALERT, CRIT or EMERG)"), level);
|
||||
}
|
||||
|
||||
if (facility) {
|
||||
f = detect_log_facility(facility);
|
||||
printf("Logger facility: %d\n", f);
|
||||
if (f == 0) {
|
||||
/* No syslog requested, just stderr */
|
||||
stderr_log_notice(_("Use stderr for logging"));
|
||||
return true;
|
||||
}
|
||||
else if (f == -1) {
|
||||
stderr_log_warning(_("Cannot detect log facility %s (use any of LOCAL0, LOCAL1, ..., LOCAL7, USER or STDERR)"), facility);
|
||||
}
|
||||
#ifdef HAVE_SYSLOG
|
||||
else {
|
||||
syslog_facility = f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
|
||||
setlogmask (LOG_UPTO (log_level));
|
||||
openlog (ident, LOG_CONS | LOG_PID | LOG_NDELAY, syslog_facility);
|
||||
|
||||
log_type = REPMGR_SYSLOG;
|
||||
stderr_log_notice(_("Setup syslog (level: %s, facility: %s)"), level, facility);
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool logger_shutdown(void)
|
||||
{
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
if (log_type == REPMGR_SYSLOG)
|
||||
closelog();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int detect_log_level(const char* level)
|
||||
{
|
||||
if (!strcmp(level, "DEBUG"))
|
||||
return LOG_DEBUG;
|
||||
if (!strcmp(level, "INFO"))
|
||||
return LOG_INFO;
|
||||
if (!strcmp(level, "NOTICE"))
|
||||
return LOG_NOTICE;
|
||||
if (!strcmp(level, "WARNING"))
|
||||
return LOG_WARNING;
|
||||
if (!strcmp(level, "ERR"))
|
||||
return LOG_ERR;
|
||||
if (!strcmp(level, "ALERT"))
|
||||
return LOG_ALERT;
|
||||
if (!strcmp(level, "CRIT"))
|
||||
return LOG_CRIT;
|
||||
if (!strcmp(level, "EMERG"))
|
||||
return LOG_EMERG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int detect_log_facility(const char* facility)
|
||||
{
|
||||
int local = 0;
|
||||
if (!strncmp(facility, "LOCAL", 5) && strlen(facility) == 6) {
|
||||
|
||||
local = atoi (&facility[5]);
|
||||
|
||||
if (local == 0)
|
||||
return LOG_LOCAL0;
|
||||
if (local == 1)
|
||||
return LOG_LOCAL1;
|
||||
if (local == 2)
|
||||
return LOG_LOCAL2;
|
||||
if (local == 3)
|
||||
return LOG_LOCAL3;
|
||||
if (local == 4)
|
||||
return LOG_LOCAL4;
|
||||
if (local == 5)
|
||||
return LOG_LOCAL5;
|
||||
if (local == 6)
|
||||
return LOG_LOCAL6;
|
||||
if (local == 7)
|
||||
return LOG_LOCAL7;
|
||||
|
||||
}
|
||||
else if (!strcmp(facility, "USER")) {
|
||||
return LOG_USER;
|
||||
}
|
||||
else if (!strcmp(facility, "STDERR")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
118
log.h
Normal file
118
log.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* log.h
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _REPMGR_LOG_H_
|
||||
#define _REPMGR_LOG_H_
|
||||
|
||||
#define REPMGR_SYSLOG 1
|
||||
#define REPMGR_STDERR 2
|
||||
|
||||
/* Standard error logging */
|
||||
#define stderr_log_debug(...) if (log_level >= LOG_DEBUG) fprintf(stderr, __VA_ARGS__)
|
||||
#define stderr_log_info(...) if (log_level >= LOG_INFO) fprintf(stderr, __VA_ARGS__)
|
||||
#define stderr_log_notice(...) if (log_level >= LOG_NOTICE) fprintf(stderr, __VA_ARGS__)
|
||||
#define stderr_log_warning(...) if (log_level >= LOG_WARNING) fprintf(stderr, __VA_ARGS__)
|
||||
#define stderr_log_err(...) if (log_level >= LOG_ERR) fprintf(stderr, __VA_ARGS__)
|
||||
#define stderr_log_crit(...) if (log_level >= LOG_CRIT) fprintf(stderr, __VA_ARGS__)
|
||||
#define stderr_log_alert(...) if (log_level >= LOG_ALERT) fprintf(stderr, __VA_ARGS__)
|
||||
#define stderr_log_emerg(...) if (log_level >= LOG_EMERG) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#define log_debug(...) \
|
||||
if (log_type == REPMGR_SYSLOG) \
|
||||
syslog(LOG_DEBUG, __VA_ARGS__); \
|
||||
else \
|
||||
stderr_log_debug(__VA_ARGS__);
|
||||
|
||||
#define log_info(...) \
|
||||
{ \
|
||||
if (log_type == REPMGR_SYSLOG) syslog(LOG_INFO, __VA_ARGS__); \
|
||||
else stderr_log_info(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define log_notice(...) \
|
||||
{ \
|
||||
if (log_type == REPMGR_SYSLOG) syslog(LOG_NOTICE, __VA_ARGS__); \
|
||||
else stderr_log_notice(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define log_warning(...) \
|
||||
{ \
|
||||
if (log_type == REPMGR_SYSLOG) syslog(LOG_WARNING, __VA_ARGS__); \
|
||||
else stderr_log_warning(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define log_err(...) \
|
||||
{ \
|
||||
if (log_type == REPMGR_SYSLOG) syslog(LOG_ERR, __VA_ARGS__); \
|
||||
else stderr_log_err(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define log_crit(...) \
|
||||
{ \
|
||||
if (log_type == REPMGR_SYSLOG) syslog(LOG_CRIT, __VA_ARGS__); \
|
||||
else stderr_log_crit(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define log_alert(...) \
|
||||
{ \
|
||||
if (log_type == REPMGR_SYSLOG) syslog(LOG_ALERT, __VA_ARGS__); \
|
||||
else stderr_log_alert(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define log_emerg(...) \
|
||||
{ \
|
||||
if (log_type == REPMGR_SYSLOG) syslog(LOG_ALERT, __VA_ARGS__); \
|
||||
else stderr_log_alert(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define LOG_EMERG 0 /* system is unusable */
|
||||
#define LOG_ALERT 1 /* action must be taken immediately */
|
||||
#define LOG_CRIT 2 /* critical conditions */
|
||||
#define LOG_ERR 3 /* error conditions */
|
||||
#define LOG_WARNING 4 /* warning conditions */
|
||||
#define LOG_NOTICE 5 /* normal but significant condition */
|
||||
#define LOG_INFO 6 /* informational */
|
||||
#define LOG_DEBUG 7 /* debug-level messages */
|
||||
|
||||
#define log_debug(...) stderr_log_debug(__VA_ARGS__)
|
||||
#define log_info(...) stderr_log_info(__VA_ARGS__)
|
||||
#define log_notice(...) stderr_log_notice(__VA_ARGS__)
|
||||
#define log_warning(...) stderr_log_warning(__VA_ARGS__)
|
||||
#define log_err(...) stderr_log_err(__VA_ARGS__)
|
||||
#define log_crit(...) stderr_log_crit(__VA_ARGS__)
|
||||
#define log_alert(...) stderr_log_alert(__VA_ARGS__)
|
||||
#define log_emerg(...) stderr_log_emerg(__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Logger initialisation and shutdown */
|
||||
bool logger_shutdown(void);
|
||||
bool logger_init(const char* ident, const char* level, const char* facility);
|
||||
|
||||
extern int log_type;
|
||||
extern int log_level;
|
||||
|
||||
#endif
|
||||
142
repmgr.c
142
repmgr.c
@@ -31,6 +31,8 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
#include "check_dir.h"
|
||||
|
||||
#define RECOVERY_FILE "recovery.conf"
|
||||
@@ -75,7 +77,7 @@ char *masterport = NULL;
|
||||
char *server_mode = NULL;
|
||||
char *server_cmd = NULL;
|
||||
|
||||
repmgr_config config = {};
|
||||
configuration_options options;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
@@ -231,11 +233,8 @@ main(int argc, char **argv)
|
||||
if (!check_parameters_for_action(action))
|
||||
exit(1);
|
||||
|
||||
if (config_file == NULL)
|
||||
{
|
||||
config_file = malloc(5 + sizeof(CONFIG_FILE));
|
||||
sprintf(config_file, "./%s", CONFIG_FILE);
|
||||
}
|
||||
if (!config_file)
|
||||
config_file = CONFIG_FILE;
|
||||
|
||||
if (wal_keep_segments == NULL)
|
||||
{
|
||||
@@ -273,6 +272,19 @@ main(int argc, char **argv)
|
||||
keywords[5] = NULL;
|
||||
values[5] = NULL;
|
||||
|
||||
/*
|
||||
* Read the configuration file: repmgr.conf
|
||||
*/
|
||||
parse_config(config_file, &options);
|
||||
if (options.node == -1)
|
||||
{
|
||||
fprintf(stderr, "Node information is missing. "
|
||||
"Check the configuration file.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
logger_init(progname, options.loglevel, options.logfacility);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MASTER_REGISTER:
|
||||
@@ -294,6 +306,7 @@ main(int argc, char **argv)
|
||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
|
||||
exit(1);
|
||||
}
|
||||
logger_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -309,31 +322,31 @@ do_master_register(void)
|
||||
bool schema_exists = false;
|
||||
char master_version[MAXVERSIONSTR];
|
||||
|
||||
conn = establishDBConnection(config.conninfo, true);
|
||||
conn = establishDBConnection(options.conninfo, true);
|
||||
|
||||
/* master should be v9 or better */
|
||||
pg_version(conn, master_version);
|
||||
if (strcmp(master_version, "") == 0)
|
||||
{
|
||||
PQfinish(conn);
|
||||
fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), progname);
|
||||
log_err( _("%s needs master to be PostgreSQL 9.0 or better\n"), progname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check we are a master */
|
||||
if (is_standby(conn))
|
||||
{
|
||||
fprintf(stderr, "repmgr: This node should be a master\n");
|
||||
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), progname);
|
||||
PQfinish(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if there is a schema for this cluster */
|
||||
sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", config.cluster_name);
|
||||
sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", options.cluster_name);
|
||||
res = PQexec(conn, sqlquery);
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
fprintf(stderr, "Can't get info about schemas: %s\n", PQerrorMessage(conn));
|
||||
log_err(_("Can't get info about schemas: %s\n"), PQerrorMessage(conn));
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
return;
|
||||
@@ -343,7 +356,7 @@ do_master_register(void)
|
||||
{
|
||||
if (!force) /* and we are not forcing so error */
|
||||
{
|
||||
fprintf(stderr, "Schema repmgr_%s already exists.", config.cluster_name);
|
||||
log_notice(_("Schema repmgr_%s already exists."), options.cluster_name);
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
return;
|
||||
@@ -355,11 +368,11 @@ do_master_register(void)
|
||||
if (!schema_exists)
|
||||
{
|
||||
/* ok, create the schema */
|
||||
sprintf(sqlquery, "CREATE SCHEMA repmgr_%s", config.cluster_name);
|
||||
sprintf(sqlquery, "CREATE SCHEMA repmgr_%s", options.cluster_name);
|
||||
if (!PQexec(conn, sqlquery))
|
||||
{
|
||||
fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n",
|
||||
config.cluster_name, PQerrorMessage(conn));
|
||||
log_err(_("Cannot create the schema repmgr_%s: %s\n"),
|
||||
options.cluster_name, PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
return;
|
||||
}
|
||||
@@ -368,11 +381,11 @@ do_master_register(void)
|
||||
sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( "
|
||||
" id integer primary key, "
|
||||
" cluster text not null, "
|
||||
" conninfo text not null)", config.cluster_name);
|
||||
" conninfo text not null)", options.cluster_name);
|
||||
if (!PQexec(conn, sqlquery))
|
||||
{
|
||||
fprintf(stderr, "Cannot create the table repmgr_%s.repl_nodes: %s\n",
|
||||
config.cluster_name, PQerrorMessage(conn));
|
||||
log_err(_("Cannot create the table repmgr_%s.repl_nodes: %s\n"),
|
||||
options.cluster_name, PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
return;
|
||||
}
|
||||
@@ -384,11 +397,11 @@ do_master_register(void)
|
||||
" last_wal_primary_location TEXT NOT NULL, "
|
||||
" last_wal_standby_location TEXT NOT NULL, "
|
||||
" replication_lag BIGINT NOT NULL, "
|
||||
" apply_lag BIGINT NOT NULL) ", config.cluster_name);
|
||||
" apply_lag BIGINT NOT NULL) ", options.cluster_name);
|
||||
if (!PQexec(conn, sqlquery))
|
||||
{
|
||||
fprintf(stderr, "Cannot create the table repmgr_%s.repl_monitor: %s\n",
|
||||
config.cluster_name, PQerrorMessage(conn));
|
||||
log_err(_("Cannot create the table repmgr_%s.repl_monitor: %s\n"),
|
||||
options.cluster_name, PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
return;
|
||||
}
|
||||
@@ -402,11 +415,11 @@ do_master_register(void)
|
||||
" last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, "
|
||||
" pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag "
|
||||
" FROM monitor_info a "
|
||||
" WHERE row_number = 1", config.cluster_name, config.cluster_name);
|
||||
" WHERE row_number = 1", options.cluster_name, options.cluster_name);
|
||||
if (!PQexec(conn, sqlquery))
|
||||
{
|
||||
fprintf(stderr, "Cannot create the view repmgr_%s.repl_status: %s\n",
|
||||
config.cluster_name, PQerrorMessage(conn));
|
||||
log_err(_("Cannot create the view repmgr_%s.repl_status: %s\n"),
|
||||
options.cluster_name, PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
return;
|
||||
}
|
||||
@@ -417,11 +430,11 @@ do_master_register(void)
|
||||
int id;
|
||||
|
||||
/* Ensure there isn't any other master already registered */
|
||||
master_conn = getMasterConnection(conn, config.node, config.cluster_name, &id);
|
||||
master_conn = getMasterConnection(conn, options.node, options.cluster_name, &id);
|
||||
if (master_conn != NULL)
|
||||
{
|
||||
PQfinish(master_conn);
|
||||
fprintf(stderr, "There is a master already in this cluster");
|
||||
log_notice(_("There is a master already in cluster %s"), options.cluster_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -431,11 +444,11 @@ do_master_register(void)
|
||||
{
|
||||
sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes "
|
||||
" WHERE id = %d",
|
||||
config.cluster_name, config.node);
|
||||
options.cluster_name, options.node);
|
||||
|
||||
if (!PQexec(conn, sqlquery))
|
||||
{
|
||||
fprintf(stderr, "Cannot delete node details, %s\n",
|
||||
log_warning(_("Cannot delete node details, %s\n"),
|
||||
PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
return;
|
||||
@@ -444,17 +457,19 @@ do_master_register(void)
|
||||
|
||||
sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
||||
"VALUES (%d, '%s', '%s')",
|
||||
config.cluster_name, config.node, config.cluster_name, config.conninfo);
|
||||
options.cluster_name, options.node, options.cluster_name, options.conninfo);
|
||||
|
||||
if (!PQexec(conn, sqlquery))
|
||||
{
|
||||
fprintf(stderr, "Cannot insert node details, %s\n",
|
||||
log_warning(_("Cannot insert node details, %s\n"),
|
||||
PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
PQfinish(conn);
|
||||
log_info(_("Master node correctly registered for cluster %s with id %d (conninfo: %s)"),
|
||||
options.cluster_name, options.node, options.conninfo);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -472,7 +487,7 @@ do_standby_register(void)
|
||||
char master_version[MAXVERSIONSTR];
|
||||
char standby_version[MAXVERSIONSTR];
|
||||
|
||||
conn = establishDBConnection(config.conninfo, true);
|
||||
conn = establishDBConnection(options.conninfo, true);
|
||||
|
||||
/* should be v9 or better */
|
||||
pg_version(conn, standby_version);
|
||||
@@ -492,7 +507,7 @@ do_standby_register(void)
|
||||
}
|
||||
|
||||
/* Check if there is a schema for this cluster */
|
||||
sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", config.cluster_name);
|
||||
sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", options.cluster_name);
|
||||
res = PQexec(conn, sqlquery);
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
@@ -504,7 +519,7 @@ do_standby_register(void)
|
||||
|
||||
if (PQntuples(res) == 0) /* schema doesn't exists */
|
||||
{
|
||||
fprintf(stderr, "Schema repmgr_%s doesn't exists.", config.cluster_name);
|
||||
fprintf(stderr, "Schema repmgr_%s doesn't exists.", options.cluster_name);
|
||||
PQclear(res);
|
||||
PQfinish(conn);
|
||||
return;
|
||||
@@ -512,9 +527,11 @@ do_standby_register(void)
|
||||
PQclear(res);
|
||||
|
||||
/* check if there is a master in this cluster */
|
||||
master_conn = getMasterConnection(conn, config.node, config.cluster_name, &master_id);
|
||||
if (!master_conn)
|
||||
master_conn = getMasterConnection(conn, options.node, options.cluster_name, &master_id);
|
||||
if (!master_conn) {
|
||||
fprintf(stderr, _("Cannot retrieve information about the connection to the master\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* master should be v9 or better */
|
||||
pg_version(master_conn, master_version);
|
||||
@@ -542,7 +559,7 @@ do_standby_register(void)
|
||||
{
|
||||
sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes "
|
||||
" WHERE id = %d",
|
||||
config.cluster_name, config.node);
|
||||
options.cluster_name, options.node);
|
||||
|
||||
if (!PQexec(master_conn, sqlquery))
|
||||
{
|
||||
@@ -556,7 +573,8 @@ do_standby_register(void)
|
||||
|
||||
sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
||||
"VALUES (%d, '%s', '%s')",
|
||||
config.cluster_name, config.node, config.cluster_name, config.conninfo);
|
||||
options.cluster_name, options.node, options.cluster_name, options.conninfo);
|
||||
fprintf(stderr, "QUERY: %s\n", sqlquery);
|
||||
|
||||
if (!PQexec(master_conn, sqlquery))
|
||||
{
|
||||
@@ -608,41 +626,38 @@ do_standby_clone(void)
|
||||
{
|
||||
case 0:
|
||||
/* dest_dir not there, must create it */
|
||||
if (verbose)
|
||||
printf(_("creating directory %s ... "), dest_dir);
|
||||
log_info(_("creating directory %s ... "), dest_dir);
|
||||
fflush(stdout);
|
||||
|
||||
if (!create_directory(dest_dir))
|
||||
{
|
||||
fprintf(stderr, _("%s: couldn't create directory %s ... "),
|
||||
log_err(_("%s: couldn't create directory %s ... "),
|
||||
progname, dest_dir);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* Present but empty, fix permissions and use it */
|
||||
if (verbose)
|
||||
printf(_("fixing permissions on existing directory %s ... "),
|
||||
dest_dir);
|
||||
log_info(_("fixing permissions on existing directory %s ... "),
|
||||
dest_dir);
|
||||
fflush(stdout);
|
||||
|
||||
if (!set_directory_permissions(dest_dir))
|
||||
{
|
||||
fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
|
||||
log_err(_("%s: could not change permissions of directory \"%s\": %s\n"),
|
||||
progname, dest_dir, strerror(errno));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* Present and not empty */
|
||||
fprintf(stderr,
|
||||
_("%s: directory \"%s\" exists but is not empty\n"),
|
||||
log_warning( _("%s: directory \"%s\" exists but is not empty\n"),
|
||||
progname, dest_dir);
|
||||
|
||||
pg_dir = is_pg_dir(dest_dir);
|
||||
if (pg_dir && !force)
|
||||
{
|
||||
fprintf(stderr, _("\nThis looks like a PostgreSQL directroy.\n"
|
||||
log_warning( _("\nThis 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 --force option\n"));
|
||||
@@ -657,7 +672,7 @@ do_standby_clone(void)
|
||||
return;
|
||||
default:
|
||||
/* Trouble accessing directory */
|
||||
fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
|
||||
log_err( _("%s: could not access directory \"%s\": %s\n"),
|
||||
progname, dest_dir, strerror(errno));
|
||||
}
|
||||
|
||||
@@ -671,7 +686,7 @@ do_standby_clone(void)
|
||||
conn = PQconnectdbParams(keywords, values, true);
|
||||
if (!conn)
|
||||
{
|
||||
fprintf(stderr, _("%s: could not connect to master\n"),
|
||||
log_err(_("%s: could not connect to master\n"),
|
||||
progname);
|
||||
return;
|
||||
}
|
||||
@@ -681,7 +696,7 @@ do_standby_clone(void)
|
||||
if (strcmp(master_version, "") == 0)
|
||||
{
|
||||
PQfinish(conn);
|
||||
fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), progname);
|
||||
log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), progname);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -689,7 +704,7 @@ do_standby_clone(void)
|
||||
if (is_standby(conn))
|
||||
{
|
||||
PQfinish(conn);
|
||||
fprintf(stderr, "\nThe command should clone a primary node\n");
|
||||
log_err(_("\nThe command should clone a primary node\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -697,24 +712,23 @@ do_standby_clone(void)
|
||||
if (!guc_setted(conn, "wal_level", "=", "hot_standby"))
|
||||
{
|
||||
PQfinish(conn);
|
||||
fprintf(stderr, _("%s needs parameter 'wal_level' to be set to 'hot_standby'\n"), progname);
|
||||
log_err(_("%s needs parameter 'wal_level' to be set to 'hot_standby'\n"), progname);
|
||||
return;
|
||||
}
|
||||
if (!guc_setted(conn, "wal_keep_segments", ">=", wal_keep_segments))
|
||||
{
|
||||
PQfinish(conn);
|
||||
fprintf(stderr, _("%s needs parameter 'wal_keep_segments' to be set to %s or greater\n"), progname, wal_keep_segments);
|
||||
log_err(_("%s needs parameter 'wal_keep_segments' to be set to %s or greater (see the '-w' option)\n"), progname, wal_keep_segments);
|
||||
return;
|
||||
}
|
||||
if (!guc_setted(conn, "archive_mode", "=", "on"))
|
||||
{
|
||||
PQfinish(conn);
|
||||
fprintf(stderr, _("%s needs parameter 'archive_mode' to be set to 'on'\n"), progname);
|
||||
log_err(_("%s needs parameter 'archive_mode' to be set to 'on'\n"), progname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf(_("Succesfully connected to primary. Current installation size is %s\n"), get_cluster_size(conn));
|
||||
log_info(_("Succesfully connected to primary. Current installation size is %s\n"), get_cluster_size(conn));
|
||||
|
||||
/* Check if the tablespace locations exists and that we can write to them */
|
||||
sprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')");
|
||||
@@ -961,7 +975,7 @@ do_standby_promote(void)
|
||||
char standby_version[MAXVERSIONSTR];
|
||||
|
||||
/* We need to connect to check configuration */
|
||||
conn = establishDBConnection(config.conninfo, true);
|
||||
conn = establishDBConnection(options.conninfo, true);
|
||||
|
||||
/* we need v9 or better */
|
||||
pg_version(conn, standby_version);
|
||||
@@ -980,7 +994,7 @@ do_standby_promote(void)
|
||||
}
|
||||
|
||||
/* we also need to check if there isn't any master already */
|
||||
old_master_conn = getMasterConnection(conn, config.node, config.cluster_name, &old_master_id);
|
||||
old_master_conn = getMasterConnection(conn, options.node, options.cluster_name, &old_master_id);
|
||||
if (old_master_conn != NULL)
|
||||
{
|
||||
PQfinish(old_master_conn);
|
||||
@@ -1023,7 +1037,7 @@ do_standby_promote(void)
|
||||
/*
|
||||
* XXX i'm removing this because it gives an annoying message saying couldn't connect
|
||||
* but is just the server starting up
|
||||
* conn = establishDBConnection(config.conninfo, true);
|
||||
* conn = establishDBConnection(options.conninfo, true);
|
||||
* if (is_standby(conn))
|
||||
* fprintf(stderr, "\n%s: STANDBY PROMOTE failed, this is still a standby node.\n", progname);
|
||||
* else
|
||||
@@ -1053,7 +1067,7 @@ do_standby_follow(void)
|
||||
char standby_version[MAXVERSIONSTR];
|
||||
|
||||
/* We need to connect to check configuration */
|
||||
conn = establishDBConnection(config.conninfo, true);
|
||||
conn = establishDBConnection(options.conninfo, true);
|
||||
|
||||
/* Check we are in a standby node */
|
||||
if (!is_standby(conn))
|
||||
@@ -1072,7 +1086,7 @@ do_standby_follow(void)
|
||||
}
|
||||
|
||||
/* we also need to check if there is any master in the cluster */
|
||||
master_conn = getMasterConnection(conn, config.node, config.cluster_name, &master_id);
|
||||
master_conn = getMasterConnection(conn, options.node, options.cluster_name, &master_id);
|
||||
if (master_conn == NULL)
|
||||
{
|
||||
PQfinish(conn);
|
||||
@@ -1202,14 +1216,14 @@ create_recovery_file(const char *data_dir)
|
||||
recovery_file = fopen(recovery_file_path, "w");
|
||||
if (recovery_file == NULL)
|
||||
{
|
||||
fprintf(stderr, "could not create recovery.conf file, it could be necesary to create it manually\n");
|
||||
fprintf(stderr, "could not create recovery.conf file, it could be necessary to create it manually\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf(line, "standby_mode = 'on'\n");
|
||||
if (fputs(line, recovery_file) == EOF)
|
||||
{
|
||||
fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n");
|
||||
fprintf(stderr, "recovery file could not be written, it could be necessary to create it manually\n");
|
||||
fclose(recovery_file);
|
||||
return false;
|
||||
}
|
||||
@@ -1217,7 +1231,7 @@ create_recovery_file(const char *data_dir)
|
||||
sprintf(line, "primary_conninfo = 'host=%s port=%s'\n", host, ((masterport==NULL) ? "5432" : masterport));
|
||||
if (fputs(line, recovery_file) == EOF)
|
||||
{
|
||||
fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n");
|
||||
fprintf(stderr, "recovery file could not be written, it could be necessary to create it manually\n");
|
||||
fclose(recovery_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
7
repmgr.h
7
repmgr.h
@@ -26,15 +26,16 @@
|
||||
|
||||
#include "dbutils.h"
|
||||
|
||||
|
||||
#define PRIMARY_MODE 0
|
||||
#define STANDBY_MODE 1
|
||||
|
||||
#define MAXLEN 80
|
||||
#define CONFIG_FILE "repmgr.conf"
|
||||
#define MAXLEN 80
|
||||
#define CONFIG_FILE "./repmgr.conf"
|
||||
#define MAXVERSIONSTR 16
|
||||
#define QUERY_STR_LEN 8192
|
||||
|
||||
#include "config.h"
|
||||
#define MAXFILENAME 1024
|
||||
#define MAXLINELENGTH 4096
|
||||
|
||||
#endif
|
||||
|
||||
45
repmgrd.c
45
repmgrd.c
@@ -27,23 +27,25 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "repmgr.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "libpq/pqsignal.h"
|
||||
|
||||
/* Local info */
|
||||
configuration_options local_options;
|
||||
int myLocalMode = STANDBY_MODE;
|
||||
PGconn *myLocalConn;
|
||||
|
||||
/* Primary info */
|
||||
int primaryId;
|
||||
char primaryConninfo[MAXLEN];
|
||||
configuration_options primary_options;
|
||||
PGconn *primaryConn;
|
||||
|
||||
char sqlquery[8192];
|
||||
|
||||
const char *progname;
|
||||
|
||||
char *config_file = NULL;
|
||||
char *config_file = CONFIG_FILE;
|
||||
bool verbose = false;
|
||||
|
||||
// should initialize with {0} to be ANSI complaint ? but this raises error with gcc -Wall
|
||||
@@ -130,24 +132,19 @@ main(int argc, char **argv)
|
||||
|
||||
setup_cancel_handler();
|
||||
|
||||
if (config_file == NULL)
|
||||
{
|
||||
config_file = malloc(5 + sizeof(CONFIG_FILE));
|
||||
sprintf(config_file, "./%s", CONFIG_FILE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the configuration file: repmgr.conf
|
||||
*/
|
||||
parse_config(config_file, &config);
|
||||
if (config.node == -1)
|
||||
parse_config(config_file, &local_options);
|
||||
if (local_options.node == -1)
|
||||
{
|
||||
fprintf(stderr, "Node information is missing. "
|
||||
"Check the configuration file.\n");
|
||||
exit(1);
|
||||
}
|
||||
logger_init(progname, local_options.loglevel, local_options.logfacility);
|
||||
|
||||
myLocalConn = establishDBConnection(config.conninfo, true);
|
||||
myLocalConn = establishDBConnection(local_options.conninfo, true);
|
||||
|
||||
/* should be v9 or better */
|
||||
pg_version(myLocalConn, standby_version);
|
||||
@@ -165,20 +162,20 @@ main(int argc, char **argv)
|
||||
myLocalMode = is_standby(myLocalConn) ? STANDBY_MODE : PRIMARY_MODE;
|
||||
if (myLocalMode == PRIMARY_MODE)
|
||||
{
|
||||
primaryId = config.node;
|
||||
strcpy(primaryConninfo, config.conninfo);
|
||||
primary_options.node = local_options.node;
|
||||
strcpy(primary_options.conninfo, local_options.conninfo);
|
||||
primaryConn = myLocalConn;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* I need the id of the primary as well as a connection to it */
|
||||
primaryConn = getMasterConnection(myLocalConn, config.node, config.cluster_name, &primaryId);
|
||||
primaryConn = getMasterConnection(myLocalConn, local_options.node, local_options.cluster_name, &primary_options.node);
|
||||
if (primaryConn == NULL)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
checkClusterConfiguration();
|
||||
checkNodeConfiguration(config.conninfo);
|
||||
checkNodeConfiguration(local_options.conninfo);
|
||||
if (myLocalMode == STANDBY_MODE)
|
||||
{
|
||||
MonitorCheck();
|
||||
@@ -237,11 +234,11 @@ MonitorExecute(void)
|
||||
"another node has been promoted.\n", progname);
|
||||
for (connection_retries = 0; connection_retries < 6; connection_retries++)
|
||||
{
|
||||
primaryConn = getMasterConnection(myLocalConn, config.node, config.cluster_name, &primaryId);
|
||||
primaryConn = getMasterConnection(myLocalConn, local_options.node, local_options.cluster_name, &primary_options.node);
|
||||
if (PQstatus(primaryConn) == CONNECTION_OK)
|
||||
{
|
||||
/* Connected, we can continue the process so break the loop */
|
||||
fprintf(stderr, "\n%s: Connected to node %d, continue monitoring.\n", progname, primaryId);
|
||||
fprintf(stderr, "\n%s: Connected to node %d, continue monitoring.\n", progname, primary_options.node);
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -320,8 +317,8 @@ MonitorExecute(void)
|
||||
"INSERT INTO repmgr_%s.repl_monitor "
|
||||
"VALUES(%d, %d, '%s'::timestamp with time zone, "
|
||||
" '%s', '%s', "
|
||||
" %lld, %lld)", config.cluster_name,
|
||||
primaryId, config.node, monitor_standby_timestamp,
|
||||
" %lld, %lld)", local_options.cluster_name,
|
||||
primary_options.node, local_options.node, monitor_standby_timestamp,
|
||||
last_wal_primary_location,
|
||||
last_wal_standby_received,
|
||||
(lsn_primary - lsn_standby_received),
|
||||
@@ -344,7 +341,7 @@ checkClusterConfiguration(void)
|
||||
|
||||
sprintf(sqlquery, "SELECT oid FROM pg_class "
|
||||
" WHERE oid = 'repmgr_%s.repl_nodes'::regclass",
|
||||
config.cluster_name);
|
||||
local_options.cluster_name);
|
||||
res = PQexec(myLocalConn, sqlquery);
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
@@ -382,7 +379,7 @@ checkNodeConfiguration(char *conninfo)
|
||||
*/
|
||||
sprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
||||
" WHERE id = %d AND cluster = '%s' ",
|
||||
config.cluster_name, config.node, config.cluster_name);
|
||||
local_options.cluster_name, local_options.node, local_options.cluster_name);
|
||||
|
||||
res = PQexec(myLocalConn, sqlquery);
|
||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
@@ -404,7 +401,7 @@ checkNodeConfiguration(char *conninfo)
|
||||
/* Adding the node */
|
||||
sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
||||
"VALUES (%d, '%s', '%s')",
|
||||
config.cluster_name, config.node, config.cluster_name, conninfo);
|
||||
local_options.cluster_name, local_options.node, local_options.cluster_name, local_options.conninfo);
|
||||
|
||||
if (!PQexec(primaryConn, sqlquery))
|
||||
{
|
||||
@@ -444,7 +441,7 @@ help(const char *progname)
|
||||
printf(_(" --help show this help, then exit\n"));
|
||||
printf(_(" --version output version information, then exit\n"));
|
||||
printf(_(" --verbose output verbose activity information\n"));
|
||||
printf(_(" -f, --config_file=PATH database to connect to\n"));
|
||||
printf(_(" -f, --config_file=PATH configuration file\n"));
|
||||
printf(_("\n%s monitors a cluster of servers.\n"), progname);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user