diff --git a/Makefile.in b/Makefile.in index 4c7bae57..68ad31be 100644 --- a/Makefile.in +++ b/Makefile.in @@ -59,8 +59,11 @@ $(info Building against PostgreSQL $(MAJORVERSION)) REPMGR_CLIENT_OBJS = repmgr-client.o \ repmgr-action-primary.o repmgr-action-standby.o repmgr-action-witness.o \ repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.o \ - configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o dbutils.o sysutils.o -REPMGRD_OBJS = repmgrd.o repmgrd-physical.o configfile.o configfile-scan.o log.o dbutils.o strutil.o controldata.o compat.o sysutils.o + configdata.o configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o \ + dbutils.o sysutils.o +REPMGRD_OBJS = repmgrd.o repmgrd-physical.o configdata.o configfile.o configfile-scan.o log.o \ + dbutils.o strutil.o controldata.o compat.o sysutils.o + DATE=$(shell date "+%Y-%m-%d") repmgr_version.h: repmgr_version.h.in diff --git a/configdata.c b/configdata.c new file mode 100644 index 00000000..037287d9 --- /dev/null +++ b/configdata.c @@ -0,0 +1,880 @@ +/* + * configdata.c - contains structs with parsed configuration data + * + * Copyright (c) 2ndQuadrant, 2010-2020 + * + * 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 "configfile.h" + +/* + * Parsed configuration settings are stored here + */ +t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER; + + +/* + * Configuration settings are defined here + */ + +struct ConfigFileSetting config_file_settings[] = +{ + + /* ================ + * node information + * ================ + */ + /* node_id */ + { + "node_id", + CONFIG_INT, + { .intptr = &config_file_options.node_id }, + { .intdefault = UNKNOWN_NODE_ID }, + { .intminval = MIN_NODE_ID }, + {}, + {} + }, + /* node_name */ + { + "node_name", + CONFIG_STRING, + { .strptr = config_file_options.node_name }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.node_name) }, + {} + }, + /* conninfo */ + { + "conninfo", + CONFIG_STRING, + { .strptr = config_file_options.conninfo }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.conninfo) }, + {} + }, + /* replication_user */ + { + "replication_user", + CONFIG_STRING, + { .strptr = config_file_options.replication_user }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.replication_user) }, + {} + }, + /* data_directory */ + { + "data_directory", + CONFIG_STRING, + { .strptr = config_file_options.data_directory }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.data_directory) }, + { .postprocess_func = &repmgr_canonicalize_path } + }, + /* config_directory */ + { + "config_directory", + CONFIG_STRING, + { .strptr = config_file_options.config_directory }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.config_directory) }, + { .postprocess_func = &repmgr_canonicalize_path } + }, + /* pg_bindir */ + { + "pg_bindir", + CONFIG_STRING, + { .strptr = config_file_options.pg_bindir }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.pg_bindir) }, + { .postprocess_func = &repmgr_canonicalize_path } + }, + /* repmgr_bindir */ + { + "repmgr_bindir", + CONFIG_STRING, + { .strptr = config_file_options.repmgr_bindir }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.repmgr_bindir) }, + { .postprocess_func = &repmgr_canonicalize_path } + }, + /* replication_type */ + { + "replication_type", + CONFIG_INT, + { .intptr = &config_file_options.replication_type }, + { .intdefault = REPLICATION_TYPE_PHYSICAL }, + { .intminval = -1 }, + {}, + {} + }, + + /* ================ + * logging settings + * ================ + */ + /* log_level */ + { + "log_level", + CONFIG_STRING, + { .strptr = config_file_options.log_level }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.log_level) }, + {} + }, + /* log_facility */ + { + "log_facility", + CONFIG_STRING, + { .strptr = config_file_options.log_facility }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.log_facility) }, + {} + }, + /* log_file */ + { + "log_file", + CONFIG_STRING, + { .strptr = config_file_options.log_file }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.log_file) }, + { .postprocess_func = &repmgr_canonicalize_path } + }, + /* log_status_interval */ + { + "log_status_interval", + CONFIG_INT, + { .intptr = &config_file_options.log_status_interval }, + { .intdefault = DEFAULT_LOG_STATUS_INTERVAL, }, + { .intminval = 0 }, + {}, + {} + }, + /* ====================== + * standby clone settings + * ====================== + */ + /* use_replication_slots */ + { + "use_replication_slots", + CONFIG_BOOL, + { .boolptr = &config_file_options.use_replication_slots }, + { .booldefault = false }, + {}, + {}, + {} + }, + /* pg_basebackup_options */ + { + "pg_basebackup_options", + CONFIG_STRING, + { .strptr = config_file_options.pg_basebackup_options }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.pg_basebackup_options) }, + {} + }, + /* restore_command */ + { + "restore_command", + CONFIG_STRING, + { .strptr = config_file_options.restore_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.restore_command) }, + {} + }, + /* tablespace_mapping */ + { + "tablespace_mapping", + CONFIG_TABLESPACE_MAPPING, + { .tablespacemappingptr = &config_file_options.tablespace_mapping }, + {}, + {}, + {}, + {} + }, + /* recovery_min_apply_delay */ + { + "recovery_min_apply_delay", + CONFIG_STRING, + { .strptr = config_file_options.recovery_min_apply_delay }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.recovery_min_apply_delay) }, + { + .process_func = &parse_time_unit_parameter, + .providedptr = &config_file_options.recovery_min_apply_delay_provided + } + }, + + /* archive_cleanup_command */ + { + "archive_cleanup_command", + CONFIG_STRING, + { .strptr = config_file_options.archive_cleanup_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.archive_cleanup_command) }, + {} + }, + + /* use_primary_conninfo_password */ + { + "use_primary_conninfo_password", + CONFIG_BOOL, + { .boolptr = &config_file_options.use_primary_conninfo_password }, + { .booldefault = false }, + {}, + {}, + {} + }, + /* passfile */ + // XXX canonicalize path? + { + "passfile", + CONFIG_STRING, + { .strptr = config_file_options.passfile }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.passfile) }, + {} + }, + + /* ====================== + * standby clone settings + * ====================== + */ + /* promote_check_timeout */ + { + "promote_check_timeout", + CONFIG_INT, + { .intptr = &config_file_options.promote_check_timeout }, + { .intdefault = DEFAULT_PROMOTE_CHECK_TIMEOUT }, + { .intminval = 1 }, + {}, + {} + }, + /* promote_check_interval */ + { + "promote_check_interval", + CONFIG_INT, + { .intptr = &config_file_options.promote_check_interval }, + { .intdefault = DEFAULT_PROMOTE_CHECK_INTERVAL }, + { .intminval = 1 }, + {}, + {} + }, + + /* ======================= + * standby follow settings + * ======================= + */ + /* primary_follow_timeout */ + { + "primary_follow_timeout", + CONFIG_INT, + { .intptr = &config_file_options.primary_follow_timeout }, + { .intdefault = DEFAULT_PRIMARY_FOLLOW_TIMEOUT, }, + { .intminval = 1 }, + {}, + {} + }, + /* standby_follow_timeout */ + { + "standby_follow_timeout", + CONFIG_INT, + { .intptr = &config_file_options.standby_follow_timeout }, + { .intdefault = DEFAULT_STANDBY_FOLLOW_TIMEOUT }, + { .intminval = 1 }, + {}, + {} + }, + + /* =========================== + * standby switchover settings + * =========================== + */ + /* shutdown_check_timeout */ + { + "shutdown_check_timeout", + CONFIG_INT, + { .intptr = &config_file_options.shutdown_check_timeout }, + { .intdefault = DEFAULT_SHUTDOWN_CHECK_TIMEOUT }, + { .intminval = 1 }, + {}, + {} + }, + /* standby_reconnect_timeout */ + { + "standby_reconnect_timeout", + CONFIG_INT, + { .intptr = &config_file_options.standby_reconnect_timeout }, + { .intdefault = DEFAULT_STANDBY_RECONNECT_TIMEOUT }, + { .intminval = 1 }, + {}, + {} + }, + /* wal_receive_check_timeout */ + { + "wal_receive_check_timeout", + CONFIG_INT, + { .intptr = &config_file_options.wal_receive_check_timeout }, + { .intdefault = DEFAULT_WAL_RECEIVE_CHECK_TIMEOUT }, + { .intminval = 1 }, + {}, + {} + }, + + /* ==================== + * node rejoin settings + * ==================== + */ + /* node_rejoin_timeout */ + { + "node_rejoin_timeout", + CONFIG_INT, + { .intptr = &config_file_options.node_rejoin_timeout }, + { .intdefault = DEFAULT_NODE_REJOIN_TIMEOUT }, + { .intminval = 1 }, + {}, + {} + }, + /* =================== + * node check settings + * =================== + */ + /* archive_ready_warning */ + { + "archive_ready_warning", + CONFIG_INT, + { .intptr = &config_file_options.archive_ready_warning }, + { .intdefault = DEFAULT_ARCHIVE_READY_WARNING }, + { .intminval = 1 }, + {}, + {} + }, + /* archive_ready_critical */ + { + "archive_ready_critical", + CONFIG_INT, + { .intptr = &config_file_options.archive_ready_critical }, + { .intdefault = DEFAULT_ARCHIVE_READY_CRITICAL }, + { .intminval = 1 }, + {}, + {} + }, + /* replication_lag_warning */ + { + "replication_lag_warning", + CONFIG_INT, + { .intptr = &config_file_options.replication_lag_warning }, + { .intdefault = DEFAULT_REPLICATION_LAG_WARNING }, + { .intminval = 1 }, + {}, + {} + }, + /* replication_lag_critical */ + { + "replication_lag_critical", + CONFIG_INT, + { .intptr = &config_file_options.replication_lag_critical }, + { .intdefault = DEFAULT_REPLICATION_LAG_CRITICAL }, + { .intminval = 1 }, + {}, + {} + }, + + /* ================ + * witness settings + * ================ + */ + /* witness_sync_interval */ + { + "witness_sync_interval", + CONFIG_INT, + { .intptr = &config_file_options.witness_sync_interval }, + { .intdefault = DEFAULT_WITNESS_SYNC_INTERVAL }, + { .intminval = 1 }, + {}, + {} + }, + + /* ================ + * repmgrd settings + * ================ + */ + /* failover */ + { + "failover", + CONFIG_FAILOVER_MODE, + { .failovermodeptr = &config_file_options.failover }, + { .failovermodedefault = FAILOVER_MANUAL }, + {}, + {}, + {} + }, + /* location */ + { + "location", + CONFIG_STRING, + { .strptr = config_file_options.location }, + { .strdefault = DEFAULT_LOCATION }, + {}, + { .strmaxlen = sizeof(config_file_options.location) }, + {} + }, + /* priority */ + { + "priority", + CONFIG_INT, + { .intptr = &config_file_options.priority }, + { .intdefault = DEFAULT_PRIORITY, }, + { .intminval = 0 }, + {}, + {} + }, + /* promote_command */ + { + "promote_command", + CONFIG_STRING, + { .strptr = config_file_options.promote_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.promote_command) }, + {} + }, + /* follow_command */ + { + "follow_command", + CONFIG_STRING, + { .strptr = config_file_options.follow_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.follow_command) }, + {} + }, + /* monitor_interval_secs */ + { + "monitor_interval_secs", + CONFIG_INT, + { .intptr = &config_file_options.monitor_interval_secs }, + { .intdefault = DEFAULT_MONITORING_INTERVAL }, + { .intminval = 1 }, + {}, + {} + }, + /* reconnect_attempts */ + { + "reconnect_attempts", + CONFIG_INT, + { .intptr = &config_file_options.reconnect_attempts }, + { .intdefault = DEFAULT_RECONNECTION_ATTEMPTS }, + { .intminval = 1 }, + {}, + {} + }, + /* reconnect_interval */ + { + "reconnect_interval", + CONFIG_INT, + { .intptr = &config_file_options.reconnect_interval }, + { .intdefault = DEFAULT_RECONNECTION_INTERVAL }, + { .intminval = 1 }, + {}, + {} + }, + + /* monitoring_history */ + { + "monitoring_history", + CONFIG_BOOL, + { .boolptr = &config_file_options.monitoring_history }, + { .booldefault = false }, + {}, + {}, + {} + }, + /* degraded_monitoring_timeout */ + { + "degraded_monitoring_timeout", + CONFIG_INT, + { .intptr = &config_file_options.degraded_monitoring_timeout }, + { .intdefault = DEFAULT_DEGRADED_MONITORING_TIMEOUT }, + { .intminval = 1 }, + {}, + {} + }, + /* async_query_timeout */ + { + "async_query_timeout", + CONFIG_INT, + { .intptr = &config_file_options.async_query_timeout }, + { .intdefault = DEFAULT_ASYNC_QUERY_TIMEOUT }, + { .intminval = 0 }, + {}, + {} + }, + /* primary_notification_timeout */ + { + "primary_notification_timeout", + CONFIG_INT, + { .intptr = &config_file_options.primary_notification_timeout }, + { .intdefault = DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT }, + { .intminval = 0 }, + {}, + {} + }, + /* repmgrd_standby_startup_timeout */ + { + "repmgrd_standby_startup_timeout", + CONFIG_INT, + { .intptr = &config_file_options.repmgrd_standby_startup_timeout }, + { .intdefault = DEFAULT_REPMGRD_STANDBY_STARTUP_TIMEOUT }, + { .intminval = 0 }, + {}, + {} + }, + /* repmgrd_pid_file */ + { + "repmgrd_pid_file", + CONFIG_STRING, + { .strptr = config_file_options.repmgrd_pid_file }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.repmgrd_pid_file) }, + { .postprocess_func = &repmgr_canonicalize_path } + }, + /* standby_disconnect_on_failover */ + { + "standby_disconnect_on_failover", + CONFIG_BOOL, + { .boolptr = &config_file_options.standby_disconnect_on_failover }, + { .booldefault = false }, + {}, + {}, + {} + }, + /* sibling_nodes_disconnect_timeout */ + { + "sibling_nodes_disconnect_timeout", + CONFIG_INT, + { .intptr = &config_file_options.sibling_nodes_disconnect_timeout }, + { .intdefault = DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT }, + { .intminval = 0 }, + {}, + {} + }, + /* connection_check_type */ + { + "connection_check_type", + CONFIG_CONNECTION_CHECK_TYPE, + { .checktypeptr = &config_file_options.connection_check_type }, + { .checktypedefault = DEFAULT_CONNECTION_CHECK_TYPE }, + {}, + {}, + {} + }, + /* primary_visibility_consensus */ + { + "primary_visibility_consensus", + CONFIG_BOOL, + { .boolptr = &config_file_options.primary_visibility_consensus }, + // XXX constant + { .booldefault = false }, + {}, + {}, + {} + }, + /* failover_validation_command */ + { + "failover_validation_command", + CONFIG_STRING, + { .strptr = config_file_options.failover_validation_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.failover_validation_command) }, + {} + }, + /* election_rerun_interval */ + { + "election_rerun_interval", + CONFIG_INT, + { .intptr = &config_file_options.election_rerun_interval }, + { .intdefault = DEFAULT_ELECTION_RERUN_INTERVAL }, + { .intminval = 1 }, + {}, + {} + }, + /* child_nodes_check_interval */ + { + "child_nodes_check_interval", + CONFIG_INT, + { .intptr = &config_file_options.child_nodes_check_interval }, + { .intdefault = DEFAULT_CHILD_NODES_CHECK_INTERVAL }, + { .intminval = 1 }, + {}, + {} + }, + /* child_nodes_disconnect_min_count */ + { + "child_nodes_disconnect_min_count", + CONFIG_INT, + { .intptr = &config_file_options.child_nodes_disconnect_min_count }, + { .intdefault = DEFAULT_CHILD_NODES_DISCONNECT_MIN_COUNT }, + { .intminval = -1 }, + {}, + {} + }, + /* child_nodes_connected_min_count */ + { + "child_nodes_connected_min_count", + CONFIG_INT, + { .intptr = &config_file_options.child_nodes_connected_min_count }, + { .intdefault = DEFAULT_CHILD_NODES_CONNECTED_MIN_COUNT}, + { .intminval = -1 }, + {}, + {} + }, + /* child_nodes_connected_include_witness */ + { + "child_nodes_connected_include_witness", + CONFIG_BOOL, + { .boolptr = &config_file_options.child_nodes_connected_include_witness }, + { .booldefault = DEFAULT_CHILD_NODES_CONNECTED_INCLUDE_WITNESS }, + {}, + {}, + {} + }, + /* child_nodes_disconnect_timeout */ + { + "child_nodes_disconnect_timeout", + CONFIG_INT, + { .intptr = &config_file_options.child_nodes_disconnect_timeout }, + { .intdefault = DEFAULT_CHILD_NODES_DISCONNECT_TIMEOUT }, + { .intminval = 0 }, + {}, + {} + }, + /* child_nodes_disconnect_command */ + { + "child_nodes_disconnect_command", + CONFIG_STRING, + { .strptr = config_file_options.child_nodes_disconnect_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.child_nodes_disconnect_command) }, + {} + }, + /* ================ + * service settings + * ================ + */ + /* pg_ctl_options */ + { + "pg_ctl_options", + CONFIG_STRING, + { .strptr = config_file_options.pg_ctl_options }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.pg_ctl_options) }, + {} + }, + /* service_start_command */ + { + "service_start_command", + CONFIG_STRING, + { .strptr = config_file_options.service_start_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.service_start_command) }, + {} + }, + /* service_stop_command */ + { + "service_stop_command", + CONFIG_STRING, + { .strptr = config_file_options.service_stop_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.service_stop_command) }, + {} + }, + /* service_restart_command */ + { + "service_restart_command", + CONFIG_STRING, + { .strptr = config_file_options.service_restart_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.service_restart_command) }, + {} + }, + /* service_reload_command */ + { + "service_reload_command", + CONFIG_STRING, + { .strptr = config_file_options.service_reload_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.service_reload_command) }, + {} + }, + /* service_promote_command */ + { + "service_promote_command", + CONFIG_STRING, + { .strptr = config_file_options.service_promote_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.service_promote_command) }, + {} + }, + + /* ======================== + * repmgrd service settings + * ======================== + */ + /* repmgrd_service_start_command */ + { + "repmgrd_service_start_command", + CONFIG_STRING, + { .strptr = config_file_options.repmgrd_service_start_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.repmgrd_service_start_command) }, + {} + }, + /* repmgrd_service_stop_command */ + { + "repmgrd_service_stop_command", + CONFIG_STRING, + { .strptr = config_file_options.repmgrd_service_stop_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.repmgrd_service_stop_command) }, + {} + }, + /* =========================== + * event notification settings + * =========================== + */ + /* event_notification_command */ + { + "event_notification_command", + CONFIG_STRING, + { .strptr = config_file_options.event_notification_command }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.event_notification_command) }, + {} + }, + { + "event_notifications", + CONFIG_EVENT_NOTIFICATION_LIST, + { .notificationlistptr = &config_file_options.event_notifications }, + {}, + {}, + {}, + {} + }, + /* =============== + * barman settings + * =============== + */ + /* barman_host */ + { + "barman_host", + CONFIG_STRING, + { .strptr = config_file_options.barman_host }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.barman_host) }, + {} + }, + /* barman_server */ + { + "barman_server", + CONFIG_STRING, + { .strptr = config_file_options.barman_server }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.barman_server) }, + {} + }, + /* barman_config */ + { + "barman_config", + CONFIG_STRING, + { .strptr = config_file_options.barman_config }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.barman_config) }, + {} + }, + /* ================== + * rsync/ssh settings + * ================== + */ + /* rsync_options */ + { + "rsync_options", + CONFIG_STRING, + { .strptr = config_file_options.rsync_options }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.rsync_options) }, + {} + }, + /* ssh_options */ + { + "ssh_options", + CONFIG_STRING, + { .strptr = config_file_options.ssh_options }, + { .strdefault = "" }, + {}, + { .strmaxlen = sizeof(config_file_options.ssh_options) }, + {} + }, + /* ========================== + * undocumented test settings + * ========================== + */ + /* promote_delay */ + { + "promote_delay", + CONFIG_INT, + { .intptr = &config_file_options.promote_delay }, + { .intdefault = 0 }, + { .intminval = 1 }, + {}, + {} + }, + /* End-of-list marker */ + { + NULL, CONFIG_INT, {}, {}, {}, {}, {} + } +}; + diff --git a/configfile-scan.l b/configfile-scan.l index 72cc1198..1e841585 100644 --- a/configfile-scan.l +++ b/configfile-scan.l @@ -40,11 +40,11 @@ static sigjmp_buf *CONF_flex_fatal_jmp; static char *CONF_scanstr(const char *s); static int CONF_flex_fatal(const char *msg); -static bool ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list); +static bool ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ConfigFileSetting *options2, ItemList *error_list, ItemList *warning_list); -static bool ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list); +static bool ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ConfigFileSetting *options2, ItemList *error_list, ItemList *warning_list); -static bool ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list); +static bool ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ConfigFileSetting *options2, ItemList *error_list, ItemList *warning_list); static char *AbsoluteConfigLocation(const char *base_dir, const char *location, const char *calling_file); @@ -120,7 +120,7 @@ ProcessPostgresConfigFile(const char *config_file, const char *base_dir, KeyValu } static bool -ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list) +ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ConfigFileSetting *options2, ItemList *error_list, ItemList *warning_list) { char *abs_path; bool success = true; @@ -168,7 +168,7 @@ ProcessConfigFile(const char *base_dir, const char *config_file, const char *cal } static bool -ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list) +ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ConfigFileSetting *options2, ItemList *error_list, ItemList *warning_list) { volatile bool OK = true; volatile YY_BUFFER_STATE lex_buffer = NULL; @@ -376,7 +376,7 @@ cleanup: * See ProcessConfigFp for further details. */ static bool -ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list) +ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ConfigFileSetting *options2, ItemList *error_list, ItemList *warning_list) { char *directory; DIR *d; diff --git a/configfile.c b/configfile.c index fdabe903..e64cda86 100644 --- a/configfile.c +++ b/configfile.c @@ -33,98 +33,6 @@ const static char *_progname = NULL; char config_file_path[MAXPGPATH] = ""; static bool config_file_provided = false; bool config_file_found = false; -t_configuration_options config_file_options; - - -t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER; - -struct ConfigFileOption config_file_options2[] = -{ - - /* ================ - * node information - * ================ - */ - /* node_id */ - { - "node_id", - CONFIG_INT, - { .intptr = &config_file_options.node_id }, - { .intdefault = UNKNOWN_NODE_ID }, - MIN_NODE_ID, - -1 - }, - /* node_name */ - { - "node_name", - CONFIG_STRING, - { .strptr = config_file_options.node_name }, - { .strdefault = NULL }, - -1, - sizeof(config_file_options.node_name) - }, - - /* ====================== - * standby clone settings - * ====================== - */ - /* use_replication_slots */ - { - "use_replication_slots", - CONFIG_BOOL, - { .boolptr = &config_file_options.use_replication_slots }, - { .booldefault = false }, - -1, - -1 - }, - /* tablespace_mapping */ - { - "tablespace_mapping", - CONFIG_TABLESPACE_MAPPING, - { .tablespacemappingptr = &config_file_options.tablespace_mapping }, - {}, - -1, - -1 - }, - /* ================ - * repmgrd settings - * ================ - */ - /* failover */ - { - "failover", - CONFIG_FAILOVER_MODE, - { .failovermodeptr = &config_file_options.failover }, - { .failovermodedefault = FAILOVER_MANUAL }, - -1, - -1 - }, - /* connection_check_type */ - { - "connection_check_type", - CONFIG_CONNECTION_CHECK_TYPE, - { .checktypeptr = &config_file_options.connection_check_type }, - { .checktypedefault = CHECK_PING }, - -1, - -1 - }, - /* =========================== - * event notification settings - * =========================== - */ - { - "event_notifications", - CONFIG_EVENT_NOTIFICATION_LIST, - { .notificationlistptr = &config_file_options.event_notifications }, - {}, - -1, - -1 - }, - /* End-of-list marker */ - { - NULL, CONFIG_INT, {}, {}, -1, -1 - } -}; static void parse_config(bool terse); @@ -137,8 +45,6 @@ static void _parse_line(char *buf, char *name, char *value); static void parse_event_notifications_list(EventNotificationList *event_notifications, const char *arg); static void clear_event_notification_list(EventNotificationList *event_notifications); -static void parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemList *errors); - static void copy_config_file_options(t_configuration_options *original, t_configuration_options *copy); static void tablespace_list_append(TablespaceList *tablespace_mapping, const char *arg); @@ -632,41 +538,41 @@ _parse_config2(ItemList *error_list, ItemList *warning_list) // ... { - ConfigFileOption *option = &config_file_options2[0]; + ConfigFileSetting *setting = &config_file_settings[0]; int i = 0; do { - switch (option->type) + switch (setting->type) { case CONFIG_INT: - printf(" %s: %i\n", option->name, *option->val.intptr); + printf(" %s: %i\n", setting->name, *setting->val.intptr); break; case CONFIG_STRING: - printf(" %s: %s\n", option->name, option->val.strptr); + printf(" %s: %s\n", setting->name, setting->val.strptr); break; case CONFIG_BOOL: - printf(" %s: %s\n", option->name, format_bool(*option->val.boolptr)); + printf(" %s: %s\n", setting->name, format_bool(*setting->val.boolptr)); break; case CONFIG_FAILOVER_MODE: - printf(" %s: %s\n", option->name, format_failover_mode(*option->val.failovermodeptr)); + printf(" %s: %s\n", setting->name, format_failover_mode(*setting->val.failovermodeptr)); break; case CONFIG_CONNECTION_CHECK_TYPE: - printf(" %s: %s\n", option->name, print_connection_check_type(*option->val.checktypeptr)); + printf(" %s: %s\n", setting->name, print_connection_check_type(*setting->val.checktypeptr)); break; case CONFIG_EVENT_NOTIFICATION_LIST: { - char *list_str = print_event_notification_list(option->val.notificationlistptr); - printf(" %s: %s\n", option->name, list_str); + char *list_str = print_event_notification_list(setting->val.notificationlistptr); + printf(" %s: %s\n", setting->name, list_str); pfree(list_str); break; } case CONFIG_TABLESPACE_MAPPING: { TablespaceListCell *cell; - for (cell = option->val.tablespacemappingptr->head; cell; cell = cell->next) + for (cell = setting->val.tablespacemappingptr->head; cell; cell = cell->next) { printf(" %s: %s=%s\n", - option->name, + setting->name, cell->old_dir, cell->new_dir); } @@ -674,8 +580,8 @@ _parse_config2(ItemList *error_list, ItemList *warning_list) } } i++; - option = &config_file_options2[i]; - } while (option->name != NULL); + setting = &config_file_settings[i]; + } while (setting->name != NULL); } } @@ -683,34 +589,73 @@ _parse_config2(ItemList *error_list, ItemList *warning_list) void parse_configuration_item2(ItemList *error_list, ItemList *warning_list, const char *name, const char *value) { - ConfigFileOption *option = &config_file_options2[0]; + ConfigFileSetting *setting = &config_file_settings[0]; int i = 0; do { - if (strcmp(name, option->name) == 0) + if (strcmp(name, setting->name) == 0) { - //printf("%s = '%s'\n", name, value); - - switch (option->type) + switch (setting->type) { - case CONFIG_INT: - *(int *)option->val.intptr = repmgr_atoi(value, name, error_list, option->minval); - break; - case CONFIG_STRING: - strncpy((char *)option->val.strptr, value, option->strmaxlen); - break; + /* Generic types */ case CONFIG_BOOL: - *(bool *)option->val.boolptr = parse_bool(value, name, error_list); + { + *(bool *)setting->val.boolptr = parse_bool(value, name, error_list); break; + } + case CONFIG_INT: + { + *(int *)setting->val.intptr = repmgr_atoi(value, name, error_list, setting->minval.intminval); + break; + } + case CONFIG_STRING: + { + if (strlen(value) > setting->maxval.strmaxlen) + { + item_list_append_format(error_list, + _("value for \"%s\" must contain fewer than %i characters (current length: %i)"), + name, + setting->maxval.strmaxlen, + (int)strlen(value)); + } + else + { + /* custom function for processing this string value */ + if (setting->process.process_func != NULL) + { + (*setting->process.process_func)(name, value, (char *)setting->val.strptr, error_list); + } + /* otherwise copy as-is */ + else + { + strncpy((char *)setting->val.strptr, value, setting->maxval.strmaxlen); + } + + /* post-processing, e.g. path canonicalisation */ + if (setting->process.postprocess_func != NULL) + { + (*setting->process.postprocess_func)(name, value, (char *)setting->val.strptr, error_list); + } + + if (setting->process.providedptr != NULL) + { + *(bool *)setting->process.providedptr = true; + } + } + break; + } + + + /* repmgr types */ case CONFIG_FAILOVER_MODE: { if (strcmp(value, "manual") == 0) { - *(failover_mode_opt *)option->val.failovermodeptr = FAILOVER_MANUAL; + *(failover_mode_opt *)setting->val.failovermodeptr = FAILOVER_MANUAL; } else if (strcmp(value, "automatic") == 0) { - *(failover_mode_opt *)option->val.failovermodeptr = FAILOVER_AUTOMATIC; + *(failover_mode_opt *)setting->val.failovermodeptr = FAILOVER_AUTOMATIC; } else { @@ -724,15 +669,15 @@ parse_configuration_item2(ItemList *error_list, ItemList *warning_list, const ch { if (strcasecmp(value, "ping") == 0) { - *(ConnectionCheckType *)option->val.checktypeptr = CHECK_PING; + *(ConnectionCheckType *)setting->val.checktypeptr = CHECK_PING; } else if (strcasecmp(value, "connection") == 0) { - *(ConnectionCheckType *)option->val.checktypeptr = CHECK_CONNECTION; + *(ConnectionCheckType *)setting->val.checktypeptr = CHECK_CONNECTION; } else if (strcasecmp(value, "query") == 0) { - *(ConnectionCheckType *)option->val.checktypeptr = CHECK_QUERY; + *(ConnectionCheckType *)setting->val.checktypeptr = CHECK_QUERY; } else { @@ -744,28 +689,31 @@ parse_configuration_item2(ItemList *error_list, ItemList *warning_list, const ch } case CONFIG_EVENT_NOTIFICATION_LIST: { - parse_event_notifications_list((EventNotificationList *)&option->val.notificationlistptr, + parse_event_notifications_list((EventNotificationList *)&setting->val.notificationlistptr, value); break; } case CONFIG_TABLESPACE_MAPPING: { - tablespace_list_append((TablespaceList *)option->val.tablespacemappingptr, value); + tablespace_list_append((TablespaceList *)setting->val.tablespacemappingptr, value); break; } default: + /* this should never happen */ log_error("encountered unknown configuration type %i when processing \"%s\"", - (int)option->type, - option->name); + (int)setting->type, + setting->name); } + /* Configuration item found - we can stop processing here */ + return; } i++; - option = &config_file_options2[i]; - } while (option->name); - + setting = &config_file_settings[i]; + } while (setting->name); /* If we reach here, the configuration item is either deprecated or unknown */ + if (strcmp(name, "cluster") == 0) { item_list_append(warning_list, @@ -808,10 +756,9 @@ parse_configuration_item2(ItemList *error_list, ItemList *warning_list, const ch } else { - // why not just append to the warning list? - //log_warning(_("%s/%s: unknown name/value pair provided; ignoring"), name, value); + item_list_append_format(warning_list, + _("%s='%s': unknown name/value pair provided; ignoring"), name, value); } - } /* @@ -1157,6 +1104,15 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, { strncpy(options->conninfo, value, MAXLEN); } + else if (strcmp(name, "replication_user") == 0) + { + if (strlen(value) < sizeof(options->replication_user)) + strncpy(options->replication_user, value, sizeof(options->replication_user)); + else + item_list_append_format(error_list, + _("value for \"replication_user\" must contain fewer than %lu characters"), + sizeof(options->replication_user)); + } else if (strcmp(name, "data_directory") == 0) { strncpy(options->data_directory, value, MAXPGPATH); @@ -1167,15 +1123,7 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, strncpy(options->config_directory, value, MAXPGPATH); canonicalize_path(options->config_directory); } - else if (strcmp(name, "replication_user") == 0) - { - if (strlen(value) < sizeof(options->replication_user)) - strncpy(options->replication_user, value, sizeof(options->replication_user)); - else - item_list_append_format(error_list, - _("value for \"replication_user\" must contain fewer than %lu characters"), - sizeof(options->replication_user)); - } + else if (strcmp(name, "pg_bindir") == 0) strncpy(options->pg_bindir, value, MAXPGPATH); else if (strcmp(name, "repmgr_bindir") == 0) @@ -1190,12 +1138,12 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, } /* log settings */ - else if (strcmp(name, "log_file") == 0) - strncpy(options->log_file, value, MAXLEN); else if (strcmp(name, "log_level") == 0) strncpy(options->log_level, value, MAXLEN); else if (strcmp(name, "log_facility") == 0) strncpy(options->log_facility, value, MAXLEN); + else if (strcmp(name, "log_file") == 0) + strncpy(options->log_file, value, MAXLEN); else if (strcmp(name, "log_status_interval") == 0) options->log_status_interval = repmgr_atoi(value, name, error_list, 0); @@ -1204,10 +1152,11 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, options->use_replication_slots = parse_bool(value, name, error_list); else if (strcmp(name, "pg_basebackup_options") == 0) strncpy(options->pg_basebackup_options, value, MAXLEN); - else if (strcmp(name, "tablespace_mapping") == 0) - tablespace_list_append(&options->tablespace_mapping, value); else if (strcmp(name, "restore_command") == 0) strncpy(options->restore_command, value, MAXLEN); + else if (strcmp(name, "tablespace_mapping") == 0) + tablespace_list_append(&options->tablespace_mapping, value); + else if (strcmp(name, "recovery_min_apply_delay") == 0) { parse_time_unit_parameter(name, value, options->recovery_min_apply_delay, error_list); @@ -1272,10 +1221,10 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, _("value for \"failover\" must be \"automatic\" or \"manual\"\n")); } } - else if (strcmp(name, "priority") == 0) - options->priority = repmgr_atoi(value, name, error_list, 0); else if (strcmp(name, "location") == 0) strncpy(options->location, value, sizeof(options->location)); + else if (strcmp(name, "priority") == 0) + options->priority = repmgr_atoi(value, name, error_list, 0); else if (strcmp(name, "promote_command") == 0) strncpy(options->promote_command, value, sizeof(options->promote_command)); else if (strcmp(name, "follow_command") == 0) @@ -1330,8 +1279,6 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, options->election_rerun_interval = repmgr_atoi(value, name, error_list, 0); else if (strcmp(name, "child_nodes_check_interval") == 0) options->child_nodes_check_interval = repmgr_atoi(value, name, error_list, 1); - else if (strcmp(name, "child_nodes_disconnect_command") == 0) - snprintf(options->child_nodes_disconnect_command, sizeof(options->child_nodes_disconnect_command), "%s", value); else if (strcmp(name, "child_nodes_disconnect_min_count") == 0) options->child_nodes_disconnect_min_count = repmgr_atoi(value, name, error_list, -1); else if (strcmp(name, "child_nodes_connected_min_count") == 0) @@ -1340,6 +1287,8 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, options->child_nodes_connected_include_witness = parse_bool(value, name, error_list); else if (strcmp(name, "child_nodes_disconnect_timeout") == 0) options->child_nodes_disconnect_timeout = repmgr_atoi(value, name, error_list, 0); + else if (strcmp(name, "child_nodes_disconnect_command") == 0) + snprintf(options->child_nodes_disconnect_command, sizeof(options->child_nodes_disconnect_command), "%s", value); /* witness settings */ else if (strcmp(name, "witness_sync_interval") == 0) @@ -1599,7 +1548,7 @@ _parse_line(char *buf, char *name, char *value) } -static void +void parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemList *errors) { char *ptr = NULL; @@ -1610,7 +1559,8 @@ parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemL if (errors != NULL) { item_list_append_format(errors, - _("invalid value provided for \"%s\""), + _("invalid value \"%s\" provided for \"%s\""), + value, name); } return; @@ -1626,8 +1576,9 @@ parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemL { item_list_append_format( errors, - _("value provided for \"%s\" must be one of ms/s/min/h/d"), - name); + _("value for \"%s\" must be one of ms/s/min/h/d (provided: \"%s\")"), + name, + value); return; } } @@ -2285,6 +2236,13 @@ repmgr_atoi(const char *value, const char *config_item, ItemList *error_list, in return (int32) longval; } +void +repmgr_canonicalize_path(const char *name, const char *value, char *config_item, ItemList *errors) +{ + // XXX check for errors? + canonicalize_path(config_item); +} + /* * Interpret a parameter value as a boolean. Currently accepts: diff --git a/configfile.h b/configfile.h index de1339ea..1444bfb4 100644 --- a/configfile.h +++ b/configfile.h @@ -90,7 +90,7 @@ typedef enum } ConfigItemType; -typedef struct ConfigFileOption +typedef struct ConfigFileSetting { const char *name; ConfigItemType type; @@ -111,9 +111,21 @@ typedef struct ConfigFileOption failover_mode_opt failovermodedefault; ConnectionCheckType *checktypedefault; } defval; - int minval; - int strmaxlen; -} ConfigFileOption; + union { + int intminval; + } minval; + union { + int strmaxlen; + } maxval; + struct { + void (*process_func)(const char *, const char *, char *, ItemList *errors); + void (*postprocess_func)(const char *, const char *, char *, ItemList *errors); + bool *providedptr; + } process; +} ConfigFileSetting; + +/* Declare the main configfile structure for client applications */ +extern ConfigFileSetting config_file_settings[]; typedef struct { @@ -376,6 +388,9 @@ int repmgr_atoi(const char *s, ItemList *error_list, int minval); +void parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemList *errors); +void repmgr_canonicalize_path(const char *name, const char *value, char *config_item, ItemList *errors); + bool parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_options *backup_options, int server_version_num, diff --git a/repmgr.h b/repmgr.h index ed1103e6..9bf03711 100644 --- a/repmgr.h +++ b/repmgr.h @@ -106,8 +106,11 @@ #define DEFAULT_RECONNECTION_ATTEMPTS 6 /* seconds */ #define DEFAULT_RECONNECTION_INTERVAL 10 /* seconds */ #define DEFAULT_MONITORING_INTERVAL 2 /* seconds */ +#define DEFAULT_DEGRADED_MONITORING_TIMEOUT -1 /* seconds */ #define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */ #define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */ +#define DEFAULT_REPMGRD_STANDBY_STARTUP_TIMEOUT -1 /*seconds */ +#define DEFAULT_CONNECTION_CHECK_TYPE CHECK_PING #define DEFAULT_PRIMARY_FOLLOW_TIMEOUT 60 /* seconds */ #define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */ #define DEFAULT_ARCHIVE_READY_WARNING 16 /* WAL files */