From f9dfcb20b4e09cdbf297320998a90890148dc135 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Thu, 20 Apr 2017 16:42:56 +0900 Subject: [PATCH] Initial config file structure definition and initialisation --- config.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- config.h | 124 +++++++++++++++++++++++++++++----- repmgr.h | 5 ++ 3 files changed, 311 insertions(+), 18 deletions(-) diff --git a/config.c b/config.c index 85632b54..625956cb 100644 --- a/config.c +++ b/config.c @@ -8,8 +8,13 @@ #include "repmgr.h" #include "config.h" +#include "log.h" const static char *_progname = NULL; +static char config_file_path[MAXPGPATH]; +static bool config_file_provided = false; +bool config_file_found = false; + static void _parse_config(t_configuration_options *options, ItemList *error_list); static void exit_with_errors(ItemList *config_errors); @@ -29,7 +34,123 @@ progname(void) bool load_config(const char *config_file, bool verbose, t_configuration_options *options, char *argv0) { - return true; + struct stat stat_config; + + /* + * If a configuration file was provided, check it exists, otherwise + * emit an error and terminate. We assume that if a user explicitly + * provides a configuration file, they'll want to make sure it's + * used and not fall back to any of the defaults. + */ + if (config_file[0]) + { + strncpy(config_file_path, config_file, MAXPGPATH); + canonicalize_path(config_file_path); + + if (stat(config_file_path, &stat_config) != 0) + { + log_error(_("provided configuration file \"%s\" not found: %s"), + config_file, + strerror(errno) + ); + exit(ERR_BAD_CONFIG); + } + + if (verbose == true) + { + log_notice(_("using configuration file \"%s\""), config_file); + } + + config_file_provided = true; + config_file_found = true; + } + + + /* + * If no configuration file was provided, attempt to find a default file + * in this order: + * - current directory + * - /etc/repmgr.conf + * - default sysconfdir + * + * here we just check for the existence of the file; parse_config() + * will handle read errors etc. + * + * XXX modify this section so package maintainers can provide a patch + * specifying location of a distribution-specific configuration file + */ + if (config_file_provided == false) + { + char my_exec_path[MAXPGPATH]; + char sysconf_etc_path[MAXPGPATH]; + + /* 1. "./repmgr.conf" */ + if (verbose == true) + { + log_notice(_("looking for configuration file in current directory")); + } + + snprintf(config_file_path, MAXPGPATH, "./%s", CONFIG_FILE_NAME); + canonicalize_path(config_file_path); + + if (stat(config_file_path, &stat_config) == 0) + { + config_file_found = true; + goto end_search; + } + + /* 2. "/etc/repmgr.conf" */ + if (verbose == true) + { + log_notice(_("looking for configuration file in /etc")); + } + + snprintf(config_file_path, MAXPGPATH, "/etc/%s", CONFIG_FILE_NAME); + if (stat(config_file_path, &stat_config) == 0) + { + config_file_found = true; + goto end_search; + } + + /* 3. default sysconfdir */ + if (find_my_exec(argv0, my_exec_path) < 0) + { + log_error(_("%s: could not find own program executable"), argv0); + exit(EXIT_FAILURE); + } + + get_etc_path(my_exec_path, sysconf_etc_path); + + if (verbose == true) + { + log_notice(_("looking for configuration file in %s"), sysconf_etc_path); + } + + snprintf(config_file_path, MAXPGPATH, "%s/%s", sysconf_etc_path, CONFIG_FILE_NAME); + if (stat(config_file_path, &stat_config) == 0) + { + config_file_found = true; + goto end_search; + } + + end_search: + if (config_file_found == true) + { + if (verbose == true) + { + log_notice(_("configuration file found at: %s"), config_file_path); + } + } + else + { + if (verbose == true) + { + log_notice(_("no configuration file provided or found")); + } + } + } + + return parse_config(options); } bool @@ -51,7 +172,84 @@ parse_config(t_configuration_options *options) static void _parse_config(t_configuration_options *options, ItemList *error_list) { + FILE *fp; + char *s, + buf[MAXLINELENGTH]; + char name[MAXLEN]; + char value[MAXLEN]; + /* For sanity-checking provided conninfo string */ + PQconninfoOption *conninfo_options; + char *conninfo_errmsg = NULL; + + bool node_id_found = false; + + /* Initialize configuration options with sensible defaults */ + + /* node information */ + options->node_id = UNKNOWN_NODE_ID; + options->upstream_node_id = NO_UPSTREAM_NODE; + memset(options->node_name, 0, sizeof(options->node_name)); + memset(options->conninfo, 0, sizeof(options->conninfo)); + memset(options->pg_bindir, 0, sizeof(options->pg_bindir)); + + /* + * log settings + * + * note: the default for "loglevel" is set in log.c and does not need + * to be initialised here + */ + memset(options->logfacility, 0, sizeof(options->logfacility)); + memset(options->logfile, 0, sizeof(options->logfile)); + + /* standby clone settings + * ----------------------- */ + options->use_replication_slots = false; + memset(options->rsync_options, 0, sizeof(options->rsync_options)); + memset(options->ssh_options, 0, sizeof(options->ssh_options)); + memset(options->pg_basebackup_options, 0, sizeof(options->pg_basebackup_options)); + memset(options->restore_command, 0, sizeof(options->restore_command)); + options->tablespace_mapping.head = NULL; + options->tablespace_mapping.tail = NULL; + + /* repmgrd settings + * ---------------- */ + options->failover_mode = MANUAL_FAILOVER; + options->priority = DEFAULT_PRIORITY; + memset(options->promote_command, 0, sizeof(options->promote_command)); + memset(options->follow_command, 0, sizeof(options->follow_command)); + options->monitor_interval_secs = 2; + options->master_response_timeout = 60; + /* default to 6 reconnection attempts at intervals of 10 seconds */ + options->reconnect_attempts = 6; + options->reconnect_interval = 10; + options->retry_promote_interval_secs = 300; + options->monitoring_history = false; /* new in 4.0, replaces --monitoring-history */ + + /* witness settings + * ---------------- */ + + /* default to resyncing repl_nodes table every 30 seconds on the witness server */ + options->witness_repl_nodes_sync_interval_secs = 30; + + /* service settings + * ---------------- */ + memset(options->pg_ctl_options, 0, sizeof(options->pg_ctl_options)); + memset(options->service_stop_command, 0, sizeof(options->service_stop_command)); + memset(options->service_start_command, 0, sizeof(options->service_start_command)); + memset(options->service_restart_command, 0, sizeof(options->service_restart_command)); + memset(options->service_reload_command, 0, sizeof(options->service_reload_command)); + memset(options->service_promote_command, 0, sizeof(options->service_promote_command)); + + /* event notification settings + * --------------------------- */ + memset(options->event_notification_command, 0, sizeof(options->event_notification_command)); + options->event_notifications.head = NULL; + options->event_notifications.tail = NULL; + + /* barman settings */ + memset(options->barman_server, 0, sizeof(options->barman_server)); + memset(options->barman_config, 0, sizeof(options->barman_config)); } diff --git a/config.h b/config.h index fbbe3ba2..bd9adbbc 100644 --- a/config.h +++ b/config.h @@ -8,26 +8,23 @@ #ifndef _REPMGR_CONFIG_H_ #define _REPMGR_CONFIG_H_ -typedef struct +#define CONFIG_FILE_NAME "repmgr.conf" +#define MAXLINELENGTH 4096 +extern bool config_file_found; + + +typedef struct EventNotificationListCell { - int node_id; - char node_name[MAXLEN]; - char loglevel[MAXLEN]; - char logfacility[MAXLEN]; - char logfile[MAXLEN]; + struct EventNotificationListCell *next; + char event_type[MAXLEN]; +} EventNotificationListCell; -} t_configuration_options; +typedef struct EventNotificationList +{ + EventNotificationListCell *head; + EventNotificationListCell *tail; +} EventNotificationList; -/* - * The following will initialize the structure with a minimal set of options; - * actual defaults are set in parse_config() before parsing the configuration file - */ - -#define T_CONFIGURATION_OPTIONS_INITIALIZER { \ - /* node settings */ \ - UNKNOWN_NODE_ID, "", \ - /* log settings */ \ - "", "", ""} typedef struct ItemListCell { @@ -42,6 +39,99 @@ typedef struct ItemList } ItemList; +typedef struct TablespaceListCell +{ + struct TablespaceListCell *next; + char old_dir[MAXPGPATH]; + char new_dir[MAXPGPATH]; +} TablespaceListCell; + +typedef struct TablespaceList +{ + TablespaceListCell *head; + TablespaceListCell *tail; +} TablespaceList; + + +typedef struct +{ + /* node information */ + int node_id; + int upstream_node_id; + char node_name[MAXLEN]; + char conninfo[MAXLEN]; + char pg_bindir[MAXLEN]; + + /* log settings */ + char loglevel[MAXLEN]; + char logfacility[MAXLEN]; + char logfile[MAXLEN]; + + /* standby clone settings */ + bool use_replication_slots; + char rsync_options[MAXLEN]; + char ssh_options[MAXLEN]; + char pg_basebackup_options[MAXLEN]; + char restore_command[MAXLEN]; + TablespaceList tablespace_mapping; + + /* repmgrd settings */ + int failover_mode; + int priority; + char promote_command[MAXLEN]; + char follow_command[MAXLEN]; + int monitor_interval_secs; + int master_response_timeout; + int reconnect_attempts; + int reconnect_interval; + int retry_promote_interval_secs; + bool monitoring_history; + + /* witness settings */ + int witness_repl_nodes_sync_interval_secs; + + /* service settings */ + char pg_ctl_options[MAXLEN]; + char service_stop_command[MAXLEN]; + char service_start_command[MAXLEN]; + char service_restart_command[MAXLEN]; + char service_reload_command[MAXLEN]; + char service_promote_command[MAXLEN]; + + /* event notification settings */ + char event_notification_command[MAXLEN]; + EventNotificationList event_notifications; + + /* barman settings */ + char barman_server[MAXLEN]; + char barman_config[MAXLEN]; +} t_configuration_options; + +/* + * The following will initialize the structure with a minimal set of options; + * actual defaults are set in parse_config() before parsing the configuration file + */ + +#define T_CONFIGURATION_OPTIONS_INITIALIZER { \ + /* node information */ \ + UNKNOWN_NODE_ID, NO_UPSTREAM_NODE, "", "", "", \ + /* log settings */ \ + "", "", "", \ + /* standby clone settings */ \ + false, "", "", "", { NULL, NULL }, \ + /* repmgrd settings */ \ + MANUAL_FAILOVER, DEFAULT_PRIORITY, "", "", 2, 60, 6, 10, 300, false \ + /* witness settings */ \ + 30, \ + /* service settings */ \ + "", "", "", "", "", "", \ + /* event notification settings */ \ + "", { NULL, NULL }, \ + /* barman settings */ \ + "", "" } + + + void set_progname(const char *argv0); const char *progname(void); diff --git a/repmgr.h b/repmgr.h index 263d34bb..cdc50a87 100644 --- a/repmgr.h +++ b/repmgr.h @@ -24,4 +24,9 @@ #define NO_UPSTREAM_NODE -1 #define UNKNOWN_NODE_ID -1 +#define MANUAL_FAILOVER 0 +#define AUTOMATIC_FAILOVER 1 +#define DEFAULT_PRIORITY 100 +#define FAILOVER_NODES_MAX_CHECK 50 + #endif