Created a class to hold configuration options and parsing inteligence
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Wed, 31 Aug 2011 02:46:44 +0000 (23:46 -0300)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Wed, 31 Aug 2011 02:46:44 +0000 (23:46 -0300)
- it does not know about where the configuration came from

src/config/configurationoptions.cpp [new file with mode: 0644]
src/config/configurationoptions.h [new file with mode: 0644]

diff --git a/src/config/configurationoptions.cpp b/src/config/configurationoptions.cpp
new file mode 100644 (file)
index 0000000..129abf4
--- /dev/null
@@ -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 <iostream>
+
+#include <boost/assert.hpp>
+#include <boost/foreach.hpp>
+
+#include <logfunc.hpp>
+
+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<string>()->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<string>(), SourceNetworkInterfaceCmdDesc.c_str() )
+        ( NameServerCmdStr.c_str(), value<string>()->default_value( DefaultNameServer ), NameServerCmdDesc.c_str() )
+        ( PingProtocolCmdStr.c_str(), value<string>(), PingProtocolCmdDesc.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() )
+        ( HostIntervalCmdStr.c_str(), value< vector<int> >(), 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<string> ();
+        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<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;
+    }
+
+    // ping-protocol
+    if ( vm.count( PingProtocolCmdStr ) > 0 )
+    {
+        string protocol_string = vm[ PingProtocolCmdStr ].as<string> ();
+        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<int> ();
+        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<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 )
+        {
+            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<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() ) );
+
+            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] 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 == 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 (file)
index 0000000..a8d014c
--- /dev/null
@@ -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 <string>
+
+#include <boost/program_options.hpp>
+
+#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