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/cib.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-08-20 11:06:04 +02:00
# include "base/utility.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-08-28 11:12:20 +02:00
boost : : signals2 : : signal < void ( const Service : : Ptr & , const Dictionary : : Ptr & , const String & ) > Service : : OnNewCheckResult ;
2013-08-20 11:06:04 +02:00
boost : : signals2 : : signal < void ( const Service : : Ptr & , NotificationType , const Dictionary : : Ptr & , const String & , const String & ) > Service : : OnNotificationsRequested ;
2013-08-28 11:12:20 +02:00
boost : : signals2 : : signal < void ( const Service : : Ptr & , double , const String & ) > Service : : OnNextCheckChanged ;
boost : : signals2 : : signal < void ( const Service : : Ptr & , bool , const String & ) > Service : : OnForceNextCheckChanged ;
2013-08-29 13:09:26 +02:00
boost : : signals2 : : signal < void ( const Service : : Ptr & , bool , const String & ) > Service : : OnForceNextNotificationChanged ;
2013-08-28 11:12:20 +02:00
boost : : signals2 : : signal < void ( const Service : : Ptr & , bool , const String & ) > Service : : OnEnableActiveChecksChanged ;
boost : : signals2 : : signal < void ( const Service : : Ptr & , bool , const String & ) > Service : : OnEnablePassiveChecksChanged ;
2013-08-29 13:06:36 +02:00
boost : : signals2 : : signal < void ( const Service : : Ptr & , bool , const String & ) > Service : : OnEnableNotificationsChanged ;
boost : : signals2 : : signal < void ( const Service : : Ptr & , bool , const String & ) > Service : : OnEnableFlappingChanged ;
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
}
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
}
2013-08-28 11:12:20 +02:00
void Service : : SetNextCheck ( double nextCheck , const String & authority )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
m_NextCheck = nextCheck ;
2013-08-20 11:06:04 +02:00
2013-09-01 06:01:27 +02:00
Utility : : QueueAsyncCallback ( boost : : bind ( boost : : ref ( Service : : OnNextCheckChanged ) , GetSelf ( ) , nextCheck , authority ) ) ;
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 ;
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 ;
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 ) ;
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 ) ;
}
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 ) ;
}
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 ) ;
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 ) ;
}
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 ;
}
double Service : : GetLastStateOK ( void ) const
{
if ( m_LastStateOK . IsEmpty ( ) )
return 0 ;
return m_LastStateOK ;
}
void Service : : SetLastStateWarning ( double ts )
{
m_LastStateWarning = ts ;
}
double Service : : GetLastStateWarning ( void ) const
{
if ( m_LastStateWarning . IsEmpty ( ) )
return 0 ;
return m_LastStateWarning ;
}
void Service : : SetLastStateCritical ( double ts )
{
m_LastStateCritical = ts ;
}
double Service : : GetLastStateCritical ( void ) const
{
if ( m_LastStateCritical . IsEmpty ( ) )
return 0 ;
return m_LastStateCritical ;
}
void Service : : SetLastStateUnknown ( double ts )
{
m_LastStateUnknown = ts ;
}
double Service : : GetLastStateUnknown ( void ) const
{
if ( m_LastStateUnknown . IsEmpty ( ) )
return 0 ;
return m_LastStateUnknown ;
}
void Service : : SetLastStateUnreachable ( double ts )
{
m_LastStateUnreachable = ts ;
}
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 ;
}
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 ;
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 ;
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 ;
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
}
2013-08-28 11:12:20 +02:00
void Service : : SetEnableActiveChecks ( bool enabled , const String & authority )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
m_EnableActiveChecks = enabled ? 1 : 0 ;
2013-08-28 11:12:20 +02:00
2013-09-01 06:01:27 +02:00
Utility : : QueueAsyncCallback ( boost : : bind ( boost : : ref ( OnEnableActiveChecksChanged ) , GetSelf ( ) , enabled , authority ) ) ;
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
}
2013-08-28 11:12:20 +02:00
void Service : : SetEnablePassiveChecks ( bool enabled , const String & authority )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
m_EnablePassiveChecks = enabled ? 1 : 0 ;
2013-08-28 11:12:20 +02:00
2013-09-01 06:01:27 +02:00
Utility : : QueueAsyncCallback ( boost : : bind ( boost : : ref ( OnEnablePassiveChecksChanged ) , GetSelf ( ) , enabled , authority ) ) ;
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
}
2013-08-28 11:12:20 +02:00
void Service : : SetForceNextCheck ( bool forced , const String & authority )
2013-02-09 18:39:43 +01:00
{
2013-02-26 10:13:54 +01:00
m_ForceNextCheck = forced ? 1 : 0 ;
2013-08-28 11:12:20 +02:00
2013-09-01 06:01:27 +02:00
Utility : : QueueAsyncCallback ( boost : : bind ( boost : : ref ( OnForceNextCheckChanged ) , GetSelf ( ) , forced , authority ) ) ;
2013-02-09 18:39:43 +01:00
}
2013-08-28 11:12:20 +02:00
void Service : : ProcessCheckResult ( const Dictionary : : Ptr & cr , const String & authority )
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-09-12 17:39:29 +02:00
if ( old_cr & & cr - > Get ( " execution_start " ) < old_cr - > Get ( " execution_start " ) )
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 . */
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 ) ) {
2013-08-29 13:48:18 +02:00
ClearAcknowledgement ( ) ;
2013-02-09 18:39:43 +01:00
}
/* 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 ;
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
olock . Lock ( ) ;
SetLastCheckResult ( cr ) ;
2013-06-21 10:20:29 +02:00
bool was_flapping , is_flapping ;
was_flapping = IsFlapping ( ) ;
2013-09-06 15:29:00 +02:00
if ( GetStateType ( ) = = StateTypeHard )
UpdateFlappingStatus ( stateChange ) ;
2013-06-21 10:20:29 +02:00
is_flapping = IsFlapping ( ) ;
2013-03-07 15:00:26 +01:00
olock . Unlock ( ) ;
2013-09-21 09:00:40 +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-09-01 06:01:27 +02:00
Utility : : QueueAsyncCallback ( boost : : bind ( boost : : ref ( OnNewCheckResult ) , GetSelf ( ) , cr , authority ) ) ;
2013-08-20 11:06:04 +02:00
OnStateChanged ( GetSelf ( ) ) ;
2013-03-02 09:07:47 +01:00
2013-06-13 11:33:00 +02:00
if ( call_eventhandler )
ExecuteEventHandler ( ) ;
2013-03-18 12:55:41 +01:00
if ( send_downtime_notification )
2013-08-20 11:06:04 +02:00
OnNotificationsRequested ( GetSelf ( ) , in_downtime ? NotificationDowntimeStart : NotificationDowntimeEnd , cr , " " , " " ) ;
2013-03-18 12:55:41 +01:00
2013-07-01 14:29:07 +02:00
if ( ! was_flapping & & is_flapping ) {
2013-08-20 11:06:04 +02:00
OnNotificationsRequested ( GetSelf ( ) , NotificationFlappingStart , cr , " " , " " ) ;
2013-07-01 17:25:30 +02:00
Log ( LogDebug , " icinga " , " Flapping: Service " + GetName ( ) + " started flapping ( " + Convert : : ToString ( GetFlappingThreshold ( ) ) + " % < " + Convert : : ToString ( GetFlappingCurrent ( ) ) + " %). " ) ;
2013-08-20 11:06:04 +02:00
OnFlappingChanged ( GetSelf ( ) , FlappingStarted ) ;
} else if ( was_flapping & & ! is_flapping ) {
OnNotificationsRequested ( GetSelf ( ) , NotificationFlappingEnd , cr , " " , " " ) ;
2013-07-01 17:25:30 +02:00
Log ( LogDebug , " icinga " , " Flapping: Service " + GetName ( ) + " stopped flapping ( " + Convert : : ToString ( GetFlappingThreshold ( ) ) + " % >= " + Convert : : ToString ( GetFlappingCurrent ( ) ) + " %). " ) ;
2013-08-20 11:06:04 +02:00
OnFlappingChanged ( GetSelf ( ) , FlappingStopped ) ;
} else if ( send_notification )
OnNotificationsRequested ( GetSelf ( ) , 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
}
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 ( ) ) ;
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-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 " ) ;
}
2013-09-12 11:36:31 +02:00
double latency = ( schedule_end - schedule_start ) - CalculateExecutionTime ( cr ) ;
if ( latency < 0 )
latency = 0 ;
return latency ;
2013-02-24 01:10:34 +01:00
}