diff --git a/Makefile b/Makefile index 634785f9..a9aa7814 100644 --- a/Makefile +++ b/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) diff --git a/README.rst b/README.rst index c2db72be..6addf0b0 100644 --- a/README.rst +++ b/README.rst @@ -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. diff --git a/config.c b/config.c index c3df1b89..33f39668 100644 --- a/config.c +++ b/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); } diff --git a/config.h b/config.h index b66bc6e4..cfd33628 100644 --- a/config.h +++ b/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); diff --git a/log.c b/log.c new file mode 100644 index 00000000..9c121a1c --- /dev/null +++ b/log.c @@ -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 . + * + */ + +#include "repmgr.h" + +#include + +#ifdef HAVE_SYSLOG +#include +#include +#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; +} diff --git a/log.h b/log.h new file mode 100644 index 00000000..3f87ff26 --- /dev/null +++ b/log.h @@ -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 . + * + */ + +#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 + +#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 diff --git a/repmgr.c b/repmgr.c index b8d2540a..d99dde44 100644 --- a/repmgr.c +++ b/repmgr.c @@ -31,6 +31,8 @@ #include #include +#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; } diff --git a/repmgr.h b/repmgr.h index 78b9edbc..f5e0dee5 100644 --- a/repmgr.h +++ b/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 diff --git a/repmgrd.c b/repmgrd.c index 3ed095e8..4a4a56eb 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -27,23 +27,25 @@ #include #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); }