- this option sets the threshold of pings to a host that must fail in order to mark the host as down.
- Handle Exceptions for exceptional errors.
+2.5. Assertions
+---------------------------------------
+Also, it is good to use ASSERTS to document assumptions about:
+- method's argument values. If you expect that a parameter have certain values,
+ assert it (preconditions)
+- and if you expect the method deliver a certain value, assert in the end of
+ the method (postcondition).
+This is known by programming by contract.
+
+
3. Source Code
=======================================
4.1. General
---------------------------------------
This configurations are shared among and affect all the hosts.
-- limit-hosts-down: ranges from 0 to the number of hosts available. This value
- represents the minimum number of hosts that have to fail (i.e. do not reply
- the ping) in order to alert any external system.
+- limit-hosts-down: an absolute number, which ranges from 0 to the number of
+ hosts available. This value represents the minimum number of hosts that have
+ to fail (i.e. do not reply to the ping) in order to alert any external system.
+- limit-ping-fail: percentage of pings to a host that can fail. If the
+ percentage of failed pings to a host exceed this number, then the host is
+ considered down.
4.2. Host
limit-hosts-down=5
+limit-ping-fail=40
[host]
name=www.intra2net.com
Configuration::Configuration() :
ConfigFileName( "" ),
LimitHostsDown( 0 ),
- Hosts(),
MinLimitHostsDown( 0 ),
- MaxLimitHostsDown( 50 )
+ MaxLimitHostsDown( 50 ),
+ LimitPingFail( 0 ),
+ MinLimitPingFail( 0 ),
+ MaxLimitPingFail( 100 ),
+ Hosts()
{
}
this->LimitHostsDown = limit_hosts_down;
}
+int Configuration::get_limit_ping_fail() const
+{
+ return LimitPingFail;
+}
+
+void Configuration::set_limit_ping_fail( const int limit_ping_fail )
+{
+ LimitPingFail = limit_ping_fail;
+}
+
vector< HostItem > Configuration::get_hosts() const
{
return Hosts;
int get_limit_hosts_down() const;
void set_limit_hosts_down( const int limit_hosts_down );
+ int get_limit_ping_fail() const;
+ void set_limit_ping_fail( const int limit_ping_fail );
+
std::vector<HostItem> get_hosts() const;
void set_hosts( const std::vector<HostItem> &hosts_list );
private:
std::string ConfigFileName;
int LimitHostsDown;
- std::vector<HostItem> Hosts;
-
const int MinLimitHostsDown;
const int MaxLimitHostsDown;
+ int LimitPingFail;
+ const int MinLimitPingFail;
+ const int MaxLimitPingFail;
+ std::vector<HostItem> Hosts;
};
DefaultLimitHostsDown( 1 ),
LimitHostsDownCmdStr( "limit-hosts-down" ),
LimitHostsDownCmdDesc( "Limit of host that have to be down in order to notify." ),
+ DefaultLimitPingFail( 50 ),
+ LimitPingFailCmdStr( "limit-ping-fail" ),
+ LimitPingFailCmdDesc( "Maximum percentage of pings that can fail for a given host." ),
HostNameCmdStr( "host.name" ),
HostNameCmdDesc( "Host address" ),
DefaultHostInterval( 1 ),
options_description options( "Configuration" );
options.add_options()
( LimitHostsDownCmdStr.c_str(), value<int>()->default_value( DefaultLimitHostsDown ), LimitHostsDownCmdDesc.c_str() )
+ ( LimitPingFailCmdStr.c_str(), value<int>()->default_value( DefaultLimitPingFail ), LimitPingFailCmdDesc.c_str() )
( HostNameCmdStr.c_str(), value< vector<string> >(), HostNameCmdDesc.c_str() )
( HostIntervalCmdStr.c_str(), value< vector<int> >(), HostIntervalCmdDesc.c_str() )
;
bool ConfigurationReader::parse_configuration_options( const variables_map &vm )
{
+ // config-file
if ( vm.count( ConfigFileCmdStr ) )
{
string config_file_name = vm[ ConfigFileCmdStr ].as<string> ();
cout << ConfigFileCmdStr << "=" << config_file_name << endl;
}
+ // limit-hosts-down
if ( vm.count( LimitHostsDownCmdStr ) )
{
int limit_host_down = vm[ LimitHostsDownCmdStr ].as<int> ();
cout << LimitHostsDownCmdStr << "=" << limit_host_down << endl;
}
+ // limit-ping-fail
+ if ( vm.count( LimitPingFailCmdStr ) )
+ {
+ int limit_ping_fail = vm[ LimitPingFailCmdStr ].as<int> ();
+ Config.set_limit_ping_fail( limit_ping_fail );
+
+ cout << LimitPingFailCmdStr << "=" << limit_ping_fail << endl;
+ }
+
+ // [host] name
int hosts_names_total = 0;
if ( vm.count( HostNameCmdStr ) )
{
hosts_names_total = hosts_names.size();
}
+ // [host] interval
int hosts_interval_total = 0;
if ( vm.count( HostIntervalCmdStr ) )
{
}
// TODO deal when interval for a given host was not set. use DefaultHostInterval
- BOOST_ASSERT(hosts_names_total == hosts_interval_total);
+
+ BOOST_ASSERT( hosts_names_total == hosts_interval_total );
return true;
}
const int DefaultLimitHostsDown;
const std::string LimitHostsDownCmdStr;
const std::string LimitHostsDownCmdDesc;
+ const int DefaultLimitPingFail;
+ const std::string LimitPingFailCmdStr;
+ const std::string LimitPingFailCmdDesc;
const std::string HostNameCmdStr;
const std::string HostNameCmdDesc;
const int DefaultHostInterval;
+#include <vector>
+
#include <boost/asio.hpp>
#include <boost/foreach.hpp>
-#include <vector>
#include "config/configurationreader.h"
#include "config/host.h"
#include "ping/pingscheduler.h"
using namespace std;
+using namespace boost;
using namespace boost::asio;
int main( int argc, char* argv[] )
{
io_service io_service;
- // TODO init_pingers()
Configuration config = config_reader.get_configuration();
+
+ int limit_ping_fail = config.get_limit_ping_fail();
+
+ // TODO init_pingers()
vector< HostItem > hosts = config.get_hosts();
vector< PingSchedulerItem > scheduler_list;
BOOST_FOREACH( HostItem host, hosts )
int ping_interval = (*host).get_interval();
PingSchedulerItem scheduler(
new PingScheduler(
- io_service, ping_address, ping_interval
+ io_service, ping_address, ping_interval,
+ limit_ping_fail
)
);
scheduler_list.push_back( scheduler );
// BoostPinger
//-----------------------------------------------------------------------------
+/**
+ * @brief This class performs ping to host using Boost Asio.
+ */
class BoostPinger : public Pinger
{
public:
#include <boost/assert.hpp>
using namespace std;
+using namespace boost;
//-----------------------------------------------------------------------------
// PingAnalyzer
PingAnalyzer::PingAnalyzer(
const string &host_address,
- const int ping_fail_threshold_percentage
+ const int limit_ping_fail_percentage
) :
Notifier( host_address ),
- PingFailThresholdPercentage( ping_fail_threshold_percentage ),
+ LimitPingFailPercentage( limit_ping_fail_percentage ),
ResolvedIpCount( 0 ),
PingsPerformedCount( 0 ),
PingsFailedCount( 0 )
{
BOOST_ASSERT( !host_address.empty() );
- BOOST_ASSERT( ( 0 <= ping_fail_threshold_percentage ) && ( ping_fail_threshold_percentage <= 100 ) );
+ BOOST_ASSERT( ( 0 <= limit_ping_fail_percentage ) && ( limit_ping_fail_percentage <= 100 ) );
}
PingAnalyzer::~PingAnalyzer()
BOOST_ASSERT( 0 <= PingsPerformedCount );
BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
- ++PingsPerformedCount;
+ increase_ping_performed_count();
if ( !ping_success )
{
- ++PingsFailedCount;
+ increase_ping_failed_count();
}
- if ( PingsPerformedCount >= ResolvedIpCount )
+ // after we tried all IPs resolved for this host, we can analyze how many
+ // failed
+ if ( tried_all_resolved_ip() )
{
analyze();
- reset_ping_counter();
+ reset_ping_counters();
}
BOOST_ASSERT( PingsFailedCount <= PingsPerformedCount );
void PingAnalyzer::analyze()
{
- BOOST_ASSERT( ( 0 <= PingFailThresholdPercentage ) && ( PingFailThresholdPercentage <= 100 ) );
- BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
BOOST_ASSERT( PingsPerformedCount == ResolvedIpCount );
+ BOOST_ASSERT( ( 0 <= LimitPingFailPercentage ) && ( LimitPingFailPercentage <= 100 ) );
+ BOOST_ASSERT( ( 0 <= PingsFailedCount ) && ( PingsFailedCount <= PingsPerformedCount ) );
- int ping_fail_threshold_absolute = PingFailThresholdPercentage / 100; // TODO possible number loss, check with care
+ int limit_ping_fail_absolute = LimitPingFailPercentage / 100; // TODO possible precision loss, check with care
- if ( PingsFailedCount > ping_fail_threshold_absolute )
+ if ( PingsFailedCount > limit_ping_fail_absolute )
{
Notifier.alert_host_down();
}
}
-void PingAnalyzer::reset_ping_counter()
+void PingAnalyzer::increase_ping_performed_count()
+{
+ ++PingsPerformedCount;
+}
+
+void PingAnalyzer::increase_ping_failed_count()
+{
+ ++PingsFailedCount;
+}
+
+void PingAnalyzer::reset_ping_counters()
{
PingsPerformedCount = 0;
PingsFailedCount = 0;
}
+
+bool PingAnalyzer::tried_all_resolved_ip() const
+{
+ return ( PingsPerformedCount >= ResolvedIpCount );
+}
#include <string>
+#include <boost/shared_ptr.hpp>
+
#include "ping/pingstatusnotifier.h"
//-----------------------------------------------------------------------------
// PingAnalyzer
//-----------------------------------------------------------------------------
+/**
+ * @brief This class analyze the ping status (success or failure) and decides
+ * what to do.
+ * Scope: one object per host.
+ */
class PingAnalyzer
{
public:
private:
void analyze();
- void reset_ping_counter();
+ void increase_ping_performed_count();
+ void increase_ping_failed_count();
+ void reset_ping_counters();
+ bool tried_all_resolved_ip() const;
private:
PingStatusNotifier Notifier;
- int PingFailThresholdPercentage;
+ int LimitPingFailPercentage;
int ResolvedIpCount;
int PingsPerformedCount;
int PingsFailedCount;
PingScheduler::PingScheduler(
boost::asio::io_service &io_service,
const string &ping_address,
- const int ping_interval_in_sec
+ const int ping_interval_in_sec,
+ const int limit_ping_fail_percentage
+
) :
IoService( io_service ),
Timer( io_service ),
TimeSentLastPing( microsec_clock::universal_time() ),
- IpList( ping_address ),
PingIntervalInSec( ping_interval_in_sec ),
- Analyzer( ping_address, 50 ) // 50% max acceptable failure
+ IpList( ping_address ),
+ Analyzer( ping_address, limit_ping_fail_percentage )
{
}
// PingScheduler
//-----------------------------------------------------------------------------
+/**
+ * @brief This class is responsible to control whether to ping a host. It
+ * schedules periodic pings to a host.
+ * Scope: one object per host.
+ */
class PingScheduler
{
public:
PingScheduler(
boost::asio::io_service &io_service,
const std::string &ping_address,
- const int ping_interval_in_sec
+ const int ping_interval_in_sec,
+ const int limit_ping_fail_percentage
);
virtual ~PingScheduler();
boost::asio::io_service &IoService;
boost::asio::deadline_timer Timer;
boost::posix_time::ptime TimeSentLastPing;
- DnsResolver IpList;
const int PingIntervalInSec;
+ DnsResolver IpList;
PingAnalyzer Analyzer;
};