#include <logfunc.hpp>
+#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;
//-----------------------------------------------------------------------------
* @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 );
}
/**
}
/**
- * @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<string>()->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<string>(), SourceNetworkInterfaceCmdDesc.c_str() )
- ( NameServerCmdStr.c_str(), value<string>()->default_value( DefaultNameServer ), NameServerCmdDesc.c_str() )
- ( HostsDownLimitCmdStr.c_str(), value<int>()->default_value( DefaultHostsDownLimit ), HostsDownLimitCmdDesc.c_str() )
- ( PingFailLimitCmdStr.c_str(), value<int>()->default_value( DefaultPingFailLimit ), PingFailLimitCmdDesc.c_str() )
- ( StatusNotifierCmdCmdStr.c_str(), value<string>(), StatusNotifierCmdCmdDesc.c_str() )
- ( LinkUpIntervalCmdStr.c_str(), value<int>()->default_value( DefaultLinkUpIntervalInMin ), LinkUpIntervalCmdDesc.c_str() )
- ( LinkDownIntervalCmdStr.c_str(), value<int>()->default_value( DefaultLinkDownIntervalInMin ), LinkDownIntervalCmdDesc.c_str() )
- ( HostNameCmdStr.c_str(), value< vector<string> >(), HostNameCmdDesc.c_str() )
- ( HostPortCmdStr.c_str(), value< vector<int> >(), HostPortCmdDesc.c_str() )
- ( HostPingProtocolCmdStr.c_str(), value< vector<string> >(), HostPingProtocolCmdDesc.c_str() )
- ( HostIntervalCmdStr.c_str(), value< vector<int> >(), 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,
)
{
// help
- if ( vm.count( HelpCmdStr ) > 0)
+ 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
+ // 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<string> ();
- 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<string> ();
- 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<string> ();
- 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<int> ();
- 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<int> ();
- 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<string>();
- 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<int>();
- 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<int>();
- 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<string> hosts_names = vm[ HostNameCmdStr ].as< vector<string> > ();
- 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<size_t>( 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<int> hosts_ports = vm[ HostPortCmdStr ].as< vector<int> >();
- BOOST_FOREACH( int host_port, hosts_ports )
- {
- BOOST_ASSERT( ( 0 <= host_port ) && ( host_port <= numeric_limits<uint16_t>::max() ) );
+ size_t host_down_limit_count = static_cast<size_t>( configuration->get_hosts_down_limit() );
- HostItem host_item = *hosts_it;
- host_item->set_port( static_cast<uint16_t>(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<string> hosts_protocols = vm[ HostPingProtocolCmdStr ].as< vector<string> >();
- 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<size_t>( 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<int> hosts_intervals = vm[ HostIntervalCmdStr ].as< vector<int> >();
- 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;