2013-02-09 18:39:43 +01:00
/******************************************************************************
* Icinga 2 *
* Copyright ( C ) 2012 Icinga Development Team ( http : //www.icinga.org/) *
* *
* 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 . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-03-16 21:18:53 +01:00
# include "icinga/service.h"
2013-06-13 11:33:00 +02:00
# include "icinga/checkcommand.h"
2013-03-17 20:19:29 +01:00
# include "icinga/icingaapplication.h"
# include "icinga/checkresultmessage.h"
2013-07-01 14:29:07 +02:00
# include "icinga/flappingmessage.h"
2013-03-17 20:19:29 +01:00
# include "icinga/cib.h"
# include "remoting/endpointmanager.h"
2013-03-16 21:18:53 +01:00
# include "base/dynamictype.h"
# include "base/objectlock.h"
# include "base/logger_fwd.h"
2013-07-01 17:25:30 +02:00
# include "base/convert.h"
2013-03-16 21:18:53 +01:00
# include <boost/smart_ptr/make_shared.hpp>
# include <boost/foreach.hpp>
# include <boost/exception/diagnostic_information.hpp>
2013-07-30 22:38:33 +02:00
# include <boost/algorithm/string/replace.hpp>
2013-02-09 18:39:43 +01:00
using namespace icinga ;
const int Service : : DefaultMaxCheckAttempts = 3 ;
2013-03-07 12:04:20 +01:00
const double Service : : DefaultCheckInterval = 5 * 60 ;
const double Service : : CheckIntervalDivisor = 5.0 ;
2013-02-09 18:39:43 +01:00
2013-03-16 21:18:53 +01:00
boost : : signals2 : : signal < void ( const Service : : Ptr & ) > Service : : OnCheckerChanged ;
boost : : signals2 : : signal < void ( const Service : : Ptr & ) > Service : : OnNextCheckChanged ;
2013-07-01 14:29:07 +02:00
boost : : signals2 : : signal < void ( const Service : : Ptr & , FlappingState ) > Service : : OnFlappingChanged ;
2013-02-09 18:39:43 +01:00
2013-06-13 11:33:00 +02:00
CheckCommand : : Ptr Service : : GetCheckCommand ( void ) const
2013-02-09 18:39:43 +01:00
{
2013-06-13 11:33:00 +02:00
return CheckCommand : : GetByName ( m_CheckCommand ) ;
2013-02-09 18:39:43 +01:00
}
long Service : : GetMaxCheckAttempts ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_MaxCheckAttempts . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return DefaultMaxCheckAttempts ;
2013-02-26 10:13:54 +01:00
return m_MaxCheckAttempts ;
2013-02-09 18:39:43 +01:00
}
2013-03-13 16:04:53 +01:00
TimePeriod : : Ptr Service : : GetCheckPeriod ( void ) const
{
return TimePeriod : : GetByName ( m_CheckPeriod ) ;
}
2013-02-09 18:39:43 +01:00
double Service : : GetCheckInterval ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_CheckInterval . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return DefaultCheckInterval ;
2013-02-26 10:13:54 +01:00
return m_CheckInterval ;
2013-02-09 18:39:43 +01:00
}
double Service : : GetRetryInterval ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_RetryInterval . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return GetCheckInterval ( ) / CheckIntervalDivisor ;
2013-02-26 10:13:54 +01:00
return m_RetryInterval ;
2013-02-09 18:39:43 +01:00
}
2013-03-14 12:17:46 +01:00
Array : : Ptr Service : : GetCheckers ( void ) const
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
return m_Checkers ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetSchedulingOffset ( long offset )
{
2013-02-26 10:13:54 +01:00
m_SchedulingOffset = offset ;
2013-02-09 18:39:43 +01:00
}
long Service : : GetSchedulingOffset ( void )
{
2013-02-26 10:13:54 +01:00
return m_SchedulingOffset ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetNextCheck ( double nextCheck )
{
2013-02-26 10:13:54 +01:00
m_NextCheck = nextCheck ;
Touch ( " next_check " ) ;
2013-02-09 18:39:43 +01:00
}
double Service : : GetNextCheck ( void )
{
2013-02-26 10:13:54 +01:00
return m_NextCheck ;
2013-02-09 18:39:43 +01:00
}
void Service : : UpdateNextCheck ( void )
{
2013-03-02 09:07:47 +01:00
ObjectLock olock ( this ) ;
2013-02-09 18:39:43 +01:00
double interval ;
if ( GetStateType ( ) = = StateTypeSoft )
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
SetNextCheck ( now - adj + interval ) ;
}
2013-02-26 10:13:54 +01:00
void Service : : SetCurrentChecker ( const String & checker )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
m_CurrentChecker = checker ;
Touch ( " current_checker " ) ;
2013-02-09 18:39:43 +01:00
}
2013-02-26 10:13:54 +01:00
String Service : : GetCurrentChecker ( void ) const
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
return m_CurrentChecker ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetCurrentCheckAttempt ( long attempt )
{
2013-02-26 10:13:54 +01:00
m_CheckAttempt = attempt ;
Touch ( " check_attempt " ) ;
2013-02-09 18:39:43 +01:00
}
long Service : : GetCurrentCheckAttempt ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_CheckAttempt . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return 1 ;
2013-02-26 10:13:54 +01:00
return m_CheckAttempt ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetState ( ServiceState state )
{
2013-02-26 10:13:54 +01:00
m_State = static_cast < long > ( state ) ;
Touch ( " state " ) ;
2013-02-09 18:39:43 +01:00
}
ServiceState Service : : GetState ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_State . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return StateUnknown ;
2013-02-26 10:13:54 +01:00
int ivalue = static_cast < int > ( m_State ) ;
2013-02-09 18:39:43 +01:00
return static_cast < ServiceState > ( ivalue ) ;
}
2013-03-07 12:04:20 +01:00
void Service : : SetLastState ( ServiceState state )
{
m_LastState = static_cast < long > ( state ) ;
Touch ( " last_state " ) ;
}
ServiceState Service : : GetLastState ( void ) const
{
if ( m_LastState . IsEmpty ( ) )
return StateUnknown ;
int ivalue = static_cast < int > ( m_LastState ) ;
return static_cast < ServiceState > ( ivalue ) ;
}
2013-07-05 09:35:49 +02:00
void Service : : SetLastHardState ( ServiceState state )
{
m_LastHardState = static_cast < long > ( state ) ;
Touch ( " last_hard_state " ) ;
}
ServiceState Service : : GetLastHardState ( void ) const
{
if ( m_LastHardState . IsEmpty ( ) )
return StateUnknown ;
int ivalue = static_cast < int > ( m_LastHardState ) ;
return static_cast < ServiceState > ( ivalue ) ;
}
2013-03-07 12:04:20 +01:00
void Service : : SetStateType ( StateType type )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
m_StateType = static_cast < long > ( type ) ;
Touch ( " state_type " ) ;
2013-02-09 18:39:43 +01:00
}
2013-03-07 12:04:20 +01:00
StateType Service : : GetStateType ( void ) const
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
if ( m_StateType . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return StateTypeSoft ;
2013-02-26 10:13:54 +01:00
int ivalue = static_cast < int > ( m_StateType ) ;
2013-03-07 12:04:20 +01:00
return static_cast < StateType > ( ivalue ) ;
}
void Service : : SetLastStateType ( StateType type )
{
m_LastStateType = static_cast < long > ( type ) ;
Touch ( " last_state_type " ) ;
}
StateType Service : : GetLastStateType ( void ) const
{
if ( m_LastStateType . IsEmpty ( ) )
return StateTypeSoft ;
int ivalue = static_cast < int > ( m_LastStateType ) ;
return static_cast < StateType > ( ivalue ) ;
2013-02-09 18:39:43 +01:00
}
2013-07-18 18:16:39 +02:00
void Service : : SetLastStateOK ( double ts )
{
m_LastStateOK = ts ;
Touch ( " last_state_ok " ) ;
}
double Service : : GetLastStateOK ( void ) const
{
if ( m_LastStateOK . IsEmpty ( ) )
return 0 ;
return m_LastStateOK ;
}
void Service : : SetLastStateWarning ( double ts )
{
m_LastStateWarning = ts ;
Touch ( " last_state_warning " ) ;
}
double Service : : GetLastStateWarning ( void ) const
{
if ( m_LastStateWarning . IsEmpty ( ) )
return 0 ;
return m_LastStateWarning ;
}
void Service : : SetLastStateCritical ( double ts )
{
m_LastStateCritical = ts ;
Touch ( " last_state_critical " ) ;
}
double Service : : GetLastStateCritical ( void ) const
{
if ( m_LastStateCritical . IsEmpty ( ) )
return 0 ;
return m_LastStateCritical ;
}
void Service : : SetLastStateUnknown ( double ts )
{
m_LastStateUnknown = ts ;
Touch ( " last_state_unknown " ) ;
}
double Service : : GetLastStateUnknown ( void ) const
{
if ( m_LastStateUnknown . IsEmpty ( ) )
return 0 ;
return m_LastStateUnknown ;
}
void Service : : SetLastStateUnreachable ( double ts )
{
m_LastStateUnreachable = ts ;
Touch ( " last_state_unreachable " ) ;
}
double Service : : GetLastStateUnreachable ( void ) const
{
if ( m_LastStateUnreachable . IsEmpty ( ) )
return 0 ;
return m_LastStateUnreachable ;
}
2013-03-19 13:04:30 +01:00
void Service : : SetLastReachable ( bool reachable )
{
m_LastReachable = reachable ;
Touch ( " last_reachable " ) ;
}
bool Service : : GetLastReachable ( void ) const
{
if ( m_LastReachable . IsEmpty ( ) )
return true ;
return m_LastReachable ;
}
2013-02-09 18:39:43 +01:00
void Service : : SetLastCheckResult ( const Dictionary : : Ptr & result )
{
2013-02-26 10:13:54 +01:00
m_LastResult = result ;
Touch ( " last_result " ) ;
2013-02-09 18:39:43 +01:00
}
Dictionary : : Ptr Service : : GetLastCheckResult ( void ) const
{
2013-02-26 10:13:54 +01:00
return m_LastResult ;
2013-02-09 18:39:43 +01:00
}
2013-07-05 09:35:49 +02:00
bool Service : : HasBeenChecked ( void ) const
{
return GetLastCheckResult ( ) ;
}
double Service : : GetLastCheck ( void ) const
{
Dictionary : : Ptr cr = GetLastCheckResult ( ) ;
double schedule_end = - 1 ;
if ( cr ) {
schedule_end = cr - > Get ( " schedule_end " ) ;
}
return schedule_end ;
}
String Service : : GetLastCheckOutput ( void ) const
{
Dictionary : : Ptr cr = GetLastCheckResult ( ) ;
String output ;
if ( cr ) {
String raw_output = cr - > Get ( " output " ) ;
size_t line_end = raw_output . Find ( " \n " ) ;
output = raw_output . SubStr ( 0 , line_end ) ;
}
return output ;
}
String Service : : GetLastCheckLongOutput ( void ) const
{
Dictionary : : Ptr cr = GetLastCheckResult ( ) ;
String long_output ;
if ( cr ) {
String raw_output = cr - > Get ( " output " ) ;
size_t line_end = raw_output . Find ( " \n " ) ;
if ( line_end > 0 & & line_end ! = String : : NPos ) {
long_output = raw_output . SubStr ( line_end + 1 , raw_output . GetLength ( ) ) ;
boost : : algorithm : : replace_all ( long_output , " \n " , " \\ n " ) ;
}
}
return long_output ;
}
String Service : : GetLastCheckPerfData ( void ) const
{
Dictionary : : Ptr cr = GetLastCheckResult ( ) ;
2013-07-10 09:57:18 +02:00
String perfdata ;
2013-07-05 09:35:49 +02:00
2013-07-10 09:57:18 +02:00
if ( cr ) {
perfdata = cr - > Get ( " performance_data_raw " ) ;
boost : : algorithm : : replace_all ( perfdata , " \n " , " \\ n " ) ;
}
2013-07-05 09:35:49 +02:00
return perfdata ;
}
2013-02-09 18:39:43 +01:00
void Service : : SetLastStateChange ( double ts )
{
2013-02-26 10:13:54 +01:00
m_LastStateChange = ts ;
Touch ( " last_state_change " ) ;
2013-02-09 18:39:43 +01:00
}
double Service : : GetLastStateChange ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_LastStateChange . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return IcingaApplication : : GetInstance ( ) - > GetStartTime ( ) ;
2013-02-26 10:13:54 +01:00
return m_LastStateChange ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetLastHardStateChange ( double ts )
{
2013-02-26 10:13:54 +01:00
m_LastHardStateChange = ts ;
Touch ( " last_hard_state_change " ) ;
2013-02-09 18:39:43 +01:00
}
double Service : : GetLastHardStateChange ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_LastHardStateChange . IsEmpty ( ) )
return IcingaApplication : : GetInstance ( ) - > GetStartTime ( ) ;
2013-02-09 18:39:43 +01:00
2013-02-26 10:13:54 +01:00
return m_LastHardStateChange ;
2013-02-09 18:39:43 +01:00
}
bool Service : : GetEnableActiveChecks ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_EnableActiveChecks . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return true ;
2013-02-26 12:37:25 +01:00
else
return m_EnableActiveChecks ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetEnableActiveChecks ( bool enabled )
{
2013-02-26 10:13:54 +01:00
m_EnableActiveChecks = enabled ? 1 : 0 ;
Touch ( " enable_active_checks " ) ;
2013-02-09 18:39:43 +01:00
}
bool Service : : GetEnablePassiveChecks ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_EnablePassiveChecks . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return true ;
2013-02-26 12:37:25 +01:00
else
return m_EnablePassiveChecks ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetEnablePassiveChecks ( bool enabled )
{
2013-02-26 10:13:54 +01:00
m_EnablePassiveChecks = enabled ? 1 : 0 ;
Touch ( " enable_passive_checks " ) ;
2013-02-09 18:39:43 +01:00
}
bool Service : : GetForceNextCheck ( void ) const
{
2013-02-26 10:13:54 +01:00
if ( m_ForceNextCheck . IsEmpty ( ) )
2013-02-09 18:39:43 +01:00
return false ;
2013-02-26 10:13:54 +01:00
return static_cast < bool > ( m_ForceNextCheck ) ;
2013-02-09 18:39:43 +01:00
}
void Service : : SetForceNextCheck ( bool forced )
{
2013-02-26 10:13:54 +01:00
m_ForceNextCheck = forced ? 1 : 0 ;
Touch ( " force_next_check " ) ;
2013-02-09 18:39:43 +01:00
}
2013-03-02 09:07:47 +01:00
void Service : : ProcessCheckResult ( const Dictionary : : Ptr & cr )
2013-02-09 18:39:43 +01:00
{
2013-03-19 16:20:13 +01:00
double now = Utility : : GetTime ( ) ;
if ( ! cr - > Contains ( " schedule_start " ) )
cr - > Set ( " schedule_start " , now ) ;
if ( ! cr - > Contains ( " schedule_end " ) )
cr - > Set ( " schedule_end " , now ) ;
if ( ! cr - > Contains ( " execution_start " ) )
cr - > Set ( " execution_start " , now ) ;
if ( ! cr - > Contains ( " execution_end " ) )
cr - > Set ( " execution_end " , now ) ;
2013-03-06 11:03:50 +01:00
bool reachable = IsReachable ( ) ;
2013-03-19 13:04:30 +01:00
Host : : Ptr host = GetHost ( ) ;
bool host_reachable = true ;
if ( host )
host_reachable = host - > IsReachable ( ) ;
2013-03-07 16:00:10 +01:00
ASSERT ( ! OwnsLock ( ) ) ;
2013-03-02 09:07:47 +01:00
ObjectLock olock ( this ) ;
2013-03-19 13:04:30 +01:00
Dictionary : : Ptr old_cr = GetLastCheckResult ( ) ;
2013-02-09 18:39:43 +01:00
ServiceState old_state = GetState ( ) ;
2013-03-07 12:04:20 +01:00
StateType old_stateType = GetStateType ( ) ;
2013-03-19 13:04:30 +01:00
long old_attempt = GetCurrentCheckAttempt ( ) ;
2013-02-24 01:10:34 +01:00
bool recovery ;
2013-02-09 18:39:43 +01:00
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 . */
2013-03-07 12:04:20 +01:00
SetLastState ( old_state ) ;
SetLastStateType ( old_stateType ) ;
2013-03-19 13:04:30 +01:00
SetLastReachable ( reachable ) ;
2013-03-07 12:04:20 +01:00
2013-03-19 13:04:30 +01:00
long attempt ;
2013-02-09 18:39:43 +01:00
if ( cr - > Get ( " state " ) = = StateOK ) {
2013-02-27 12:44:51 +01:00
if ( old_state = = StateOK & & old_stateType = = StateTypeSoft )
2013-03-20 15:25:53 +01:00
SetStateType ( StateTypeHard ) ; // SOFT OK -> HARD OK
2013-02-09 18:39:43 +01:00
attempt = 1 ;
2013-02-24 01:10:34 +01:00
recovery = true ;
2013-07-18 17:04:09 +02:00
ResetNotificationNumbers ( ) ;
2013-07-18 18:16:39 +02:00
SetLastStateOK ( Utility : : GetTime ( ) ) ;
2013-02-09 18:39:43 +01:00
} else {
2013-03-19 13:04:30 +01:00
if ( old_attempt > = GetMaxCheckAttempts ( ) ) {
2013-02-09 18:39:43 +01:00
SetStateType ( StateTypeHard ) ;
attempt = 1 ;
} else if ( GetStateType ( ) = = StateTypeSoft | | GetState ( ) = = StateOK ) {
SetStateType ( StateTypeSoft ) ;
2013-03-19 13:04:30 +01:00
attempt = old_attempt + 1 ;
} else {
attempt = old_attempt ;
2013-02-09 18:39:43 +01:00
}
2013-02-24 01:10:34 +01:00
recovery = false ;
2013-07-18 18:16:39 +02:00
if ( cr - > Get ( " state " ) = = StateWarning )
SetLastStateWarning ( Utility : : GetTime ( ) ) ;
if ( cr - > Get ( " state " ) = = StateCritical )
SetLastStateCritical ( Utility : : GetTime ( ) ) ;
if ( cr - > Get ( " state " ) = = StateUnknown )
SetLastStateUnknown ( Utility : : GetTime ( ) ) ;
2013-02-09 18:39:43 +01:00
}
2013-07-18 18:28:23 +02:00
if ( ! reachable )
SetLastStateUnreachable ( Utility : : GetTime ( ) ) ;
2013-02-09 18:39:43 +01:00
SetCurrentCheckAttempt ( attempt ) ;
int state = cr - > Get ( " state " ) ;
SetState ( static_cast < ServiceState > ( state ) ) ;
2013-06-13 11:33:00 +02:00
bool call_eventhandler = false ;
2013-06-21 10:20:29 +02:00
bool stateChange = ( old_state ! = GetState ( ) ) ;
if ( stateChange ) {
2013-02-09 18:39:43 +01:00
SetLastStateChange ( now ) ;
/* remove acknowledgements */
if ( GetAcknowledgement ( ) = = AcknowledgementNormal | |
( GetAcknowledgement ( ) = = AcknowledgementSticky & & GetStateType ( ) = = StateTypeHard & & GetState ( ) = = StateOK ) ) {
SetAcknowledgement ( AcknowledgementNone ) ;
SetAcknowledgementExpiry ( 0 ) ;
}
/* reschedule service dependencies */
2013-03-02 09:07:47 +01:00
BOOST_FOREACH ( const Service : : Ptr & parent , GetParentServices ( ) ) {
2013-03-04 15:52:42 +01:00
ObjectLock olock ( parent ) ;
2013-02-09 18:39:43 +01:00
parent - > SetNextCheck ( Utility : : GetTime ( ) ) ;
}
/* reschedule host dependencies */
2013-03-02 09:07:47 +01:00
BOOST_FOREACH ( const Host : : Ptr & parent , GetParentHosts ( ) ) {
Service : : Ptr service = parent - > GetHostCheckService ( ) ;
2013-02-09 18:39:43 +01:00
2013-03-04 15:52:42 +01:00
if ( service & & service - > GetName ( ) ! = GetName ( ) ) {
2013-02-27 12:44:51 +01:00
ObjectLock olock ( service ) ;
2013-02-09 18:39:43 +01:00
service - > SetNextCheck ( Utility : : GetTime ( ) ) ;
2013-02-27 12:44:51 +01:00
}
2013-02-09 18:39:43 +01:00
}
2013-06-13 11:33:00 +02:00
call_eventhandler = true ;
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 ) ;
2013-03-21 11:37:34 +01:00
if ( old_state ! = GetState ( ) & & old_stateType = = StateTypeHard & & GetStateType ( ) = = StateTypeHard )
hardChange = true ;
2013-06-13 12:24:20 +02:00
if ( IsVolatile ( ) )
hardChange = true ;
2013-07-05 09:35:49 +02:00
if ( hardChange ) {
SetLastHardState ( GetState ( ) ) ;
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
2013-02-09 18:39:43 +01:00
if ( GetState ( ) ! = StateOK )
TriggerDowntimes ( ) ;
2013-03-02 09:07:47 +01:00
Service : : UpdateStatistics ( cr ) ;
2013-02-09 18:39:43 +01:00
2013-03-18 12:55:41 +01:00
bool in_downtime = IsInDowntime ( ) ;
bool send_notification = hardChange & & reachable & & ! in_downtime & & ! IsAcknowledged ( ) ;
2013-03-20 15:25:53 +01:00
if ( old_state = = StateOK & & old_stateType = = StateTypeSoft )
send_notification = false ; /* Don't send notifications for SOFT-OK -> HARD-OK. */
2013-03-18 12:55:41 +01:00
bool send_downtime_notification = m_LastInDowntime ! = in_downtime ;
m_LastInDowntime = in_downtime ;
Touch ( " last_in_downtime " ) ;
2013-03-06 11:03:50 +01:00
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 ) ;
2013-03-19 13:04:30 +01:00
Dictionary : : Ptr vars_after = boost : : make_shared < Dictionary > ( ) ;
vars_after - > Set ( " state " , GetState ( ) ) ;
vars_after - > Set ( " state_type " , GetStateType ( ) ) ;
vars_after - > Set ( " attempt " , GetCurrentCheckAttempt ( ) ) ;
vars_after - > Set ( " reachable " , reachable ) ;
vars_after - > Set ( " host_reachable " , host_reachable ) ;
if ( old_cr )
cr - > Set ( " vars_before " , old_cr - > Get ( " vars_after " ) ) ;
cr - > Set ( " vars_after " , vars_after ) ;
2013-03-07 15:00:26 +01:00
cr - > Seal ( ) ;
olock . Lock ( ) ;
SetLastCheckResult ( cr ) ;
2013-06-21 10:20:29 +02:00
bool was_flapping , is_flapping ;
was_flapping = IsFlapping ( ) ;
UpdateFlappingStatus ( stateChange ) ;
is_flapping = IsFlapping ( ) ;
2013-03-07 15:00:26 +01:00
olock . Unlock ( ) ;
2013-07-01 17:56:05 +02:00
Log ( LogDebug , " icinga " , " Flapping: Service " + GetName ( ) +
" was: " + Convert : : ToString ( was_flapping ) +
" is: " + Convert : : ToString ( is_flapping ) +
" threshold: " + Convert : : ToString ( GetFlappingThreshold ( ) ) +
" % current: " + Convert : : ToString ( GetFlappingCurrent ( ) ) + " %. " ) ;
2013-07-01 17:25:30 +02:00
2013-03-02 09:07:47 +01:00
/* Flush the object so other instances see the service's
* new state when they receive the CheckResult message */
Flush ( ) ;
RequestMessage rm ;
rm . SetMethod ( " checker::CheckResult " ) ;
/* TODO: add _old_ state to message */
CheckResultMessage params ;
params . SetService ( GetName ( ) ) ;
params . SetCheckResult ( cr ) ;
rm . SetParams ( params ) ;
EndpointManager : : GetInstance ( ) - > SendMulticastMessage ( rm ) ;
2013-06-13 11:33:00 +02:00
if ( call_eventhandler )
ExecuteEventHandler ( ) ;
2013-03-18 12:55:41 +01:00
if ( send_downtime_notification )
RequestNotifications ( in_downtime ? NotificationDowntimeStart : NotificationDowntimeEnd , cr ) ;
2013-07-01 14:29:07 +02:00
if ( ! was_flapping & & is_flapping ) {
2013-06-21 10:20:29 +02:00
RequestNotifications ( NotificationFlappingStart , cr ) ;
2013-07-01 14:29:07 +02:00
RequestMessage rm ;
rm . SetMethod ( " icinga::Flapping " ) ;
FlappingMessage params ;
params . SetService ( GetName ( ) ) ;
params . SetState ( FlappingStarted ) ;
rm . SetParams ( params ) ;
EndpointManager : : GetInstance ( ) - > SendMulticastMessage ( rm ) ;
2013-07-01 17:25:30 +02:00
Log ( LogDebug , " icinga " , " Flapping: Service " + GetName ( ) + " started flapping ( " + Convert : : ToString ( GetFlappingThreshold ( ) ) + " % < " + Convert : : ToString ( GetFlappingCurrent ( ) ) + " %). " ) ;
2013-07-01 14:29:07 +02:00
}
else if ( was_flapping & & ! is_flapping ) {
2013-06-21 10:20:29 +02:00
RequestNotifications ( NotificationFlappingEnd , cr ) ;
2013-07-01 14:29:07 +02:00
RequestMessage rm ;
rm . SetMethod ( " icinga::Flapping " ) ;
FlappingMessage params ;
params . SetService ( GetName ( ) ) ;
params . SetState ( FlappingStopped ) ;
rm . SetParams ( params ) ;
EndpointManager : : GetInstance ( ) - > SendMulticastMessage ( rm ) ;
2013-07-01 17:25:30 +02:00
Log ( LogDebug , " icinga " , " Flapping: Service " + GetName ( ) + " stopped flapping ( " + Convert : : ToString ( GetFlappingThreshold ( ) ) + " % >= " + Convert : : ToString ( GetFlappingCurrent ( ) ) + " %). " ) ;
2013-07-01 14:29:07 +02:00
}
2013-06-21 10:20:29 +02:00
else if ( send_notification )
2013-03-07 12:04:20 +01:00
RequestNotifications ( recovery ? NotificationRecovery : NotificationProblem , cr ) ;
2013-02-09 18:39:43 +01:00
}
ServiceState Service : : StateFromString ( const String & state )
{
2013-02-24 01:10:34 +01:00
if ( state = = " OK " )
2013-02-09 18:39:43 +01:00
return StateOK ;
2013-02-24 01:10:34 +01:00
else if ( state = = " WARNING " )
2013-02-09 18:39:43 +01:00
return StateWarning ;
2013-02-24 01:10:34 +01:00
else if ( state = = " CRITICAL " )
2013-02-09 18:39:43 +01:00
return StateCritical ;
2013-02-24 01:10:34 +01:00
else if ( state = = " UNCHECKABLE " )
2013-02-09 18:39:43 +01:00
return StateUncheckable ;
else
return StateUnknown ;
}
String Service : : StateToString ( ServiceState state )
{
switch ( state ) {
case StateOK :
2013-02-24 01:10:34 +01:00
return " OK " ;
2013-02-09 18:39:43 +01:00
case StateWarning :
2013-02-24 01:10:34 +01:00
return " WARNING " ;
2013-02-09 18:39:43 +01:00
case StateCritical :
2013-02-24 01:10:34 +01:00
return " CRITICAL " ;
2013-02-09 18:39:43 +01:00
case StateUncheckable :
2013-02-24 01:10:34 +01:00
return " UNCHECKABLE " ;
2013-02-09 18:39:43 +01:00
case StateUnknown :
default :
2013-02-24 01:10:34 +01:00
return " UNKNOWN " ;
2013-02-09 18:39:43 +01:00
}
}
2013-03-07 12:04:20 +01:00
StateType Service : : StateTypeFromString ( const String & type )
2013-02-09 18:39:43 +01:00
{
2013-02-24 01:10:34 +01:00
if ( type = = " SOFT " )
2013-02-09 18:39:43 +01:00
return StateTypeSoft ;
else
return StateTypeHard ;
}
2013-03-07 12:04:20 +01:00
String Service : : StateTypeToString ( StateType type )
2013-02-09 18:39:43 +01:00
{
if ( type = = StateTypeSoft )
2013-02-24 01:10:34 +01:00
return " SOFT " ;
2013-02-09 18:39:43 +01:00
else
2013-02-24 01:10:34 +01:00
return " HARD " ;
2013-02-09 18:39:43 +01:00
}
bool Service : : IsAllowedChecker ( const String & checker ) const
{
2013-03-14 12:17:46 +01:00
Array : : Ptr checkers = GetCheckers ( ) ;
2013-02-09 18:39:43 +01:00
if ( ! checkers )
return true ;
2013-03-02 09:07:47 +01:00
ObjectLock olock ( checkers ) ;
2013-03-14 12:17:46 +01:00
BOOST_FOREACH ( const Value & pattern , checkers ) {
2013-02-09 18:39:43 +01:00
if ( Utility : : Match ( pattern , checker ) )
return true ;
}
return false ;
}
2013-03-25 18:36:15 +01:00
void Service : : ExecuteCheck ( void )
2013-02-09 18:39:43 +01:00
{
2013-03-07 16:00:10 +01:00
ASSERT ( ! OwnsLock ( ) ) ;
2013-02-24 01:10:34 +01:00
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
SetLastState ( GetState ( ) ) ;
SetLastStateType ( GetLastStateType ( ) ) ;
2013-03-19 14:13:58 +01:00
SetLastReachable ( reachable ) ;
2013-02-09 18:39:43 +01:00
}
/* keep track of scheduling info in case the check type doesn't provide its own information */
2013-02-24 01:10:34 +01:00
Dictionary : : Ptr checkInfo = boost : : make_shared < Dictionary > ( ) ;
2013-03-04 15:52:42 +01:00
checkInfo - > Set ( " schedule_start " , GetNextCheck ( ) ) ;
2013-03-02 09:07:47 +01:00
checkInfo - > Set ( " execution_start " , Utility : : GetTime ( ) ) ;
2013-02-24 01:10:34 +01:00
2013-03-04 15:52:42 +01:00
Service : : Ptr self = GetSelf ( ) ;
2013-02-09 18:39:43 +01:00
Dictionary : : Ptr result ;
try {
2013-06-24 09:30:49 +02:00
CheckCommand : : Ptr command = GetCheckCommand ( ) ;
2013-07-06 20:46:09 +02:00
if ( ! command ) {
Log ( LogDebug , " icinga " , " No check_command found for service ' " + GetName ( ) + " '. Skipping execution. " ) ;
2013-06-24 09:30:49 +02:00
return ;
2013-07-06 20:46:09 +02:00
}
2013-06-24 09:30:49 +02:00
result = command - > Execute ( GetSelf ( ) ) ;
2013-03-16 21:18:53 +01:00
} catch ( const std : : exception & ex ) {
std : : ostringstream msgbuf ;
2013-02-09 18:39:43 +01:00
msgbuf < < " Exception occured during check for service ' "
2013-03-16 21:18:53 +01:00
< < GetName ( ) < < " ': " < < boost : : diagnostic_information ( ex ) ;
2013-02-09 18:39:43 +01:00
String message = msgbuf . str ( ) ;
2013-03-16 21:18:53 +01:00
Log ( LogWarning , " icinga " , message ) ;
2013-02-09 18:39:43 +01:00
result = boost : : make_shared < Dictionary > ( ) ;
result - > Set ( " state " , StateUnknown ) ;
result - > Set ( " output " , message ) ;
}
2013-03-25 18:36:15 +01:00
checkInfo - > Set ( " execution_end " , Utility : : GetTime ( ) ) ;
checkInfo - > Set ( " schedule_end " , Utility : : GetTime ( ) ) ;
checkInfo - > Seal ( ) ;
2013-02-09 18:39:43 +01:00
if ( result ) {
if ( ! result - > Contains ( " schedule_start " ) )
2013-02-24 01:10:34 +01:00
result - > Set ( " schedule_start " , checkInfo - > Get ( " schedule_start " ) ) ;
2013-02-09 18:39:43 +01:00
if ( ! result - > Contains ( " schedule_end " ) )
2013-02-24 01:10:34 +01:00
result - > Set ( " schedule_end " , checkInfo - > Get ( " schedule_end " ) ) ;
2013-02-09 18:39:43 +01:00
if ( ! result - > Contains ( " execution_start " ) )
2013-02-24 01:10:34 +01:00
result - > Set ( " execution_start " , checkInfo - > Get ( " execution_start " ) ) ;
2013-02-09 18:39:43 +01:00
if ( ! result - > Contains ( " execution_end " ) )
2013-02-24 01:10:34 +01:00
result - > Set ( " execution_end " , checkInfo - > Get ( " execution_end " ) ) ;
if ( ! result - > Contains ( " macros " ) )
result - > Set ( " macros " , checkInfo - > Get ( " macros " ) ) ;
2013-02-09 18:39:43 +01:00
if ( ! result - > Contains ( " active " ) )
result - > Set ( " active " , 1 ) ;
2013-03-15 11:18:56 +01:00
if ( ! result - > Contains ( " current_checker " ) )
result - > Set ( " current_checker " , EndpointManager : : GetInstance ( ) - > GetIdentity ( ) ) ;
2013-02-09 18:39:43 +01:00
}
2013-03-02 09:07:47 +01:00
if ( result )
ProcessCheckResult ( result ) ;
2013-03-07 12:04:20 +01:00
/* figure out when the next check is for this service; the call to
* ProcessCheckResult ( ) should ' ve already done this but lets do it again
* just in case there was no check result . */
UpdateNextCheck ( ) ;
2013-02-24 01:10:34 +01:00
{
ObjectLock olock ( this ) ;
2013-03-06 11:03:50 +01:00
m_CheckRunning = false ;
2013-02-24 01:10:34 +01:00
}
2013-02-09 18:39:43 +01:00
}
2013-02-11 23:37:39 +01:00
void Service : : UpdateStatistics ( const Dictionary : : Ptr & cr )
{
time_t ts ;
Value schedule_end = cr - > Get ( " schedule_end " ) ;
if ( ! schedule_end . IsEmpty ( ) )
ts = static_cast < time_t > ( schedule_end ) ;
else
ts = static_cast < time_t > ( Utility : : GetTime ( ) ) ;
Value active = cr - > Get ( " active " ) ;
if ( active . IsEmpty ( ) | | static_cast < long > ( active ) )
CIB : : UpdateActiveChecksStatistics ( ts , 1 ) ;
else
CIB : : UpdatePassiveChecksStatistics ( ts , 1 ) ;
}
2013-02-24 01:10:34 +01:00
double Service : : CalculateExecutionTime ( const Dictionary : : Ptr & cr )
{
double execution_start = 0 , execution_end = 0 ;
if ( cr ) {
if ( ! cr - > Contains ( " execution_start " ) | | ! cr - > Contains ( " execution_end " ) )
return 0 ;
execution_start = cr - > Get ( " execution_start " ) ;
execution_end = cr - > Get ( " execution_end " ) ;
}
return ( execution_end - execution_start ) ;
}
double Service : : CalculateLatency ( const Dictionary : : Ptr & cr )
{
double schedule_start = 0 , schedule_end = 0 ;
if ( cr ) {
if ( ! cr - > Contains ( " schedule_start " ) | | ! cr - > Contains ( " schedule_end " ) )
return 0 ;
schedule_start = cr - > Get ( " schedule_start " ) ;
schedule_end = cr - > Get ( " schedule_end " ) ;
}
return ( schedule_end - schedule_start ) - CalculateExecutionTime ( cr ) ;
}