2013-02-09 18:39:43 +01:00
/******************************************************************************
* Icinga 2 *
2018-10-18 09:27:04 +02:00
* Copyright ( C ) 2012 - 2018 Icinga Development Team ( https : //icinga.com/) *
2013-02-09 18:39:43 +01:00
* *
* This program is free software ; you can redistribute it and / or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation ; either version 2 *
* of the License , or ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the Free Software Foundation *
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-05-25 16:23:35 +02:00
# include "icinga/checkable.hpp"
# include "icinga/service.hpp"
# include "icinga/host.hpp"
# include "icinga/checkcommand.hpp"
# include "icinga/icingaapplication.hpp"
# include "icinga/cib.hpp"
2015-10-19 17:31:18 +02:00
# include "icinga/clusterevents.hpp"
2014-05-25 16:23:35 +02:00
# include "remote/messageorigin.hpp"
2014-11-13 11:23:57 +01:00
# include "remote/apilistener.hpp"
2014-05-25 16:23:35 +02:00
# include "base/objectlock.hpp"
2014-10-19 14:21:12 +02:00
# include "base/logger.hpp"
2014-05-25 16:23:35 +02:00
# include "base/convert.hpp"
# include "base/utility.hpp"
# include "base/context.hpp"
2013-02-09 18:39:43 +01:00
using namespace icinga ;
2015-08-04 14:47:44 +02:00
boost : : signals2 : : signal < void ( const Checkable : : Ptr & , const CheckResult : : Ptr & , const MessageOrigin : : Ptr & ) > Checkable : : OnNewCheckResult ;
boost : : signals2 : : signal < void ( const Checkable : : Ptr & , const CheckResult : : Ptr & , StateType , const MessageOrigin : : Ptr & ) > Checkable : : OnStateChange ;
boost : : signals2 : : signal < void ( const Checkable : : Ptr & , const CheckResult : : Ptr & , std : : set < Checkable : : Ptr > , const MessageOrigin : : Ptr & ) > Checkable : : OnReachabilityChanged ;
2016-06-07 12:44:12 +02:00
boost : : signals2 : : signal < void ( const Checkable : : Ptr & , NotificationType , const CheckResult : : Ptr & , const String & , const String & , const MessageOrigin : : Ptr & ) > Checkable : : OnNotificationsRequested ;
2016-01-22 18:42:15 +01:00
boost : : signals2 : : signal < void ( const Checkable : : Ptr & ) > Checkable : : OnNextCheckUpdated ;
2014-04-03 15:36:13 +02:00
2016-05-12 13:46:22 +02:00
boost : : mutex Checkable : : m_StatsMutex ;
int Checkable : : m_PendingChecks = 0 ;
2018-01-16 10:40:08 +01:00
boost : : condition_variable Checkable : : m_PendingChecksCV ;
2016-05-12 13:46:22 +02:00
2018-01-04 04:25:35 +01:00
CheckCommand : : Ptr Checkable : : GetCheckCommand ( ) const
2013-02-09 18:39:43 +01:00
{
2015-09-22 09:42:30 +02:00
return dynamic_pointer_cast < CheckCommand > ( NavigateCheckCommandRaw ( ) ) ;
2013-02-09 18:39:43 +01:00
}
2018-01-04 04:25:35 +01:00
TimePeriod : : Ptr Checkable : : GetCheckPeriod ( ) const
2013-03-13 16:04:53 +01:00
{
2015-08-04 14:47:44 +02:00
return TimePeriod : : GetByName ( GetCheckPeriodRaw ( ) ) ;
2013-02-09 18:39:43 +01:00
}
2014-04-03 15:36:13 +02:00
void Checkable : : SetSchedulingOffset ( long offset )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
m_SchedulingOffset = offset ;
2013-02-09 18:39:43 +01:00
}
2018-01-04 04:25:35 +01:00
long Checkable : : GetSchedulingOffset ( )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
return m_SchedulingOffset ;
2013-02-09 18:39:43 +01:00
}
2016-03-15 13:02:38 +01:00
void Checkable : : UpdateNextCheck ( const MessageOrigin : : Ptr & origin )
2013-02-09 18:39:43 +01:00
{
double interval ;
2017-12-14 15:37:20 +01:00
if ( GetStateType ( ) = = StateTypeSoft & & GetLastCheckResult ( ) ! = nullptr )
2013-02-09 18:39:43 +01:00
interval = GetRetryInterval ( ) ;
else
interval = GetCheckInterval ( ) ;
double now = Utility : : GetTime ( ) ;
double adj = 0 ;
if ( interval > 1 )
2013-03-20 15:25:53 +01:00
adj = fmod ( now * 100 + GetSchedulingOffset ( ) , interval * 100 ) / 100.0 ;
2013-02-09 18:39:43 +01:00
2019-01-09 11:27:33 +01:00
if ( adj ! = 0.0 )
adj = std : : min ( 0.5 + fmod ( GetSchedulingOffset ( ) , interval * 5 ) / 100.0 , adj ) ;
2016-05-24 11:05:29 +02:00
2018-07-02 16:17:33 +02:00
double nextCheck = now - adj + interval ;
2019-01-16 17:27:38 +01:00
double lastCheck = GetLastCheck ( ) ;
2018-07-02 16:17:33 +02:00
Log ( LogDebug , " Checkable " )
< < " Update checkable ' " < < GetName ( ) < < " ' with check interval ' " < < GetCheckInterval ( )
2019-01-16 17:27:38 +01:00
< < " ' from last check time at " < < Utility : : FormatDateTime ( " %Y-%m-%d %H:%M:%S %z " , ( lastCheck < 0 ? 0 : lastCheck ) )
2018-07-02 16:17:33 +02:00
< < " ( " < < GetLastCheck ( ) < < " ) to next check time at " < < Utility : : FormatDateTime ( " %Y-%m-%d %H:%M:%S %z " , nextCheck ) < < " ( " < < nextCheck < < " ). " ;
SetNextCheck ( nextCheck , false , origin ) ;
2013-02-09 18:39:43 +01:00
}
2018-01-04 04:25:35 +01:00
bool Checkable : : HasBeenChecked ( ) const
2013-07-05 09:35:49 +02:00
{
2017-12-14 15:37:20 +01:00
return GetLastCheckResult ( ) ! = nullptr ;
2013-07-05 09:35:49 +02:00
}
2018-01-04 04:25:35 +01:00
double Checkable : : GetLastCheck ( ) const
2013-07-05 09:35:49 +02:00
{
2013-11-09 14:22:38 +01:00
CheckResult : : Ptr cr = GetLastCheckResult ( ) ;
2013-07-05 09:35:49 +02:00
double schedule_end = - 1 ;
2013-10-26 09:41:45 +02:00
if ( cr )
2013-11-09 14:22:38 +01:00
schedule_end = cr - > GetScheduleEnd ( ) ;
2013-07-05 09:35:49 +02:00
return schedule_end ;
}
2015-08-04 14:47:44 +02:00
void Checkable : : ProcessCheckResult ( const CheckResult : : Ptr & cr , const MessageOrigin : : Ptr & origin )
2013-02-09 18:39:43 +01:00
{
2014-03-12 10:05:36 +01:00
{
ObjectLock olock ( this ) ;
m_CheckRunning = false ;
}
2018-05-29 13:51:34 +02:00
if ( ! cr )
2016-08-08 14:17:44 +02:00
return ;
2013-03-19 16:20:13 +01:00
double now = Utility : : GetTime ( ) ;
2013-11-09 14:22:38 +01:00
if ( cr - > GetScheduleStart ( ) = = 0 )
cr - > SetScheduleStart ( now ) ;
2013-03-19 16:20:13 +01:00
2013-11-09 14:22:38 +01:00
if ( cr - > GetScheduleEnd ( ) = = 0 )
cr - > SetScheduleEnd ( now ) ;
2013-03-19 16:20:13 +01:00
2013-11-09 14:22:38 +01:00
if ( cr - > GetExecutionStart ( ) = = 0 )
cr - > SetExecutionStart ( now ) ;
2013-03-19 16:20:13 +01:00
2013-11-09 14:22:38 +01:00
if ( cr - > GetExecutionEnd ( ) = = 0 )
cr - > SetExecutionEnd ( now ) ;
2013-03-19 16:20:13 +01:00
2016-01-29 14:03:58 +01:00
if ( ! origin | | origin - > IsLocal ( ) )
2014-03-21 10:08:42 +01:00
cr - > SetCheckSource ( IcingaApplication : : GetInstance ( ) - > GetNodeName ( ) ) ;
2013-09-27 07:34:08 +02:00
2014-11-13 11:23:57 +01:00
Endpoint : : Ptr command_endpoint = GetCommandEndpoint ( ) ;
2015-09-05 15:18:10 +02:00
/* override check source if command_endpoint was defined */
2016-01-29 14:03:58 +01:00
if ( command_endpoint & & ! GetExtension ( " agent_check " ) )
2015-09-05 15:18:10 +02:00
cr - > SetCheckSource ( command_endpoint - > GetName ( ) ) ;
/* agent checks go through the api */
2015-01-18 22:15:35 +01:00
if ( command_endpoint & & GetExtension ( " agent_check " ) ) {
2014-11-13 11:23:57 +01:00
ApiListener : : Ptr listener = ApiListener : : GetInstance ( ) ;
if ( listener ) {
2015-01-18 22:15:35 +01:00
/* send message back to its origin */
2015-10-19 17:31:18 +02:00
Dictionary : : Ptr message = ClusterEvents : : MakeCheckResultMessage ( this , cr ) ;
2014-11-13 11:23:57 +01:00
listener - > SyncSendMessage ( command_endpoint , message ) ;
}
return ;
2015-01-18 22:15:35 +01:00
2014-11-13 11:23:57 +01:00
}
2018-05-29 13:51:34 +02:00
if ( ! IsActive ( ) )
return ;
2013-03-06 11:03:50 +01:00
bool reachable = IsReachable ( ) ;
2014-02-27 11:05:55 +01:00
bool notification_reachable = IsReachable ( DependencyNotification ) ;
2013-03-06 11:03:50 +01:00
2013-03-02 09:07:47 +01:00
ObjectLock olock ( this ) ;
2013-11-09 14:22:38 +01:00
CheckResult : : Ptr old_cr = GetLastCheckResult ( ) ;
2014-04-03 15:36:13 +02:00
ServiceState old_state = GetStateRaw ( ) ;
2013-03-07 12:04:20 +01:00
StateType old_stateType = GetStateType ( ) ;
2013-10-26 09:41:45 +02:00
long old_attempt = GetCheckAttempt ( ) ;
2014-07-22 14:13:21 +02:00
bool recovery = false ;
2013-02-09 18:39:43 +01:00
2016-03-10 14:32:57 +01:00
/* Ignore check results older than the current one. */
2013-11-09 14:22:38 +01:00
if ( old_cr & & cr - > GetExecutionStart ( ) < old_cr - > GetExecutionStart ( ) )
2013-09-12 17:39:29 +02:00
return ;
2013-03-25 18:36:15 +01:00
/* The ExecuteCheck function already sets the old state, but we need to do it again
2013-03-08 14:43:48 +01:00
* in case this was a passive check result . */
2014-04-03 15:36:13 +02:00
SetLastStateRaw ( old_state ) ;
2013-03-07 12:04:20 +01:00
SetLastStateType ( old_stateType ) ;
2013-03-19 13:04:30 +01:00
SetLastReachable ( reachable ) ;
2013-03-07 12:04:20 +01:00
2016-03-10 14:32:57 +01:00
Host : : Ptr host ;
Service : : Ptr service ;
tie ( host , service ) = GetHostService ( this ) ;
CheckableType checkableType = CheckableHost ;
if ( service )
checkableType = CheckableService ;
2014-03-10 08:56:31 +01:00
long attempt = 1 ;
2013-02-09 18:39:43 +01:00
2014-12-12 15:53:10 +01:00
std : : set < Checkable : : Ptr > children = GetChildren ( ) ;
2016-08-08 11:02:08 +02:00
if ( IsStateOK ( cr - > GetState ( ) ) ) {
2016-05-31 17:03:49 +02:00
SetStateType ( StateTypeHard ) ; // NOT-OK -> HARD OK
2013-02-09 18:39:43 +01:00
2016-08-24 11:13:19 +02:00
if ( ! IsStateOK ( old_state ) )
2016-05-31 17:03:49 +02:00
recovery = true ;
2014-07-22 14:13:21 +02:00
2013-07-18 17:04:09 +02:00
ResetNotificationNumbers ( ) ;
2015-11-02 14:10:44 +01:00
SaveLastState ( ServiceOK , Utility : : GetTime ( ) ) ;
2014-12-12 15:53:10 +01:00
/* update reachability for child objects in OK state */
if ( ! children . empty ( ) )
OnReachabilityChanged ( this , cr , children , origin ) ;
2013-02-09 18:39:43 +01:00
} else {
2016-09-27 11:29:25 +02:00
/* OK -> NOT-OK change, first SOFT state. Reset attempt counter. */
if ( IsStateOK ( old_state ) ) {
2013-02-09 18:39:43 +01:00
SetStateType ( StateTypeSoft ) ;
2016-09-27 11:29:25 +02:00
attempt = 1 ;
}
/* SOFT state change, increase attempt counter. */
if ( old_stateType = = StateTypeSoft & & ! IsStateOK ( old_state ) ) {
2015-02-20 21:30:14 +01:00
SetStateType ( StateTypeSoft ) ;
2016-09-27 11:29:25 +02:00
attempt = old_attempt + 1 ;
}
/* HARD state change (e.g. previously 2/3 and this next attempt). Reset attempt counter. */
if ( attempt > = GetMaxCheckAttempts ( ) ) {
SetStateType ( StateTypeHard ) ;
attempt = 1 ;
2013-02-09 18:39:43 +01:00
}
2013-02-24 01:10:34 +01:00
2016-03-15 09:46:20 +01:00
if ( ! IsStateOK ( cr - > GetState ( ) ) ) {
2015-11-02 14:10:44 +01:00
SaveLastState ( cr - > GetState ( ) , Utility : : GetTime ( ) ) ;
2013-11-09 14:22:38 +01:00
}
2014-12-12 15:53:10 +01:00
/* update reachability for child objects in NOT-OK state */
if ( ! children . empty ( ) )
OnReachabilityChanged ( this , cr , children , origin ) ;
2013-02-09 18:39:43 +01:00
}
2013-07-18 18:28:23 +02:00
if ( ! reachable )
SetLastStateUnreachable ( Utility : : GetTime ( ) ) ;
2013-10-26 09:41:45 +02:00
SetCheckAttempt ( attempt ) ;
2013-02-09 18:39:43 +01:00
2014-04-03 15:36:13 +02:00
ServiceState new_state = cr - > GetState ( ) ;
SetStateRaw ( new_state ) ;
2013-02-09 18:39:43 +01:00
2016-03-10 14:32:57 +01:00
bool stateChange ;
/* Exception on state change calculation for hosts. */
if ( checkableType = = CheckableService )
stateChange = ( old_state ! = new_state ) ;
else
stateChange = ( Host : : CalculateState ( old_state ) ! = Host : : CalculateState ( new_state ) ) ;
2013-06-21 10:20:29 +02:00
if ( stateChange ) {
2013-02-09 18:39:43 +01:00
SetLastStateChange ( now ) ;
/* remove acknowledgements */
if ( GetAcknowledgement ( ) = = AcknowledgementNormal | |
2017-12-19 15:50:05 +01:00
( GetAcknowledgement ( ) = = AcknowledgementSticky & & IsStateOK ( new_state ) ) ) {
2013-08-29 13:48:18 +02:00
ClearAcknowledgement ( ) ;
2013-02-09 18:39:43 +01:00
}
2014-04-03 15:36:13 +02:00
/* reschedule direct parents */
2016-08-25 06:19:44 +02:00
for ( const Checkable : : Ptr & parent : GetParents ( ) ) {
2014-04-03 15:36:13 +02:00
if ( parent . get ( ) = = this )
continue ;
2017-06-22 12:31:32 +02:00
if ( ! parent - > GetEnableActiveChecks ( ) )
continue ;
if ( parent - > GetNextCheck ( ) > = now + parent - > GetRetryInterval ( ) ) {
ObjectLock olock ( parent ) ;
parent - > SetNextCheck ( now ) ;
}
2013-02-09 18:39:43 +01:00
}
}
2013-06-19 10:57:07 +02:00
bool remove_acknowledgement_comments = false ;
if ( GetAcknowledgement ( ) = = AcknowledgementNone )
remove_acknowledgement_comments = true ;
2013-03-20 15:25:53 +01:00
bool hardChange = ( GetStateType ( ) = = StateTypeHard & & old_stateType = = StateTypeSoft ) ;
2014-04-03 15:36:13 +02:00
if ( stateChange & & old_stateType = = StateTypeHard & & GetStateType ( ) = = StateTypeHard )
2013-03-21 11:37:34 +01:00
hardChange = true ;
2015-01-08 16:18:11 +01:00
bool is_volatile = GetVolatile ( ) ;
2013-06-13 12:24:20 +02:00
2015-01-08 16:18:11 +01:00
if ( hardChange | | is_volatile ) {
2014-04-03 15:36:13 +02:00
SetLastHardStateRaw ( new_state ) ;
2013-03-02 09:07:47 +01:00
SetLastHardStateChange ( now ) ;
2013-07-05 09:35:49 +02:00
}
2013-03-02 09:07:47 +01:00
2016-03-15 09:46:20 +01:00
if ( ! IsStateOK ( new_state ) )
2013-02-09 18:39:43 +01:00
TriggerDowntimes ( ) ;
2014-05-26 20:56:34 +02:00
/* statistics for external tools */
2016-03-10 14:32:57 +01:00
Checkable : : UpdateStatistics ( cr , checkableType ) ;
2013-02-09 18:39:43 +01:00
2013-03-18 12:55:41 +01:00
bool in_downtime = IsInDowntime ( ) ;
2016-03-11 13:19:03 +01:00
bool send_notification = false ;
if ( notification_reachable & & ! in_downtime & & ! IsAcknowledged ( ) ) {
2018-07-21 10:38:09 +02:00
/* Send notifications whether when a hard state change occurred. */
2016-08-24 11:13:19 +02:00
if ( hardChange & & ! ( old_stateType = = StateTypeSoft & & IsStateOK ( new_state ) ) )
2016-03-11 13:19:03 +01:00
send_notification = true ;
/* Or if the checkable is volatile and in a HARD state. */
else if ( is_volatile & & GetStateType ( ) = = StateTypeHard )
send_notification = true ;
}
2013-03-18 12:55:41 +01:00
2016-03-15 09:46:20 +01:00
if ( IsStateOK ( old_state ) & & old_stateType = = StateTypeSoft )
2013-03-20 15:25:53 +01:00
send_notification = false ; /* Don't send notifications for SOFT-OK -> HARD-OK. */
2016-03-15 09:46:20 +01:00
if ( is_volatile & & IsStateOK ( old_state ) & & IsStateOK ( new_state ) )
2015-01-08 16:18:11 +01:00
send_notification = false ; /* Don't send notifications for volatile OK -> OK changes. */
2013-03-02 09:07:47 +01:00
olock . Unlock ( ) ;
2013-02-09 18:39:43 +01:00
2013-06-19 10:57:07 +02:00
if ( remove_acknowledgement_comments )
RemoveCommentsByType ( CommentAcknowledgement ) ;
2018-01-11 11:17:38 +01:00
Dictionary : : Ptr vars_after = new Dictionary ( {
{ " state " , new_state } ,
{ " state_type " , GetStateType ( ) } ,
{ " attempt " , GetCheckAttempt ( ) } ,
{ " reachable " , reachable }
} ) ;
2013-03-19 13:04:30 +01:00
if ( old_cr )
2013-11-09 14:22:38 +01:00
cr - > SetVarsBefore ( old_cr - > GetVarsAfter ( ) ) ;
2013-03-19 13:04:30 +01:00
2013-11-09 14:22:38 +01:00
cr - > SetVarsAfter ( vars_after ) ;
2013-03-19 13:04:30 +01:00
2013-03-07 15:00:26 +01:00
olock . Lock ( ) ;
SetLastCheckResult ( cr ) ;
2013-06-21 10:20:29 +02:00
2017-10-19 17:32:52 +02:00
bool was_flapping = IsFlapping ( ) ;
2013-06-21 10:20:29 +02:00
2017-10-19 17:32:52 +02:00
UpdateFlappingStatus ( old_state ! = cr - > GetState ( ) ) ;
2016-03-10 14:32:57 +01:00
2017-10-19 17:32:52 +02:00
bool is_flapping = IsFlapping ( ) ;
2013-06-21 10:20:29 +02:00
2016-03-15 13:02:38 +01:00
if ( cr - > GetActive ( ) ) {
2016-05-24 11:05:29 +02:00
UpdateNextCheck ( origin ) ;
2016-03-15 13:02:38 +01:00
} else {
2018-01-11 17:10:46 +01:00
/* Reschedule the next check for external passive check results. The side effect of
* this is that for as long as we receive results for a service we
2016-03-15 13:02:38 +01:00
* won ' t execute any active checks . */
2018-01-11 17:10:46 +01:00
double offset ;
double ttl = cr - > GetTtl ( ) ;
if ( ttl > 0 )
offset = ttl ;
else
offset = GetCheckInterval ( ) ;
SetNextCheck ( Utility : : GetTime ( ) + offset , false , origin ) ;
2016-03-15 13:02:38 +01:00
}
2013-03-07 15:00:26 +01:00
olock . Unlock ( ) ;
2017-11-08 12:12:27 +01:00
# ifdef I2_DEBUG /* I2_DEBUG */
Log ( LogDebug , " Checkable " )
2017-12-19 15:50:05 +01:00
< < " Flapping: Checkable " < < GetName ( )
< < " was: " < < was_flapping
< < " is: " < < is_flapping
< < " threshold low: " < < GetFlappingThresholdLow ( )
< < " threshold high: " < < GetFlappingThresholdHigh ( )
< < " % current: " < < GetFlappingCurrent ( ) < < " %. " ;
2017-11-08 12:12:27 +01:00
# endif /* I2_DEBUG */
2013-07-01 17:25:30 +02:00
2014-11-08 21:17:16 +01:00
OnNewCheckResult ( this , cr , origin ) ;
2014-03-09 18:06:24 +01:00
/* signal status updates to for example db_ido */
2014-11-08 21:17:16 +01:00
OnStateChanged ( this ) ;
2013-03-02 09:07:47 +01:00
2014-05-25 12:45:29 +02:00
String old_state_str = ( service ? Service : : StateToString ( old_state ) : Host : : StateToString ( Host : : CalculateState ( old_state ) ) ) ;
String new_state_str = ( service ? Service : : StateToString ( new_state ) : Host : : StateToString ( Host : : CalculateState ( new_state ) ) ) ;
2016-05-21 13:41:43 +02:00
/* Whether a hard state change or a volatile state change except OK -> OK happened. */
2016-05-21 14:16:47 +02:00
if ( hardChange | | ( is_volatile & & ! ( IsStateOK ( old_state ) & & IsStateOK ( new_state ) ) ) ) {
2014-11-08 21:17:16 +01:00
OnStateChange ( this , cr , StateTypeHard , origin ) ;
2014-10-19 17:52:17 +02:00
Log ( LogNotice , " Checkable " )
2017-12-19 15:50:05 +01:00
< < " State Change: Checkable ' " < < GetName ( ) < < " ' hard state change from " < < old_state_str < < " to " < < new_state_str < < " detected. " < < ( is_volatile ? " Checkable is volatile. " : " " ) ;
2016-06-13 10:09:18 +02:00
}
/* Whether a state change happened or the state type is SOFT (must be logged too). */
else if ( stateChange | | GetStateType ( ) = = StateTypeSoft ) {
2014-11-08 21:17:16 +01:00
OnStateChange ( this , cr , StateTypeSoft , origin ) ;
2014-10-19 17:52:17 +02:00
Log ( LogNotice , " Checkable " )
2017-12-19 15:50:05 +01:00
< < " State Change: Checkable ' " < < GetName ( ) < < " ' soft state change from " < < old_state_str < < " to " < < new_state_str < < " detected. " ;
2014-05-22 23:47:03 +02:00
}
2013-09-25 18:01:08 +02:00
2016-05-21 13:41:43 +02:00
if ( GetStateType ( ) = = StateTypeSoft | | hardChange | | recovery | |
2017-12-19 15:50:05 +01:00
( is_volatile & & ! ( IsStateOK ( old_state ) & & IsStateOK ( new_state ) ) ) )
2013-06-13 11:33:00 +02:00
ExecuteEventHandler ( ) ;
2016-06-13 10:12:38 +02:00
/* Flapping start/end notifications */
2017-10-19 17:32:52 +02:00
if ( ! in_downtime & & ! was_flapping & & is_flapping ) {
2016-11-10 14:02:02 +01:00
/* FlappingStart notifications happen on state changes, not in downtimes */
2016-06-13 10:12:38 +02:00
if ( ! IsPaused ( ) )
2017-11-30 08:36:35 +01:00
OnNotificationsRequested ( this , NotificationFlappingStart , cr , " " , " " , nullptr ) ;
2016-06-13 10:12:38 +02:00
Log ( LogNotice , " Checkable " )
2017-12-19 15:50:05 +01:00
< < " Flapping Start: Checkable ' " < < GetName ( ) < < " ' started flapping (Current flapping value "
< < GetFlappingCurrent ( ) < < " % > high threshold " < < GetFlappingThresholdHigh ( ) < < " %). " ;
2016-06-13 10:12:38 +02:00
NotifyFlapping ( origin ) ;
2016-11-10 14:02:02 +01:00
} else if ( ! in_downtime & & was_flapping & & ! is_flapping ) {
/* FlappingEnd notifications are independent from state changes, must not happen in downtine */
2016-06-13 10:12:38 +02:00
if ( ! IsPaused ( ) )
2017-11-30 08:36:35 +01:00
OnNotificationsRequested ( this , NotificationFlappingEnd , cr , " " , " " , nullptr ) ;
2016-06-13 10:12:38 +02:00
Log ( LogNotice , " Checkable " )
2017-12-19 15:50:05 +01:00
< < " Flapping Stop: Checkable ' " < < GetName ( ) < < " ' stopped flapping (Current flapping value "
< < GetFlappingCurrent ( ) < < " % < low threshold " < < GetFlappingThresholdLow ( ) < < " %). " ;
2016-06-13 10:12:38 +02:00
NotifyFlapping ( origin ) ;
}
2016-08-24 11:13:19 +02:00
if ( send_notification & & ! is_flapping ) {
2016-06-13 10:12:38 +02:00
if ( ! IsPaused ( ) )
2017-11-30 08:36:35 +01:00
OnNotificationsRequested ( this , recovery ? NotificationRecovery : NotificationProblem , cr , " " , " " , nullptr ) ;
2016-02-22 19:43:44 +01:00
}
2013-02-09 18:39:43 +01:00
}
2015-01-18 22:15:35 +01:00
void Checkable : : ExecuteRemoteCheck ( const Dictionary : : Ptr & resolvedMacros )
{
CONTEXT ( " Executing remote check for object ' " + GetName ( ) + " ' " ) ;
double scheduled_start = GetNextCheck ( ) ;
double before_check = Utility : : GetTime ( ) ;
CheckResult : : Ptr cr = new CheckResult ( ) ;
cr - > SetScheduleStart ( scheduled_start ) ;
cr - > SetExecutionStart ( before_check ) ;
GetCheckCommand ( ) - > Execute ( this , cr , resolvedMacros , true ) ;
}
2018-01-04 04:25:35 +01:00
void Checkable : : ExecuteCheck ( )
2013-02-09 18:39:43 +01:00
{
2014-04-03 15:36:13 +02:00
CONTEXT ( " Executing check for object ' " + GetName ( ) + " ' " ) ;
2013-11-19 07:49:41 +01:00
2016-05-10 11:12:37 +02:00
/* keep track of scheduling info in case the check type doesn't provide its own information */
double scheduled_start = GetNextCheck ( ) ;
double before_check = Utility : : GetTime ( ) ;
2018-07-02 16:17:53 +02:00
/* This calls SetNextCheck() which updates the CheckerComponent's idle/pending
* queues and ensures that checks are not fired multiple times . ProcessCheckResult ( )
* is called too late . See # 6421.
*/
UpdateNextCheck ( ) ;
2013-03-19 14:13:58 +01:00
bool reachable = IsReachable ( ) ;
2013-03-06 11:03:50 +01:00
{
ObjectLock olock ( this ) ;
/* don't run another check if there is one pending */
2013-03-25 18:36:15 +01:00
if ( m_CheckRunning )
2013-03-06 11:03:50 +01:00
return ;
m_CheckRunning = true ;
2013-03-08 14:43:48 +01:00
2014-04-03 15:36:13 +02:00
SetLastStateRaw ( GetStateRaw ( ) ) ;
2013-03-08 14:43:48 +01:00
SetLastStateType ( GetLastStateType ( ) ) ;
2013-03-19 14:13:58 +01:00
SetLastReachable ( reachable ) ;
2013-02-09 18:39:43 +01:00
}
2015-01-18 22:15:35 +01:00
CheckResult : : Ptr cr = new CheckResult ( ) ;
2013-03-25 18:36:15 +01:00
2015-01-18 22:15:35 +01:00
cr - > SetScheduleStart ( scheduled_start ) ;
cr - > SetExecutionStart ( before_check ) ;
2013-02-09 18:39:43 +01:00
2014-11-13 11:23:57 +01:00
Endpoint : : Ptr endpoint = GetCommandEndpoint ( ) ;
2015-01-18 22:15:35 +01:00
bool local = ! endpoint | | endpoint = = Endpoint : : GetLocalEndpoint ( ) ;
2014-11-13 11:23:57 +01:00
2015-01-18 22:15:35 +01:00
if ( local ) {
2017-12-14 15:37:20 +01:00
GetCheckCommand ( ) - > Execute ( this , cr , nullptr , false ) ;
2015-01-18 22:15:35 +01:00
} else {
Dictionary : : Ptr macros = new Dictionary ( ) ;
GetCheckCommand ( ) - > Execute ( this , cr , macros , false ) ;
2014-11-13 11:23:57 +01:00
2015-10-22 10:52:38 +02:00
if ( endpoint - > GetConnected ( ) ) {
2015-01-18 22:15:35 +01:00
/* perform check on remote endpoint */
2014-11-13 11:23:57 +01:00
Dictionary : : Ptr message = new Dictionary ( ) ;
message - > Set ( " jsonrpc " , " 2.0 " ) ;
message - > Set ( " method " , " event::ExecuteCommand " ) ;
Host : : Ptr host ;
Service : : Ptr service ;
tie ( host , service ) = GetHostService ( this ) ;
Dictionary : : Ptr params = new Dictionary ( ) ;
message - > Set ( " params " , params ) ;
params - > Set ( " command_type " , " check_command " ) ;
params - > Set ( " command " , GetCheckCommand ( ) - > GetName ( ) ) ;
params - > Set ( " host " , host - > GetName ( ) ) ;
if ( service )
params - > Set ( " service " , service - > GetShortName ( ) ) ;
params - > Set ( " macros " , macros ) ;
ApiListener : : Ptr listener = ApiListener : : GetInstance ( ) ;
if ( listener )
listener - > SyncSendMessage ( endpoint , message ) ;
2015-01-18 22:15:35 +01:00
2016-01-21 10:32:38 +01:00
/* Re-schedule the check so we don't run it again until after we've received
2017-12-19 15:50:05 +01:00
* a check result from the remote instance . The check will be re - scheduled
* using the proper check interval once we ' ve received a check result .
*/
2016-01-21 10:32:38 +01:00
SetNextCheck ( Utility : : GetTime ( ) + GetCheckCommand ( ) - > GetTimeout ( ) + 30 ) ;
2016-10-24 08:38:58 +02:00
} else if ( ! endpoint - > GetSyncing ( ) & & Application : : GetInstance ( ) - > GetStartTime ( ) < Utility : : GetTime ( ) - 300 ) {
2015-01-18 22:15:35 +01:00
/* fail to perform check on unconnected endpoint */
cr - > SetState ( ServiceUnknown ) ;
2016-04-19 09:35:48 +02:00
String output = " Remote Icinga instance ' " + endpoint - > GetName ( ) + " ' is not connected to " ;
Endpoint : : Ptr localEndpoint = Endpoint : : GetLocalEndpoint ( ) ;
if ( localEndpoint )
output + = " ' " + localEndpoint - > GetName ( ) + " ' " ;
else
output + = " this instance " ;
cr - > SetOutput ( output ) ;
2015-01-18 22:15:35 +01:00
ProcessCheckResult ( cr ) ;
2014-11-13 11:23:57 +01:00
}
{
ObjectLock olock ( this ) ;
m_CheckRunning = false ;
}
}
2013-02-09 18:39:43 +01:00
}
2013-02-11 23:37:39 +01:00
2014-05-26 20:56:34 +02:00
void Checkable : : UpdateStatistics ( const CheckResult : : Ptr & cr , CheckableType type )
2013-02-11 23:37:39 +01:00
{
2013-11-09 14:22:38 +01:00
time_t ts = cr - > GetScheduleEnd ( ) ;
2014-05-26 20:56:34 +02:00
if ( type = = CheckableHost ) {
if ( cr - > GetActive ( ) )
CIB : : UpdateActiveHostChecksStatistics ( ts , 1 ) ;
else
CIB : : UpdatePassiveHostChecksStatistics ( ts , 1 ) ;
} else if ( type = = CheckableService ) {
if ( cr - > GetActive ( ) )
CIB : : UpdateActiveServiceChecksStatistics ( ts , 1 ) ;
else
CIB : : UpdatePassiveServiceChecksStatistics ( ts , 1 ) ;
} else {
2014-05-28 13:45:45 +02:00
Log ( LogWarning , " Checkable " , " Unknown checkable type for statistic update. " ) ;
2014-05-26 20:56:34 +02:00
}
2013-02-11 23:37:39 +01:00
}
2016-05-12 13:46:22 +02:00
2018-01-04 04:25:35 +01:00
void Checkable : : IncreasePendingChecks ( )
2016-05-12 13:46:22 +02:00
{
boost : : mutex : : scoped_lock lock ( m_StatsMutex ) ;
m_PendingChecks + + ;
}
2018-01-04 04:25:35 +01:00
void Checkable : : DecreasePendingChecks ( )
2016-05-12 13:46:22 +02:00
{
boost : : mutex : : scoped_lock lock ( m_StatsMutex ) ;
m_PendingChecks - - ;
2018-01-16 10:40:08 +01:00
m_PendingChecksCV . notify_one ( ) ;
2016-05-12 13:46:22 +02:00
}
2018-01-04 04:25:35 +01:00
int Checkable : : GetPendingChecks ( )
2016-05-12 13:46:22 +02:00
{
boost : : mutex : : scoped_lock lock ( m_StatsMutex ) ;
return m_PendingChecks ;
}
2018-01-16 10:40:08 +01:00
void Checkable : : AquirePendingCheckSlot ( int maxPendingChecks )
{
boost : : mutex : : scoped_lock lock ( m_StatsMutex ) ;
while ( m_PendingChecks > = maxPendingChecks )
m_PendingChecksCV . wait ( lock ) ;
m_PendingChecks + + ;
}