improved information content of logs: in LinkAnalyzer messages add cname chain
[pingcheck] / src / link / linkstatus.cpp
CommitLineData
91fcc471
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
72e54d1c 20#include "link/linkstatus.h"
ddf41c89
GMF
21
22#include <iostream>
23
301610ca
GMF
24#include <logfunc.hpp>
25
e638894d
CH
26#include "dns/dnsmaster.h"
27
780b0bca
CH
28#include "boost_assert_handler.h"
29
ddf41c89 30using namespace std;
2bf8720f
GMF
31using boost::posix_time::microsec_clock;
32using boost::posix_time::ptime;
301610ca 33using I2n::Logger::GlobalLogger;
ddf41c89
GMF
34
35//-----------------------------------------------------------------------------
72e54d1c 36// LinkStatus
ddf41c89
GMF
37//-----------------------------------------------------------------------------
38
5a3f6189
GMF
39/**
40 * @brief Creates a link status object.
41 *
72e54d1c 42 * @param hosts_down_limit The maximum amount of different hosts that can be
5a3f6189 43 * down before the system take any action.
72e54d1c 44 * @param link_up_interval_in_min The amount of time required to the link to
5a3f6189 45 * stay up before notify.
72e54d1c 46 * @param link_down_interval_in_min The amount of time required to the link to
5a3f6189 47 * stay down before notify.
72e54d1c 48 * @param status_notifier_cmd The command used to notify about link status
5a3f6189
GMF
49 * changes.
50 */
72e54d1c 51LinkStatus::LinkStatus(
a341119a 52 const int hosts_down_limit,
f1bf3249 53 const int link_up_interval_in_min,
1634f2a1 54 const int link_down_interval_in_min,
b279ae09 55 const string &status_notifier_cmd
c1fff16a 56) :
a341119a 57 HostsDownLimit( hosts_down_limit ),
f1bf3249
GMF
58 HostsDownList(),
59 LinkUpIntervalInMin( link_up_interval_in_min ),
1634f2a1 60 LinkDownIntervalInMin( link_down_interval_in_min ),
72e54d1c 61 CurrentLinkStatus( Status_Down ),
f1bf3249
GMF
62 CurrentNotificationStatus( NotificationStatus_NotReported ),
63 TimeLinkStatusChanged( microsec_clock::universal_time() ),
365036be 64 StatusNotifierCmd( new StatusNotifierCommand( status_notifier_cmd ) )
ddf41c89 65{
a341119a 66 BOOST_ASSERT( 0 <= hosts_down_limit );
f1bf3249 67 BOOST_ASSERT( 0 <= link_up_interval_in_min );
1634f2a1 68 BOOST_ASSERT( 0 <= link_down_interval_in_min );
ddf41c89
GMF
69}
70
72e54d1c 71LinkStatus::~LinkStatus()
ddf41c89
GMF
72{
73}
74
5a3f6189
GMF
75/**
76 * @brief Notify the system that a given host is up. The object takes an
77 * appropriated action to deal with that.
78 * Note: this object does not resolves IPs, thus you have to send the same host
79 * address in order to the object to consider the same host.
80 *
81 * @param host_address the DNS/IP address of the host that is up.
82 */
72e54d1c 83void LinkStatus::notify_host_up( const string &host_address )
ddf41c89 84{
c1fff16a
GMF
85 BOOST_ASSERT( !host_address.empty() );
86
f5ffc5df 87 bool has_changed = add_host_up( host_address );
c1fff16a 88
f5ffc5df
CH
89 if (has_changed)
90 GlobalLogger.notice() << "Status (" << HostsDownList.size()
91 << "/" << HostsDownLimit << " down): now up again is "
e638894d 92 << DnsMaster::get_cname_chain_str(host_address) << endl;
f5ffc5df
CH
93 else // less important so log only at info level
94 GlobalLogger.info() << "Status (" << HostsDownList.size()
95 << "/" << HostsDownLimit << " down): still up is "
e638894d 96 << DnsMaster::get_cname_chain_str(host_address) << endl;
1266407a 97
a341119a 98 if ( !exceeded_host_down_limit() )
1266407a 99 {
fb469ffa 100 notify_link_up();
1266407a
GMF
101 }
102
b279ae09 103 // removed from the list?
1266407a 104 BOOST_ASSERT( HostsDownList.count( host_address ) == 0 );
529e5587 105} //lint !e1788
ddf41c89 106
5a3f6189
GMF
107/**
108 * @brief Notify the system that a given host is down. The object takes an
109 * appropriated action to deal with that.
110 * Note: this object does not resolves IPs, thus you have to send the same host
111 * address in order to the object to consider the same host.
112 *
72e54d1c 113 * @param host_address The DNS/IP address of the host that is down.
5a3f6189 114 */
72e54d1c 115void LinkStatus::notify_host_down( const string &host_address )
ddf41c89 116{
c1fff16a
GMF
117 BOOST_ASSERT( !host_address.empty() );
118
1266407a 119 add_host_down( host_address );
c1fff16a 120
f5ffc5df
CH
121 // report this always at notice level
122 GlobalLogger.notice() << "Status (" << HostsDownList.size()
123 << "/" << HostsDownLimit << " down): down is "
e638894d 124 << DnsMaster::get_cname_chain_str(host_address) << endl;
f5ffc5df 125
a341119a 126 if ( exceeded_host_down_limit() )
1266407a 127 {
fb469ffa 128 notify_link_down();
1266407a 129 }
c1fff16a 130
b279ae09 131 // inserted in the list?
1266407a 132 BOOST_ASSERT( HostsDownList.count( host_address ) == 1 );
529e5587 133} //lint !e1788
c1fff16a 134
f5ffc5df
CH
135// returns true if this did change something (i.e. host had been down)
136bool LinkStatus::add_host_up( const string &host_address )
1266407a
GMF
137{
138 if ( HostsDownList.count( host_address ) > 0 )
139 {
a4049623
GMF
140 size_t erased_host_count = HostsDownList.erase( host_address );
141
142 BOOST_ASSERT( erased_host_count == 1 );
f5ffc5df
CH
143
144 return true;
1266407a 145 }
f5ffc5df
CH
146 else
147 return false;
148
1266407a 149}
c1fff16a 150
72e54d1c 151void LinkStatus::add_host_down( const string &host_address )
1266407a 152{
a4049623 153 (void) HostsDownList.insert( host_address );
1266407a 154}
c1fff16a 155
72e54d1c 156bool LinkStatus::exceeded_host_down_limit() const
1266407a 157{
cf289c98 158 int host_down_count = static_cast<int>( HostsDownList.size() );
6cfbd37c 159
a341119a 160 return ( host_down_count > HostsDownLimit );
ddf41c89 161}
b279ae09 162
72e54d1c 163void LinkStatus::notify_link_up()
b279ae09 164{
72e54d1c 165 set_link_status( Status_Up );
b279ae09 166
1634f2a1
GMF
167 // report the link status only if: it is up longer than a configured amount
168 // of time, and if we haven't reported the new status yet
f1bf3249
GMF
169 if ( is_link_up_enough_time() && can_report_link_status() )
170 {
72e54d1c 171 BOOST_ASSERT( CurrentLinkStatus == Status_Up );
f1bf3249
GMF
172 BOOST_ASSERT( CurrentNotificationStatus == NotificationStatus_NotReported );
173
709ded82 174 StatusNotifierCmd->set_token_value(
f1bf3249
GMF
175 StatusNotifierCommand::StatusToken,
176 "up"
2a686bc0 177 ); //lint !e534
f1bf3249 178
f5ffc5df
CH
179 GlobalLogger.notice() << "Status (" << HostsDownList.size()
180 << "/" << HostsDownLimit << " down): report link up" << endl;
709ded82 181 bool executed = StatusNotifierCmd->execute();
f1bf3249 182
2a686bc0 183 if ( executed )
a4049623
GMF
184 {
185 CurrentNotificationStatus = NotificationStatus_Reported;
186 }
f1bf3249 187 }
b279ae09
GMF
188}
189
72e54d1c 190void LinkStatus::notify_link_down()
b279ae09 191{
72e54d1c 192 set_link_status( Status_Down );
f1bf3249 193
1634f2a1
GMF
194 // report the link status only if: it is down longer than a configured amount
195 // of time, and if we haven't reported the new status yet
196 if ( is_link_down_enough_time() && can_report_link_status() )
f1bf3249 197 {
72e54d1c 198 BOOST_ASSERT( CurrentLinkStatus == Status_Down );
f1bf3249 199 BOOST_ASSERT( CurrentNotificationStatus == NotificationStatus_NotReported );
b279ae09 200
f5ffc5df
CH
201 GlobalLogger.notice() << "Status (" << HostsDownList.size()
202 << "/" << HostsDownLimit << " down): report link down" << endl;
709ded82 203 StatusNotifierCmd->set_token_value(
f1bf3249
GMF
204 StatusNotifierCommand::StatusToken,
205 "down"
2a686bc0 206 ); //lint !e534
f1bf3249 207
709ded82 208 bool executed = StatusNotifierCmd->execute();
f1bf3249 209
2a686bc0 210 if ( executed )
a4049623
GMF
211 {
212 CurrentNotificationStatus = NotificationStatus_Reported;
213 }
f1bf3249
GMF
214 }
215}
216
72e54d1c 217bool LinkStatus::is_link_up_enough_time() const
f1bf3249 218{
72e54d1c 219 if ( CurrentLinkStatus == Status_Up )
f1bf3249
GMF
220 {
221 ptime now = microsec_clock::universal_time();
222 long amount_time_link_is_up = (now - TimeLinkStatusChanged).total_seconds();
223 long link_up_interval_in_sec = LinkUpIntervalInMin * 60;
224
225 if ( amount_time_link_is_up >= link_up_interval_in_sec )
226 {
227 return true;
228 }
229 }
230
231 return false;
232}
233
72e54d1c 234bool LinkStatus::is_link_down_enough_time() const
1634f2a1 235{
72e54d1c 236 if ( CurrentLinkStatus == Status_Down )
1634f2a1
GMF
237 {
238 ptime now = microsec_clock::universal_time();
239 long amount_time_link_is_down = (now - TimeLinkStatusChanged).total_seconds();
240 long link_down_interval_in_sec = LinkDownIntervalInMin * 60;
241
242 if ( amount_time_link_is_down >= link_down_interval_in_sec )
243 {
244 return true;
245 }
246 }
247
248 return false;
249}
250
72e54d1c 251bool LinkStatus::can_report_link_status() const
f1bf3249
GMF
252{
253 return ( CurrentNotificationStatus == NotificationStatus_NotReported );
254}
255
72e54d1c
GMF
256void LinkStatus::set_link_status(
257 const LinkStatus::Status new_link_status
f1bf3249
GMF
258)
259{
260 // only reset the control flags if the link status has changed
261 if ( new_link_status != CurrentLinkStatus )
262 {
263 CurrentLinkStatus = new_link_status;
264 TimeLinkStatusChanged = microsec_clock::universal_time();
265
266 // have to report the link status change
267 CurrentNotificationStatus = NotificationStatus_NotReported;
268 }
b279ae09 269}