From 02be9010e7917f22f1db565b1832f56b2b0cc64b Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 7 Mar 2013 12:04:20 +0100 Subject: [PATCH] Implemented LAST*STATE* macros. --- .../notification/notificationcomponent.cpp | 8 +- lib/icinga/externalcommandprocessor.cpp | 4 +- lib/icinga/host.cpp | 124 ++++++++++++++---- lib/icinga/host.h | 31 +++++ lib/icinga/notification.cpp | 31 +---- lib/icinga/notification.h | 2 +- lib/icinga/notificationrequestmessage.cpp | 12 ++ lib/icinga/notificationrequestmessage.h | 3 + lib/icinga/service-check.cpp | 93 ++++++++----- lib/icinga/service-notification.cpp | 7 +- lib/icinga/service.cpp | 32 ++++- lib/icinga/service.h | 36 +++-- 12 files changed, 266 insertions(+), 117 deletions(-) diff --git a/components/notification/notificationcomponent.cpp b/components/notification/notificationcomponent.cpp index a79942155..a777cb600 100644 --- a/components/notification/notificationcomponent.cpp +++ b/components/notification/notificationcomponent.cpp @@ -81,7 +81,7 @@ void NotificationComponent::NotificationTimerHandler(void) } if (send_notification) - service->RequestNotifications(NotificationProblem); + service->RequestNotifications(NotificationProblem, service->GetLastCheckResult()); } } @@ -103,10 +103,14 @@ void NotificationComponent::SendNotificationsRequestHandler(const Endpoint::Ptr& if (!params.Get("type", &type)) return; + Dictionary::Ptr cr; + if (!params.Get("check_result", &cr)) + return; + Service::Ptr service = Service::GetByName(svc); if (!service) return; - service->SendNotifications(static_cast(type)); + service->SendNotifications(static_cast(type), cr); } diff --git a/lib/icinga/externalcommandprocessor.cpp b/lib/icinga/externalcommandprocessor.cpp index 4f18ba4ec..c5b7fd7cf 100644 --- a/lib/icinga/externalcommandprocessor.cpp +++ b/lib/icinga/externalcommandprocessor.cpp @@ -1111,7 +1111,7 @@ void ExternalCommandProcessor::SendCustomHostNotification(double, const vectorGetName()); Service::Ptr service = host->GetHostCheckService(); if (service) - service->RequestNotifications(NotificationCustom); + service->RequestNotifications(NotificationCustom, service->GetLastCheckResult()); } void ExternalCommandProcessor::SendCustomSvcNotification(double, const vector& arguments) @@ -1122,7 +1122,7 @@ void ExternalCommandProcessor::SendCustomSvcNotification(double, const vectorGetName()); - service->RequestNotifications(NotificationCustom); + service->RequestNotifications(NotificationCustom, service->GetLastCheckResult()); } void ExternalCommandProcessor::DelayHostNotification(double, const vector& arguments) diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index c72f47b1b..0e62d4a1d 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -506,15 +506,107 @@ set Host::GetParentServices(void) const return parents; } +HostState Host::GetState(void) const +{ + assert(!OwnsLock()); + + if (!IsReachable()) + return HostUnreachable; + + Service::Ptr hc = GetHostCheckService(); + + if (!hc) + return HostUp; + + switch (hc->GetState()) { + case StateOK: + case StateWarning: + return HostUp; + default: + return HostDown; + } +} + +StateType Host::GetStateType(void) const +{ + Service::Ptr hc = GetHostCheckService(); + + if (!hc) + return StateTypeHard; + + return hc->GetStateType(); +} + +HostState Host::GetLastState(void) const +{ + assert(!OwnsLock()); + + if (!IsReachable()) + return HostUnreachable; + + Service::Ptr hc = GetHostCheckService(); + + if (!hc) + return HostUp; + + switch (hc->GetLastState()) { + case StateOK: + case StateWarning: + return HostUp; + default: + return HostDown; + } +} + +StateType Host::GetLastStateType(void) const +{ + Service::Ptr hc = GetHostCheckService(); + + if (!hc) + return StateTypeHard; + + return hc->GetLastStateType(); +} + +String Host::HostStateToString(HostState state) +{ + switch (state) { + case HostUp: + return "UP"; + case HostDown: + return "DOWN"; + case HostUnreachable: + return "UNREACHABLE"; + default: + return "INVALID"; + } +} + Dictionary::Ptr Host::CalculateDynamicMacros(void) const { assert(!OwnsLock()); Dictionary::Ptr macros = boost::make_shared(); - macros->Set("HOSTNAME", GetName()); - macros->Set("HOSTDISPLAYNAME", GetDisplayName()); - macros->Set("HOSTALIAS", GetName()); + { + ObjectLock olock(this); + + macros->Set("HOSTNAME", GetName()); + macros->Set("HOSTDISPLAYNAME", GetDisplayName()); + macros->Set("HOSTALIAS", GetName()); + + HostState state = GetState(); + + macros->Set("HOSTSTATE", HostStateToString(GetState())); + macros->Set("HOSTSTATEID", GetState()); + + HostState lastState = GetLastState(); + StateType lastStateType = GetLastStateType(); + + macros->Set("LASTHOSTSTATE", HostStateToString(lastState)); + macros->Set("LASTHOSTSTATEID", lastState); + macros->Set("LASTHOSTSTATETYPE", Service::StateTypeToString(lastStateType)); + } Dictionary::Ptr cr; @@ -523,32 +615,12 @@ Dictionary::Ptr Host::CalculateDynamicMacros(void) const if (hc) { ObjectLock olock(hc); - String state; - int stateid; - - switch (hc->GetState()) { - case StateOK: - case StateWarning: - state = "UP"; - stateid = 0; - break; - default: - state = "DOWN"; - stateid = 1; - break; - } - - if (!IsReachable()) { - state = "UNREACHABLE"; - stateid = 2; - } - - macros->Set("HOSTSTATE", state); - macros->Set("HOSTSTATEID", stateid); macros->Set("HOSTSTATETYPE", Service::StateTypeToString(hc->GetStateType())); macros->Set("HOSTATTEMPT", hc->GetCurrentCheckAttempt()); macros->Set("MAXHOSTATTEMPT", hc->GetMaxCheckAttempts()); + macros->Set("LASTHOSTSTATECHANGE", (time_t)hc->GetLastStateChange()); + cr = hc->GetLastCheckResult(); } @@ -558,6 +630,8 @@ Dictionary::Ptr Host::CalculateDynamicMacros(void) const macros->Set("HOSTOUTPUT", cr->Get("output")); macros->Set("HOSTPERFDATA", cr->Get("performance_data_raw")); + + macros->Set("LASTHOSTCHECK", (time_t)cr->Get("schedule_start")); } macros->Seal(); diff --git a/lib/icinga/host.h b/lib/icinga/host.h index b76a8e7c1..f50d1b10c 100644 --- a/lib/icinga/host.h +++ b/lib/icinga/host.h @@ -25,6 +25,29 @@ namespace icinga class Service; +/** + * The state of a host. + * + * @ingroup icinga + */ +enum HostState +{ + HostUp = 0, + HostDown = 1, + HostUnreachable = 2 +}; + +/** + * The state type of a host or service. + * + * @ingroup icinga + */ +enum StateType +{ + StateTypeSoft = 0, + StateTypeHard = 1 +}; + /** * An Icinga host. * @@ -65,6 +88,14 @@ public: static void ValidateServiceDictionary(const ScriptTask::Ptr& task, const std::vector& arguments); + HostState GetState(void) const; + StateType GetStateType(void) const; + + HostState GetLastState(void) const; + StateType GetLastStateType(void) const; + + static String HostStateToString(HostState state); + protected: virtual void OnRegistrationCompleted(void); virtual void OnAttributeChanged(const String& name); diff --git a/lib/icinga/notification.cpp b/lib/icinga/notification.cpp index 5e18cea1a..e9f6c9d99 100644 --- a/lib/icinga/notification.cpp +++ b/lib/icinga/notification.cpp @@ -161,38 +161,11 @@ String Notification::NotificationTypeToString(NotificationType type) /** * @threadsafety Always. */ -void Notification::BeginExecuteNotification(NotificationType type) +void Notification::BeginExecuteNotification(NotificationType type, const Dictionary::Ptr& cr) { assert(!OwnsLock()); - vector macroDicts; - - Dictionary::Ptr notificationMacros = boost::make_shared(); - notificationMacros->Set("NOTIFICATIONTYPE", NotificationTypeToString(type)); - macroDicts.push_back(notificationMacros); - - macroDicts.push_back(GetMacros()); - - Service::Ptr service = GetService(); - - if (service) { - macroDicts.push_back(service->GetMacros()); - macroDicts.push_back(service->CalculateDynamicMacros()); - - Host::Ptr host = service->GetHost(); - - if (host) { - macroDicts.push_back(host->GetMacros()); - macroDicts.push_back(host->CalculateDynamicMacros()); - } - } - - IcingaApplication::Ptr app = IcingaApplication::GetInstance(); - macroDicts.push_back(app->GetMacros()); - - macroDicts.push_back(IcingaApplication::CalculateDynamicMacros()); - - Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts); + Dictionary::Ptr macros = cr->Get("macros"); set allUsers; diff --git a/lib/icinga/notification.h b/lib/icinga/notification.h index a0fec755c..2fd89a847 100644 --- a/lib/icinga/notification.h +++ b/lib/icinga/notification.h @@ -63,7 +63,7 @@ public: set GetUsers(void) const; set GetGroups(void) const; - void BeginExecuteNotification(NotificationType type); + void BeginExecuteNotification(NotificationType type, const Dictionary::Ptr& cr); static String NotificationTypeToString(NotificationType type); diff --git a/lib/icinga/notificationrequestmessage.cpp b/lib/icinga/notificationrequestmessage.cpp index dc530e3a9..a8361efc7 100644 --- a/lib/icinga/notificationrequestmessage.cpp +++ b/lib/icinga/notificationrequestmessage.cpp @@ -44,3 +44,15 @@ void NotificationRequestMessage::SetType(NotificationType type) { Set("type", type); } + +Dictionary::Ptr NotificationRequestMessage::GetCheckResult(void) const +{ + Dictionary::Ptr cr; + Get("check_result", &cr); + return cr; +} + +void NotificationRequestMessage::SetCheckResult(const Dictionary::Ptr& cr) +{ + Set("check_result", cr); +} diff --git a/lib/icinga/notificationrequestmessage.h b/lib/icinga/notificationrequestmessage.h index be4889abf..b2ee07af8 100644 --- a/lib/icinga/notificationrequestmessage.h +++ b/lib/icinga/notificationrequestmessage.h @@ -39,6 +39,9 @@ public: NotificationType GetType(void) const; void SetType(NotificationType type); + + Dictionary::Ptr GetCheckResult(void) const; + void SetCheckResult(const Dictionary::Ptr& cr); }; } diff --git a/lib/icinga/service-check.cpp b/lib/icinga/service-check.cpp index 368d27629..043e01981 100644 --- a/lib/icinga/service-check.cpp +++ b/lib/icinga/service-check.cpp @@ -22,8 +22,8 @@ using namespace icinga; const int Service::DefaultMaxCheckAttempts = 3; -const int Service::DefaultCheckInterval = 5 * 60; -const int Service::CheckIntervalDivisor = 5; +const double Service::DefaultCheckInterval = 5 * 60; +const double Service::CheckIntervalDivisor = 5.0; signals2::signal Service::OnCheckerChanged; signals2::signal Service::OnNextCheckChanged; @@ -191,10 +191,26 @@ ServiceState Service::GetState(void) const return static_cast(ivalue); } +void Service::SetLastState(ServiceState state) +{ + m_LastState = static_cast(state); + + Touch("last_state"); +} + +ServiceState Service::GetLastState(void) const +{ + if (m_LastState.IsEmpty()) + return StateUnknown; + + int ivalue = static_cast(m_LastState); + return static_cast(ivalue); +} + /** * @threadsafety Always. */ -void Service::SetStateType(ServiceStateType type) +void Service::SetStateType(StateType type) { m_StateType = static_cast(type); Touch("state_type"); @@ -203,13 +219,34 @@ void Service::SetStateType(ServiceStateType type) /** * @threadsafety Always. */ -ServiceStateType Service::GetStateType(void) const +StateType Service::GetStateType(void) const { if (m_StateType.IsEmpty()) return StateTypeSoft; int ivalue = static_cast(m_StateType); - return static_cast(ivalue); + return static_cast(ivalue); +} + +/** + * @threadsafety Always. + */ +void Service::SetLastStateType(StateType type) +{ + m_LastStateType = static_cast(type); + Touch("last_state_type"); +} + +/** + * @threadsafety Always. + */ +StateType Service::GetLastStateType(void) const +{ + if (m_LastStateType.IsEmpty()) + return StateTypeSoft; + + int ivalue = static_cast(m_LastStateType); + return static_cast(ivalue); } /** @@ -340,10 +377,13 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr) ObjectLock olock(this); ServiceState old_state = GetState(); - ServiceStateType old_stateType = GetStateType(); + StateType old_stateType = GetStateType(); bool hardChange = false; bool recovery; + SetLastState(old_state); + SetLastStateType(old_stateType); + long attempt = GetCurrentCheckAttempt(); if (cr->Get("state") == StateOK) { @@ -423,6 +463,9 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr) * new state when they receive the CheckResult message */ Flush(); + /* Update macros - these are used by event handlers and notifications. */ + cr->Set("macros", CalculateAllMacros()); + RequestMessage rm; rm.SetMethod("checker::CheckResult"); @@ -436,7 +479,7 @@ void Service::ProcessCheckResult(const Dictionary::Ptr& cr) EndpointManager::GetInstance()->SendMulticastMessage(rm); if (send_notification) - RequestNotifications(recovery ? NotificationRecovery : NotificationProblem); + RequestNotifications(recovery ? NotificationRecovery : NotificationProblem, cr); } /** @@ -479,7 +522,7 @@ String Service::StateToString(ServiceState state) /** * @threadsafety Always. */ -ServiceStateType Service::StateTypeFromString(const String& type) +StateType Service::StateTypeFromString(const String& type) { if (type == "SOFT") return StateTypeSoft; @@ -490,7 +533,7 @@ ServiceStateType Service::StateTypeFromString(const String& type) /** * @threadsafety Always. */ -String Service::StateTypeToString(ServiceStateType type) +String Service::StateTypeToString(StateType type) { if (type == StateTypeSoft) return "SOFT"; @@ -547,27 +590,7 @@ void Service::BeginExecuteCheck(const function& callback) checkInfo->Set("schedule_start", GetNextCheck()); checkInfo->Set("execution_start", Utility::GetTime()); - vector macroDicts; - macroDicts.push_back(GetMacros()); - - Value raw_command = GetCheckCommand(); - - Host::Ptr host = GetHost(); - - macroDicts.push_back(CalculateDynamicMacros()); - - if (host) { - macroDicts.push_back(host->GetMacros()); - macroDicts.push_back(host->CalculateDynamicMacros()); - } - - IcingaApplication::Ptr app = IcingaApplication::GetInstance(); - macroDicts.push_back(app->GetMacros()); - - macroDicts.push_back(IcingaApplication::CalculateDynamicMacros()); - - Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts); - + Dictionary::Ptr macros = CalculateAllMacros(); checkInfo->Set("macros", macros); Service::Ptr self = GetSelf(); @@ -648,17 +671,17 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo, if (result) ProcessCheckResult(result); + /* 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(); + { ObjectLock olock(this); m_CurrentTask.reset(); m_CheckRunning = false; } - /* figure out when the next check is for this service; the call to - * ApplyCheckResult() should've already done this but lets do it again - * just in case there was no check result. */ - UpdateNextCheck(); - callback(); } diff --git a/lib/icinga/service-notification.cpp b/lib/icinga/service-notification.cpp index 23faac1e3..76bd6b384 100644 --- a/lib/icinga/service-notification.cpp +++ b/lib/icinga/service-notification.cpp @@ -29,7 +29,7 @@ Timer::Ptr Service::m_NotificationsCacheTimer; /** * @threadsafety Always. */ -void Service::RequestNotifications(NotificationType type) +void Service::RequestNotifications(NotificationType type, const Dictionary::Ptr& cr) { { ObjectLock olock(this); @@ -44,6 +44,7 @@ void Service::RequestNotifications(NotificationType type) params.SetService(GetName()); params.SetType(type); + params.SetCheckResult(cr); Logger::Write(LogDebug, "icinga", "Sending notification anycast request for service '" + GetName() + "'"); EndpointManager::GetInstance()->SendAnycastMessage(Endpoint::Ptr(), msg); @@ -52,7 +53,7 @@ void Service::RequestNotifications(NotificationType type) /** * @threadsafety Always. */ -void Service::SendNotifications(NotificationType type) +void Service::SendNotifications(NotificationType type, const Dictionary::Ptr& cr) { if (!GetEnableNotifications()) { Logger::Write(LogInformation, "icinga", "Notifications are disabled for service '" + GetName() + "'."); @@ -68,7 +69,7 @@ void Service::SendNotifications(NotificationType type) BOOST_FOREACH(const Notification::Ptr& notification, notifications) { try { - notification->BeginExecuteNotification(type); + notification->BeginExecuteNotification(type, cr); } catch (const exception& ex) { stringstream msgbuf; msgbuf << "Exception occured during notification for service '" diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index cdce9cff9..5b7d4a68b 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -44,6 +44,8 @@ Service::Service(const Dictionary::Ptr& serializedObject) RegisterAttribute("check_attempt", Attribute_Replicated, &m_CheckAttempt); RegisterAttribute("state", Attribute_Replicated, &m_State); RegisterAttribute("state_type", Attribute_Replicated, &m_StateType); + RegisterAttribute("last_state", Attribute_Replicated, &m_LastState); + RegisterAttribute("last_state_type", Attribute_Replicated, &m_LastStateType); RegisterAttribute("last_result", Attribute_Replicated, &m_LastResult); RegisterAttribute("last_state_change", Attribute_Replicated, &m_LastStateChange); RegisterAttribute("last_hard_state_change", Attribute_Replicated, &m_LastHardStateChange); @@ -315,7 +317,7 @@ void Service::AcknowledgeProblem(AcknowledgementType type, double expiry) SetAcknowledgement(type); SetAcknowledgementExpiry(expiry); - RequestNotifications(NotificationAcknowledgement); + RequestNotifications(NotificationAcknowledgement, GetLastCheckResult()); } /** @@ -443,6 +445,10 @@ Dictionary::Ptr Service::CalculateDynamicMacros(void) const macros->Set("SERVICEATTEMPT", GetCurrentCheckAttempt()); macros->Set("MAXSERVICEATTEMPT", GetMaxCheckAttempts()); macros->Set("SERVICECHECKCOMMAND", "check_i2"); + macros->Set("LASTSERVICESTATE", StateToString(GetLastState())); + macros->Set("LASTSERVICESTATEID", GetLastState()); + macros->Set("LASTSERVICESTATETYPE", StateTypeToString(GetLastStateType())); + macros->Set("LASTSERVICESTATECHANGE", (time_t)GetLastStateChange()); cr = GetLastCheckResult(); } @@ -455,9 +461,33 @@ Dictionary::Ptr Service::CalculateDynamicMacros(void) const macros->Set("SERVICEOUTPUT", cr->Get("output")); macros->Set("SERVICEPERFDATA", cr->Get("performance_data_raw")); + + macros->Set("LASTSERVICECHECK", (time_t)cr->Get("schedule_start")); } macros->Seal(); return macros; } + +Dictionary::Ptr Service::CalculateAllMacros(void) const +{ + vector macroDicts; + macroDicts.push_back(GetMacros()); + + Host::Ptr host = GetHost(); + + macroDicts.push_back(CalculateDynamicMacros()); + + if (host) { + macroDicts.push_back(host->GetMacros()); + macroDicts.push_back(host->CalculateDynamicMacros()); + } + + IcingaApplication::Ptr app = IcingaApplication::GetInstance(); + macroDicts.push_back(app->GetMacros()); + + macroDicts.push_back(IcingaApplication::CalculateDynamicMacros()); + + return MacroProcessor::MergeMacroDicts(macroDicts); +} diff --git a/lib/icinga/service.h b/lib/icinga/service.h index b26f03809..9400e0f46 100644 --- a/lib/icinga/service.h +++ b/lib/icinga/service.h @@ -37,17 +37,6 @@ enum ServiceState StateUncheckable, }; -/** - * The state type of a service. - * - * @ingroup icinga - */ -enum ServiceStateType -{ - StateTypeSoft, - StateTypeHard -}; - /** * The acknowledgement type of a service. * @@ -94,8 +83,8 @@ public: static Service::Ptr GetByNamePair(const String& hostName, const String& serviceName); static const int DefaultMaxCheckAttempts; - static const int DefaultCheckInterval; - static const int CheckIntervalDivisor; + static const double DefaultCheckInterval; + static const double CheckIntervalDivisor; String GetDisplayName(void) const; Host::Ptr GetHost(void) const; @@ -107,6 +96,7 @@ public: String GetShortName(void) const; Dictionary::Ptr CalculateDynamicMacros(void) const; + Dictionary::Ptr CalculateAllMacros(void) const; set GetParentHosts(void) const; set GetParentServices(void) const; @@ -141,8 +131,14 @@ public: void SetState(ServiceState state); ServiceState GetState(void) const; - void SetStateType(ServiceStateType type); - ServiceStateType GetStateType(void) const; + void SetStateType(StateType type); + StateType GetStateType(void) const; + + void SetLastState(ServiceState state); + ServiceState GetLastState(void) const; + + void SetLastStateType(StateType type); + StateType GetLastStateType(void) const; void SetLastCheckResult(const Dictionary::Ptr& result); Dictionary::Ptr GetLastCheckResult(void) const; @@ -179,8 +175,8 @@ public: static ServiceState StateFromString(const String& state); static String StateToString(ServiceState state); - static ServiceStateType StateTypeFromString(const String& state); - static String StateTypeToString(ServiceStateType state); + static StateType StateTypeFromString(const String& state); + static String StateTypeToString(StateType state); static signals2::signal OnCheckerChanged; static signals2::signal OnNextCheckChanged; @@ -236,8 +232,8 @@ public: double GetNotificationInterval(void) const; - void RequestNotifications(NotificationType type); - void SendNotifications(NotificationType type); + void RequestNotifications(NotificationType type, const Dictionary::Ptr& cr); + void SendNotifications(NotificationType type, const Dictionary::Ptr& cr); set GetNotifications(void) const; @@ -276,6 +272,8 @@ private: Attribute m_CheckAttempt; Attribute m_State; Attribute m_StateType; + Attribute m_LastState; + Attribute m_LastStateType; Attribute m_LastResult; Attribute m_LastStateChange; Attribute m_LastHardStateChange; -- 2.40.0