From: Guilherme Maciel Ferreira Date: Sat, 8 Oct 2011 14:10:24 +0000 (-0300) Subject: Using individual classes for each option, instead of doing all the work in one big... X-Git-Tag: v1.3~11^2~34^2~5 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=6c5bdffde9b4fbc5c2f0fe57afe9fbf1a22bb078;p=pingcheck Using individual classes for each option, instead of doing all the work in one big class --- diff --git a/src/config/configurationoptions.cpp b/src/config/configurationoptions.cpp index 65fcc89..5947d68 100644 --- a/src/config/configurationoptions.cpp +++ b/src/config/configurationoptions.cpp @@ -27,10 +27,27 @@ #include +#include "config/option/configfileoption.h" +#include "config/option/daemonoption.h" +#include "config/option/hostdownlimitoption.h" +#include "config/option/hostnameoption.h" +#include "config/option/hostportoption.h" +#include "config/option/hostpingprotocoloption.h" +#include "config/option/hostpingintervaloption.h" +#include "config/option/linkdownintervaloption.h" +#include "config/option/linkupintervaloption.h" +#include "config/option/nameserveroption.h" +#include "config/option/pingfaillimitoption.h" +#include "config/option/sourcenetworkinterfaceoption.h" +#include "config/option/statusnotifiercmdoption.h" +#include "config/option/versionoption.h" + using namespace std; +using boost::program_options::option_description; using boost::program_options::options_description; using boost::program_options::value; using boost::program_options::variables_map; +using boost::shared_ptr; using I2n::Logger::GlobalLogger; //----------------------------------------------------------------------------- @@ -41,45 +58,53 @@ using I2n::Logger::GlobalLogger; * @brief Default constructor. */ ConfigurationOptions::ConfigurationOptions() : + GenericOptions(), + ConfigOptions(), + HostOptions(), 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." ), - 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" ), - HostPingProtocolCmdStr( "host.ping-protocol" ), - HostPingProtocolCmdDesc( "Defines which protocol will be used to ping the destination." ), - DefaultHostIntervalInSec( 60 ), // 60 seconds - HostIntervalCmdStr( "host.interval" ), - HostIntervalCmdDesc( "Interval between each ping to the host" ) + HelpCmdDesc( "Print this help and exit." ) { + ConfigurationOptionItem config_file( new ConfigFileOption ); + GenericOptions.push_back( config_file ); + + ConfigurationOptionItem daemon( new DaemonOption ); + GenericOptions.push_back( daemon ); + + ConfigurationOptionItem version( new VersionOption ); + GenericOptions.push_back( version ); + + ConfigurationOptionItem host_down_limit( new HostDownLimitOption ); + ConfigOptions.push_back( host_down_limit ); + + ConfigurationOptionItem link_down_interval( new LinkDownIntervalOption ); + ConfigOptions.push_back( link_down_interval ); + + ConfigurationOptionItem link_up_interval( new LinkUpIntervalOption ); + ConfigOptions.push_back( link_up_interval ); + + ConfigurationOptionItem nameserver( new NameserverOption ); + ConfigOptions.push_back( nameserver ); + + ConfigurationOptionItem ping_fail_limit( new PingFailLimitOption ); + ConfigOptions.push_back( ping_fail_limit ); + + ConfigurationOptionItem source_network_interface( new SourceNetworkInterfaceOption ); + ConfigOptions.push_back( source_network_interface ); + + ConfigurationOptionItem status_notifier_cmd( new StatusNotifierCmdOption ); + ConfigOptions.push_back( status_notifier_cmd ); + + HostConfigurationOptionItem host_name( new HostNameOption ); + HostOptions.push_back( host_name ); + + HostConfigurationOptionItem host_port( new HostPortOption ); + HostOptions.push_back( host_port ); + + HostConfigurationOptionItem host_protocol( new HostPingProtocolOption ); + HostOptions.push_back( host_protocol ); + + HostConfigurationOptionItem host_interval( new HostPingIntervalOption ); + HostOptions.push_back( host_interval ); } /** @@ -90,55 +115,64 @@ ConfigurationOptions::~ConfigurationOptions() } /** - * @brief TODO - * - * @return + * @return The options which are common to all kinds of applications. */ 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() ) ; + BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions ) + { + // Do not pass the the underlying boost::program_options::option_description + // object from ConfigurationOption to the + // boost::program_options::options_description::add() method, because it + // deletes the boost::program_options::option_description, causing + // multiple freed when ConfigurationOption try to delete it. + option_description option = generic_option->get_option_description(); + shared_ptr< option_description > ptr( new option_description( option ) ); + options.add( ptr ); + } + return options; } /** - * @brief TODO - * - * @return + * @return The options which are specific to this application. */ 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() ) - ( 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() ) - ( HostPingProtocolCmdStr.c_str(), value< vector >(), HostPingProtocolCmdDesc.c_str() ) - ( HostIntervalCmdStr.c_str(), value< vector >(), HostIntervalCmdDesc.c_str() ) - ; + + BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions ) + { + option_description option = configuration_option->get_option_description(); + shared_ptr< option_description > ptr( new option_description( option ) ); + options.add( ptr ); + } + + BOOST_FOREACH( ConfigurationOptionItem host_option, HostOptions ) + { + option_description option = host_option->get_option_description(); + shared_ptr< option_description > ptr( new option_description( option ) ); + options.add( ptr ); + } return options; } /** - * @brief TODO + * @brief Parse the options common to all kinds of applications. * - * @param - * @param + * @param vm The input @c boost::program_options::variables_map. + * @param configuration The output @c Configuration filled with the parsed + * generic options. * - * @return + * @return @c true if it was parsed at least one option, or @c false if there + * were no options available in this category. */ bool ConfigurationOptions::parse_generic_options( const variables_map& vm, @@ -146,7 +180,7 @@ bool ConfigurationOptions::parse_generic_options( ) { // help - if ( vm.count( HelpCmdStr ) > 0) + if ( vm.count( HelpCmdStr ) > 0 ) { options_description generic = get_generic_options(); options_description config = get_configuration_options(); @@ -154,239 +188,85 @@ bool ConfigurationOptions::parse_generic_options( options_description visible_options( "Allowed options" ); visible_options.add( generic ).add( config ); - // TODO return a string with help, does not print to interface + // TODO GlobalOutput::print( help ) cout << visible_options << endl; return true; } - // version - if ( vm.count( VersionCmdStr ) > 0 ) + BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions ) { - cout << PROJECT_NAME << " version " << VERSION_STRING << endl; - return true; + bool validated = generic_option->validate( vm ); + if ( validated ) + { + generic_option->parse( vm, configuration ); + } } - // 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 + * @brief Parse the options specific to this application. * - * @param - * @param + * @param vm The input @c boost::program_options::variables_map. + * @param configuration The output @c Configuration filled with the parsed + * configuration options. * - * @return + * @return @c true if it was parsed at least one option, or @c false if there + * were no options available in this category. */ 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; - } - - // 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 ) + BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions ) { - 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 ) + bool validated = configuration_option->validate( vm ); + if ( validated ) { - 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_option->parse( vm, configuration ); } - - 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() ) ); + size_t host_down_limit_count = static_cast( configuration->get_hosts_down_limit() ); - 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] ping-protocol - size_t host_ping_protocol_count = 0; - if ( vm.count( HostPingProtocolCmdStr ) > 0 ) + BOOST_FOREACH( HostConfigurationOptionItem host_option, HostOptions ) { - HostList hosts_list = configuration->get_hosts(); - HostList::iterator hosts_it = hosts_list.begin(); - - vector hosts_protocols = vm[ HostPingProtocolCmdStr ].as< vector >(); - BOOST_FOREACH( string protocol_string, hosts_protocols ) + bool validated = host_option->validate( vm ); + bool parsed = host_option->parse( vm, configuration ); + if ( validated && parsed ) { - BOOST_ASSERT( !protocol_string.empty() ); - - HostItem host_item = *hosts_it; - PingProtocol host_protocol = get_ping_protocol_from_string( protocol_string ); - host_item->set_ping_protocol( host_protocol ); - ++hosts_it; - - GlobalLogger.info() << HostPingProtocolCmdStr << "=" - << protocol_string << endl; + // The set_hosts_count() method is called in parse() method, that is + // why we must parse before check the number of host options + size_t hosts_parsed_count = host_option->get_hosts_count(); + bool have_minimum_hosts = ( host_down_limit_count <= hosts_parsed_count ); + // Ensure we have all options for each host + if ( !have_minimum_hosts ) { + // TODO GlobalOutput::print() + GlobalLogger.error() << "Could not parse configuration file." << + " Missing an entry for one of the hosts." << endl; + // TODO Assume default value for a missing option + return false; + } + + BOOST_ASSERT( hosts_parsed_count >= static_cast( host_down_limit_count ) ); } - - host_ping_protocol_count = hosts_protocols.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 == host_ping_protocol_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 { + VersionOption v; + bool is_help = ( vm.count( HelpCmdStr ) > 0 ); - bool is_version = ( vm.count( VersionCmdStr ) > 0 ); + bool is_version = ( vm.count( v.get_command_string() ) > 0 ); bool terminate_app = is_help || is_version; return terminate_app; diff --git a/src/config/configurationoptions.h b/src/config/configurationoptions.h index c68799b..20cd660 100644 --- a/src/config/configurationoptions.h +++ b/src/config/configurationoptions.h @@ -18,14 +18,16 @@ on this file might be covered by the GNU General Public License. */ -#ifndef CONFIGURATIONOPTIONS_H -#define CONFIGURATIONOPTIONS_H +#ifndef CONFIGURATION_OPTIONS_H +#define CONFIGURATION_OPTIONS_H #include #include #include "config/configuration.h" +#include "config/option/configurationoption.h" +#include "config/option/hostconfigurationoption.h" //----------------------------------------------------------------------------- // ConfigurationOptions @@ -56,46 +58,14 @@ public: const boost::program_options::variables_map &vm ) const; -public: // TODO change to private +private: + ConfigurationOptionList GenericOptions; + ConfigurationOptionList ConfigOptions; + HostConfigurationOptionList HostOptions; + 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 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 std::string HostPingProtocolCmdStr; - const std::string HostPingProtocolCmdDesc; - const int DefaultHostIntervalInSec; - const std::string HostIntervalCmdStr; - const std::string HostIntervalCmdDesc; }; -#endif // CONFIGURATIONOPTIONS_H +#endif // CONFIGURATION_OPTIONS_H