From aab6eaa1cc3b1dc8b746da52f89ace2f42ca0704 Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Tue, 30 Aug 2011 23:46:44 -0300 Subject: [PATCH] Created a class to hold configuration options and parsing inteligence - it does not know about where the configuration came from --- src/config/configurationoptions.cpp | 379 +++++++++++++++++++++++++++++++++++ src/config/configurationoptions.h | 101 +++++++++ 2 files changed, 480 insertions(+), 0 deletions(-) create mode 100644 src/config/configurationoptions.cpp create mode 100644 src/config/configurationoptions.h diff --git a/src/config/configurationoptions.cpp b/src/config/configurationoptions.cpp new file mode 100644 index 0000000..129abf4 --- /dev/null +++ b/src/config/configurationoptions.cpp @@ -0,0 +1,379 @@ +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + */ + +#include "config/configurationoptions.h" + +#include + +#include +#include + +#include + +using namespace std; +using boost::program_options::options_description; +using boost::program_options::value; +using boost::program_options::variables_map; +using I2n::Logger::GlobalLogger; + +//----------------------------------------------------------------------------- +// ConfigurationOptions +//----------------------------------------------------------------------------- + +/** + * @brief Default constructor. + */ +ConfigurationOptions::ConfigurationOptions() : + HelpCmdStr( "help" ), + HelpCmdDesc( "Print this help and exit." ), + VersionCmdStr( "version" ), + VersionCmdDesc( "Print the version string and exit." ), + DaemonCmdStr( "daemon" ), + DaemonCmdDesc( "Run the evil in background." ), + DefaultConfigFileName( "/etc/pingcheck.conf" ), + ConfigFileCmdStr( "config-file" ), + ConfigFileCmdDesc( "Name of the configuration file." ), + SourceNetworkInterfaceCmdStr( "source-network-interface" ), + SourceNetworkInterfaceCmdDesc( "The network interface from where the packets will be received and originated" ), + DefaultNameServer( "127.0.0.1" ), + NameServerCmdStr( "nameserver" ), + NameServerCmdDesc( "The local address from where the DNS query will be made." ), + PingProtocolCmdStr( "ping-protocol" ), + PingProtocolCmdDesc( "Defines which protocol will be used to ping the destination." ), + DefaultHostsDownLimit( 0 ), // no host down + HostsDownLimitCmdStr( "hosts-down-limit" ), + HostsDownLimitCmdDesc( "Limit of host that have to be down in order to notify." ), + DefaultPingFailLimit( 50 ), // 50 pings can fail at most + PingFailLimitCmdStr( "ping-fail-limit" ), + PingFailLimitCmdDesc( "Maximum percentage of pings that can fail for a given host." ), + StatusNotifierCmdCmdStr( "status-notifier-cmd" ), + StatusNotifierCmdCmdDesc( "The command to execute to alert about host status." ), + DefaultLinkUpIntervalInMin( 5 ), // 5 minutes + LinkUpIntervalCmdStr( "link-up-interval" ), + LinkUpIntervalCmdDesc( "How long the link must be responsive in order to consider it stable." ), + DefaultLinkDownIntervalInMin( 2 ), // 2 minutes + LinkDownIntervalCmdStr( "link-down-interval" ), + LinkDownIntervalCmdDesc( "How long the link must be offline in order to consider it down." ), + HostNameCmdStr( "host.name" ), + HostNameCmdDesc( "Host address" ), + DefaultHostPort( 80 ), // HTTP port + HostPortCmdStr( "host.port" ), + HostPortCmdDesc( "Host port number" ), + DefaultHostIntervalInSec( 60 ), // 60 seconds + HostIntervalCmdStr( "host.interval" ), + HostIntervalCmdDesc( "Interval between each ping to the host" ) +{ +} + +/** + * @brief Destructor. + */ +ConfigurationOptions::~ConfigurationOptions() +{ +} + +/** + * @brief TODO + * + * @return + */ +options_description ConfigurationOptions::get_generic_options() const +{ + options_description options( "Generic options" ); + options.add_options() + ( HelpCmdStr.c_str(), HelpCmdDesc.c_str() ) + ( VersionCmdStr.c_str(), VersionCmdDesc.c_str() ) + ( DaemonCmdStr.c_str(), DaemonCmdDesc.c_str() ) + ( ConfigFileCmdStr.c_str(), value()->default_value( DefaultConfigFileName ), ConfigFileCmdDesc.c_str() ) + ; + + return options; +} + +/** + * @brief TODO + * + * @return + */ +options_description ConfigurationOptions::get_configuration_options() const +{ + options_description options( "Configuration" ); + options.add_options() + ( SourceNetworkInterfaceCmdStr.c_str(), value(), SourceNetworkInterfaceCmdDesc.c_str() ) + ( NameServerCmdStr.c_str(), value()->default_value( DefaultNameServer ), NameServerCmdDesc.c_str() ) + ( PingProtocolCmdStr.c_str(), value(), PingProtocolCmdDesc.c_str() ) + ( HostsDownLimitCmdStr.c_str(), value()->default_value( DefaultHostsDownLimit ), HostsDownLimitCmdDesc.c_str() ) + ( PingFailLimitCmdStr.c_str(), value()->default_value( DefaultPingFailLimit ), PingFailLimitCmdDesc.c_str() ) + ( StatusNotifierCmdCmdStr.c_str(), value(), StatusNotifierCmdCmdDesc.c_str() ) + ( LinkUpIntervalCmdStr.c_str(), value()->default_value( DefaultLinkUpIntervalInMin ), LinkUpIntervalCmdDesc.c_str() ) + ( LinkDownIntervalCmdStr.c_str(), value()->default_value( DefaultLinkDownIntervalInMin ), LinkDownIntervalCmdDesc.c_str() ) + ( HostNameCmdStr.c_str(), value< vector >(), HostNameCmdDesc.c_str() ) + ( HostPortCmdStr.c_str(), value< vector >(), HostPortCmdDesc.c_str() ) + ( HostIntervalCmdStr.c_str(), value< vector >(), HostIntervalCmdDesc.c_str() ) + ; + + return options; +} + +/** + * @brief TODO + * + * @param + * @param + * + * @return + */ +bool ConfigurationOptions::parse_generic_options( + const variables_map& vm, + Configuration *configuration +) +{ + // help + if ( vm.count( HelpCmdStr ) > 0) + { + options_description generic = get_generic_options(); + options_description config = get_configuration_options(); + + options_description visible_options( "Allowed options" ); + visible_options.add( generic ).add( config ); + + // TODO return a string with help, does not print to interface + cout << visible_options << endl; + return true; + } + + // version + if ( vm.count( VersionCmdStr ) > 0 ) + { + cout << PROJECT_NAME << " version " << VERSION_STRING << endl; + return true; + } + + // daemon + bool have_daemon = ( vm.count( DaemonCmdStr ) > 0 ); + configuration->set_daemon( have_daemon ); + GlobalLogger.info() << DaemonCmdStr << "=" + << have_daemon << endl; + + // config-file + if ( vm.count( ConfigFileCmdStr ) > 0 ) + { + string config_file_name = vm[ ConfigFileCmdStr ].as (); + configuration->set_config_file_name( config_file_name ); + + GlobalLogger.info() << ConfigFileCmdStr << "=" + << config_file_name << endl; + } + + return false; +} + +/** + * @brief TODO + * + * @param + * @param + * + * @return + */ +bool ConfigurationOptions::parse_configuration_options( + const variables_map &vm, + Configuration *configuration +) +{ + // source-network-interface + if ( vm.count( SourceNetworkInterfaceCmdStr ) > 0 ) + { + string source_network_interface = + vm[ SourceNetworkInterfaceCmdStr ].as (); + configuration->set_source_network_interface( source_network_interface ); + + GlobalLogger.info() << SourceNetworkInterfaceCmdStr << "=" + << source_network_interface << endl; + } + + // nameserver + if ( vm.count( NameServerCmdStr ) > 0 ) + { + string nameserver = vm[ NameServerCmdStr ].as (); + configuration->set_nameserver( nameserver ); + + GlobalLogger.info() << NameServerCmdStr << "=" + << nameserver << endl; + } + + // ping-protocol + if ( vm.count( PingProtocolCmdStr ) > 0 ) + { + string protocol_string = vm[ PingProtocolCmdStr ].as (); + PingProtocol protocol = get_ping_protocol_from_string( protocol_string ); + configuration->set_ping_protocol( protocol ); + + GlobalLogger.info() << PingProtocolCmdStr << "=" + << protocol_string << endl; + } + + // hosts-down-limit + int host_down_limit = 0; + if ( vm.count( HostsDownLimitCmdStr ) > 0 ) + { + host_down_limit = vm[ HostsDownLimitCmdStr ].as (); + configuration->set_hosts_down_limit( host_down_limit ); + + GlobalLogger.info() << HostsDownLimitCmdStr << "=" + << host_down_limit << endl; + } + + // ping-fail-limit + if ( vm.count( PingFailLimitCmdStr ) > 0 ) + { + int ping_fail_limit = vm[ PingFailLimitCmdStr ].as (); + configuration->set_ping_fail_limit( ping_fail_limit ); + + GlobalLogger.info() << PingFailLimitCmdStr << "=" + << ping_fail_limit << endl; + } + + // status-notifier-cmd + if ( vm.count( StatusNotifierCmdCmdStr ) > 0 ) + { + string status_notifier_cmd = vm[ StatusNotifierCmdCmdStr ].as(); + configuration->set_status_notifier_cmd( status_notifier_cmd ); + + GlobalLogger.info() << StatusNotifierCmdCmdStr << "=" + << status_notifier_cmd << endl; + } + + // link-up-interval + if ( vm.count( LinkUpIntervalCmdStr ) > 0 ) + { + int link_up_interval_in_min = vm[ LinkUpIntervalCmdStr ].as(); + configuration->set_link_up_interval_in_min( link_up_interval_in_min ); + + GlobalLogger.info() << LinkUpIntervalCmdStr << "=" + << link_up_interval_in_min << endl; + } + + // link-down-interval + if ( vm.count( LinkDownIntervalCmdStr ) > 0 ) + { + int link_down_interval_in_min = vm[ LinkDownIntervalCmdStr ].as(); + configuration->set_link_down_interval_in_min( link_down_interval_in_min ); + + GlobalLogger.info() << LinkDownIntervalCmdStr << "=" + << link_down_interval_in_min << endl; + } + + // [host] name + size_t hosts_names_count = 0; + if ( vm.count( HostNameCmdStr ) > 0 ) + { + HostList hosts_list; + + vector hosts_names = vm[ HostNameCmdStr ].as< vector > (); + BOOST_FOREACH( string host_name, hosts_names ) + { + BOOST_ASSERT( !host_name.empty() ); + + HostItem host_item( new Host( host_name ) ); + hosts_list.push_back( host_item ); + + GlobalLogger.info() << HostNameCmdStr << "=" + << host_name << endl; + } + + configuration->set_hosts( hosts_list ); + + hosts_names_count = hosts_names.size(); + + BOOST_ASSERT( hosts_names_count >= static_cast( host_down_limit ) ); + } + + // [host] port + size_t host_port_count = 0; + if ( vm.count( HostPortCmdStr ) > 0 ) + { + HostList hosts_list = configuration->get_hosts(); + HostList::iterator hosts_it = hosts_list.begin(); + + vector hosts_ports = vm[ HostPortCmdStr ].as< vector >(); + BOOST_FOREACH( int host_port, hosts_ports ) + { + BOOST_ASSERT( ( 0 <= host_port ) && ( host_port <= numeric_limits::max() ) ); + + HostItem host_item = *hosts_it; + host_item->set_port( static_cast(host_port) ); + ++hosts_it; + + GlobalLogger.info() << HostPortCmdStr << "=" << host_port << endl; + } + + host_port_count = hosts_ports.size(); + } + + // [host] interval + size_t hosts_interval_count = 0; + if ( vm.count( HostIntervalCmdStr ) > 0 ) + { + HostList hosts_list = configuration->get_hosts(); + HostList::iterator hosts_it = hosts_list.begin(); + + vector hosts_intervals = vm[ HostIntervalCmdStr ].as< vector >(); + BOOST_FOREACH( int host_interval_in_sec, hosts_intervals ) + { + BOOST_ASSERT( 0 < host_interval_in_sec ); + + HostItem host_item = *hosts_it; + host_item->set_interval_in_sec( host_interval_in_sec ); + ++hosts_it; + + GlobalLogger.info() << HostIntervalCmdStr << "=" + << host_interval_in_sec << endl; + } + + hosts_interval_count = hosts_intervals.size(); + } + + // make sure there is always an interval for each host + if ( hosts_names_count != hosts_interval_count ) + { + GlobalLogger.error() << "Could not parse configuration file." << + " Missing an interval entry for one of the hosts." << endl; + return false; + } + + BOOST_ASSERT( hosts_names_count == host_port_count ); + BOOST_ASSERT( hosts_names_count == hosts_interval_count ); + + return true; +} + +/** + * @return which options must abort the application. Like the --version. + * TODO rename to is_haltable? + */ +bool ConfigurationOptions::halt_on_generic_options( const variables_map &vm ) const +{ + bool is_help = ( vm.count( HelpCmdStr ) > 0 ); + bool is_version = ( vm.count( VersionCmdStr ) > 0 ); + bool terminate_app = is_help || is_version; + + return terminate_app; +} diff --git a/src/config/configurationoptions.h b/src/config/configurationoptions.h new file mode 100644 index 0000000..a8d014c --- /dev/null +++ b/src/config/configurationoptions.h @@ -0,0 +1,101 @@ +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + */ + +#ifndef CONFIGURATIONOPTIONS_H +#define CONFIGURATIONOPTIONS_H + +#include + +#include + +#include "config/configuration.h" + +//----------------------------------------------------------------------------- +// ConfigurationOptions +//----------------------------------------------------------------------------- + +/** + * @brief Options for configuration. + */ +class ConfigurationOptions +{ +public: + ConfigurationOptions(); + virtual ~ConfigurationOptions(); + + boost::program_options::options_description get_generic_options() const; + boost::program_options::options_description get_configuration_options() const; + + bool parse_generic_options( + const boost::program_options::variables_map &vm, + Configuration *configuration + ); + bool parse_configuration_options( + const boost::program_options::variables_map &vm, + Configuration *configuration + ); + + bool halt_on_generic_options( + const boost::program_options::variables_map &vm + ) const; + +public: // TODO change to private + const std::string HelpCmdStr; + const std::string HelpCmdDesc; + const std::string VersionCmdStr; + const std::string VersionCmdDesc; + const std::string DaemonCmdStr; + const std::string DaemonCmdDesc; + const std::string DefaultConfigFileName; + const std::string ConfigFileCmdStr; + const std::string ConfigFileCmdDesc; + const std::string SourceNetworkInterfaceCmdStr; + const std::string SourceNetworkInterfaceCmdDesc; + const std::string DefaultNameServer; + const std::string NameServerCmdStr; + const std::string NameServerCmdDesc; + const std::string PingProtocolCmdStr; + const std::string PingProtocolCmdDesc; + const int DefaultHostsDownLimit; + const std::string HostsDownLimitCmdStr; + const std::string HostsDownLimitCmdDesc; + const int DefaultPingFailLimit; + const std::string PingFailLimitCmdStr; + const std::string PingFailLimitCmdDesc; + const std::string StatusNotifierCmdCmdStr; + const std::string StatusNotifierCmdCmdDesc; + const int DefaultLinkUpIntervalInMin; + const std::string LinkUpIntervalCmdStr; + const std::string LinkUpIntervalCmdDesc; + const int DefaultLinkDownIntervalInMin; + const std::string LinkDownIntervalCmdStr; + const std::string LinkDownIntervalCmdDesc; + const std::string HostNameCmdStr; + const std::string HostNameCmdDesc; + const int DefaultHostPort; + const std::string HostPortCmdStr; + const std::string HostPortCmdDesc; + const int DefaultHostIntervalInSec; + const std::string HostIntervalCmdStr; + const std::string HostIntervalCmdDesc; + +}; + +#endif // CONFIGURATIONOPTIONS_H -- 1.7.1