From cf92cd83b3ba6a1c9d5e293250e2911fbe70dced Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sat, 9 Feb 2013 18:39:43 +0100 Subject: [PATCH] Implement some dynamic macros. Move check-specific code to service-check.cpp --- lib/base/process.cpp | 3 +- lib/icinga/Makefile.am | 1 + lib/icinga/host.cpp | 20 + lib/icinga/host.h | 2 + lib/icinga/icinga.vcxproj | 1 + lib/icinga/pluginchecktask.cpp | 2 + lib/icinga/pluginnotificationtask.cpp | 2 + lib/icinga/service-check.cpp | 527 +++++++++++++++++++++++++ lib/icinga/service-comment.cpp | 7 + lib/icinga/service-downtime.cpp | 7 + lib/icinga/service.cpp | 534 +------------------------- lib/icinga/service.h | 29 +- 12 files changed, 603 insertions(+), 532 deletions(-) create mode 100644 lib/icinga/service-check.cpp diff --git a/lib/base/process.cpp b/lib/base/process.cpp index 1f76f3832..9564b403c 100644 --- a/lib/base/process.cpp +++ b/lib/base/process.cpp @@ -65,7 +65,7 @@ void Process::WorkerThreadProc(void) #ifndef _MSC_VER fd_set readfds; int nfds = 0; - + FD_ZERO(&readfds); int fd; @@ -221,4 +221,3 @@ int Process::GetFD(void) const { return fileno(m_FP); } - diff --git a/lib/icinga/Makefile.am b/lib/icinga/Makefile.am index 31b3a51da..72358dbac 100644 --- a/lib/icinga/Makefile.am +++ b/lib/icinga/Makefile.am @@ -31,6 +31,7 @@ libicinga_la_SOURCES = \ pluginnotificationtask.cpp \ pluginnotificationtask.h \ service.cpp \ + service-check.cpp \ service-comment.cpp \ service-downtime.cpp \ service-notification.cpp \ diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index a0bf5ea20..cd8569708 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -424,3 +424,23 @@ set Host::GetParentServices(void) const return parents; } + +Dynamic::Ptr Host::CalculateDynamicMacros(void) const +{ + Dictionary::Ptr macros = boost::make_shared(); + + macros->Set("HOSTNAME", GetName()); + macros->Set("HOSTDISPLAYNAME", GetDisplayName()); + macros->Set("HOSTSTATE", "DERP"); + + Service::Ptr hostcheck = GetHostCheckService(); + + if (hostcheck) { + macros->Set("HOSTSTATEID", 99); + macros->Set("HOSTSTATETYPE", Service::StateTypeToString(hostcheck->GetStateType()); + macros->Set("HOSTATTEMPT", hostcheck->GetCurrentAttempt()); + macros->Set("MAXHOSTATTEMPT", hostcheck->GetMaxAttempts()); + } + + return macros; +} diff --git a/lib/icinga/host.h b/lib/icinga/host.h index 224414a61..e4f5b29a4 100644 --- a/lib/icinga/host.h +++ b/lib/icinga/host.h @@ -51,6 +51,8 @@ public: Dictionary::Ptr GetServiceDependencies(void) const; String GetHostCheck(void) const; + Dynamic::Ptr CalculateDynamicMacros(void) const; + shared_ptr GetHostCheckService(void) const; set GetParentHosts(void) const; set > GetParentServices(void) const; diff --git a/lib/icinga/icinga.vcxproj b/lib/icinga/icinga.vcxproj index dbb7a8fbf..0f96cf6ca 100644 --- a/lib/icinga/icinga.vcxproj +++ b/lib/icinga/icinga.vcxproj @@ -39,6 +39,7 @@ + diff --git a/lib/icinga/pluginchecktask.cpp b/lib/icinga/pluginchecktask.cpp index bf9188195..cb4774733 100644 --- a/lib/icinga/pluginchecktask.cpp +++ b/lib/icinga/pluginchecktask.cpp @@ -42,7 +42,9 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector macroDicts; macroDicts.push_back(service->GetMacros()); + macroDicts.push_back(service->CalculateDynamicMacros()); macroDicts.push_back(service->GetHost()->GetMacros()); + macroDicts.push_back(service->GetHost()->CalculateDynamicMacros()); macroDicts.push_back(IcingaApplication::GetInstance()->GetMacros()); String command = MacroProcessor::ResolveMacros(checkCommand, macroDicts); diff --git a/lib/icinga/pluginnotificationtask.cpp b/lib/icinga/pluginnotificationtask.cpp index 8bec5e77c..7901bf871 100644 --- a/lib/icinga/pluginnotificationtask.cpp +++ b/lib/icinga/pluginnotificationtask.cpp @@ -47,7 +47,9 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const vecto vector macroDicts; macroDicts.push_back(notification->GetMacros()); macroDicts.push_back(notification->GetService()->GetMacros()); + macroDicts.push_back(notification->GetService()->CalculateDynamicMacros()); macroDicts.push_back(notification->GetService()->GetHost()->GetMacros()); + macroDicts.push_back(notification->GetService()->GetHost()->CalculateDynamicMacros()); macroDicts.push_back(IcingaApplication::GetInstance()->GetMacros()); String command = MacroProcessor::ResolveMacros(notificationCommand, macroDicts); diff --git a/lib/icinga/service-check.cpp b/lib/icinga/service-check.cpp new file mode 100644 index 000000000..41653fa71 --- /dev/null +++ b/lib/icinga/service-check.cpp @@ -0,0 +1,527 @@ +/****************************************************************************** + * 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. * + ******************************************************************************/ + +#include "i2-icinga.h" + +using namespace icinga; + +const int Service::DefaultMaxCheckAttempts = 3; +const int Service::DefaultCheckInterval = 5 * 60; +const int Service::CheckIntervalDivisor = 5; + +boost::signal Service::OnCheckResultReceived; +boost::signal Service::OnCheckerChanged; +boost::signal Service::OnNextCheckChanged; + +String Service::GetCheckCommand(void) const +{ + return Get("check_command"); +} + +long Service::GetMaxCheckAttempts(void) const +{ + Value value = Get("max_check_attempts"); + + if (value.IsEmpty()) + return DefaultMaxCheckAttempts; + + return value; +} + +double Service::GetCheckInterval(void) const +{ + Value value = Get("check_interval"); + + if (value.IsEmpty()) + return DefaultCheckInterval; + + return value; +} + +double Service::GetRetryInterval(void) const +{ + Value value = Get("retry_interval"); + + if (value.IsEmpty()) + return GetCheckInterval() / CheckIntervalDivisor; + + return value; +} + +Dictionary::Ptr Service::GetCheckers(void) const +{ + return Get("checkers"); +} + +void Service::SetSchedulingOffset(long offset) +{ + Set("scheduling_offset", offset); +} + +long Service::GetSchedulingOffset(void) +{ + Value value = Get("scheduling_offset"); + + if (value.IsEmpty()) { + value = rand(); + SetSchedulingOffset(value); + } + + return value; +} + +void Service::SetFirstCheck(bool first) +{ + Set("first_check", first ? 1 : 0); +} + +bool Service::GetFirstCheck(void) const +{ + Value value = Get("first_check"); + + if (value.IsEmpty()) + return true; + + return static_cast(value); +} + + +void Service::SetNextCheck(double nextCheck) +{ + Set("next_check", nextCheck); +} + +double Service::GetNextCheck(void) +{ + Value value = Get("next_check"); + + if (value.IsEmpty()) { + UpdateNextCheck(); + + value = Get("next_check"); + + if (value.IsEmpty()) + BOOST_THROW_EXCEPTION(runtime_error("Failed to schedule next check.")); + } + + return value; +} + +void Service::UpdateNextCheck(void) +{ + double interval; + + if (GetStateType() == StateTypeSoft) + interval = GetRetryInterval(); + else + interval = GetCheckInterval(); + + double now = Utility::GetTime(); + double adj = 0; + + if (interval > 1) + adj = fmod(now + GetSchedulingOffset(), interval); + + SetNextCheck(now - adj + interval); +} + +void Service::SetChecker(const String& checker) +{ + Set("checker", checker); +} + +String Service::GetChecker(void) const +{ + return Get("checker"); +} + +void Service::SetCurrentCheckAttempt(long attempt) +{ + Set("check_attempt", attempt); +} + +long Service::GetCurrentCheckAttempt(void) const +{ + Value value = Get("check_attempt"); + + if (value.IsEmpty()) + return 1; + + return value; +} + +void Service::SetState(ServiceState state) +{ + Set("state", static_cast(state)); +} + +ServiceState Service::GetState(void) const +{ + Value value = Get("state"); + + if (value.IsEmpty()) + return StateUnknown; + + int ivalue = static_cast(value); + return static_cast(ivalue); +} + +void Service::SetStateType(ServiceStateType type) +{ + Set("state_type", static_cast(type)); +} + +ServiceStateType Service::GetStateType(void) const +{ + Value value = Get("state_type"); + + if (value.IsEmpty()) + return StateTypeSoft; + + int ivalue = static_cast(value); + return static_cast(ivalue); +} + +void Service::SetLastCheckResult(const Dictionary::Ptr& result) +{ + Set("last_result", result); +} + +Dictionary::Ptr Service::GetLastCheckResult(void) const +{ + return Get("last_result"); +} + +void Service::SetLastStateChange(double ts) +{ + Set("last_state_change", static_cast(ts)); +} + +double Service::GetLastStateChange(void) const +{ + Value value = Get("last_state_change"); + + if (value.IsEmpty()) + return IcingaApplication::GetInstance()->GetStartTime(); + + return value; +} + +void Service::SetLastHardStateChange(double ts) +{ + Set("last_hard_state_change", ts); +} + +double Service::GetLastHardStateChange(void) const +{ + Value value = Get("last_hard_state_change"); + + if (value.IsEmpty()) + value = IcingaApplication::GetInstance()->GetStartTime(); + + return value; +} + +bool Service::GetEnableActiveChecks(void) const +{ + Value value = Get("enable_active_checks"); + + if (value.IsEmpty()) + return true; + + return static_cast(value); +} + +void Service::SetEnableActiveChecks(bool enabled) +{ + Set("enable_active_checks", enabled ? 1 : 0); +} + +bool Service::GetEnablePassiveChecks(void) const +{ + Value value = Get("enable_passive_checks"); + + if (value.IsEmpty()) + return true; + + return static_cast(value); +} + +void Service::SetEnablePassiveChecks(bool enabled) +{ + Set("enable_passive_checks", enabled ? 1 : 0); +} + +bool Service::GetForceNextCheck(void) const +{ + Value value = Get("force_next_check"); + + if (value.IsEmpty()) + return false; + + return static_cast(value); +} + +void Service::SetForceNextCheck(bool forced) +{ + Set("force_next_check", forced ? 1 : 0); +} + +void Service::ApplyCheckResult(const Dictionary::Ptr& cr) +{ + ServiceState old_state = GetState(); + ServiceStateType old_stateType = GetStateType(); + + long attempt = GetCurrentCheckAttempt(); + + if (cr->Get("state") == StateOK) { + if (GetState() == StateOK) + SetStateType(StateTypeHard); + + attempt = 1; + } else { + if (attempt >= GetMaxCheckAttempts()) { + SetStateType(StateTypeHard); + attempt = 1; + } else if (GetStateType() == StateTypeSoft || GetState() == StateOK) { + SetStateType(StateTypeSoft); + attempt++; + } + } + + SetCurrentCheckAttempt(attempt); + + int state = cr->Get("state"); + SetState(static_cast(state)); + + SetLastCheckResult(cr); + + double now = Utility::GetTime(); + + if (old_state != GetState()) { + SetLastStateChange(now); + + /* remove acknowledgements */ + if (GetAcknowledgement() == AcknowledgementNormal || + (GetAcknowledgement() == AcknowledgementSticky && GetStateType() == StateTypeHard && GetState() == StateOK)) { + SetAcknowledgement(AcknowledgementNone); + SetAcknowledgementExpiry(0); + } + + /* reschedule service dependencies */ + BOOST_FOREACH(const Service::Ptr& parent, GetParentServices()) { + parent->SetNextCheck(Utility::GetTime()); + } + + /* reschedule host dependencies */ + BOOST_FOREACH(const Host::Ptr& parent, GetParentHosts()) { + Service::Ptr service = parent->GetHostCheckService(); + + if (service) + service->SetNextCheck(Utility::GetTime()); + } + } + + if (GetState() != StateOK) + TriggerDowntimes(); + + if (GetStateType() == StateTypeHard && (old_state != GetState() || old_stateType == StateTypeSoft)) { + SetLastHardStateChange(now); + + /* Make sure the notification component sees the updated + * state/state_type attributes. */ + DynamicObject::FlushTx(); + + RequestNotifications(NotificationStateChange); + } +} + +ServiceState Service::StateFromString(const String& state) +{ + if (state == "ok") + return StateOK; + else if (state == "warning") + return StateWarning; + else if (state == "critical") + return StateCritical; + else if (state == "uncheckable") + return StateUncheckable; + else + return StateUnknown; +} + +String Service::StateToString(ServiceState state) +{ + switch (state) { + case StateOK: + return "ok"; + case StateWarning: + return "warning"; + case StateCritical: + return "critical"; + case StateUncheckable: + return "uncheckable"; + case StateUnknown: + default: + return "unknown"; + } +} + +ServiceStateType Service::StateTypeFromString(const String& type) +{ + if (type == "soft") + return StateTypeSoft; + else + return StateTypeHard; +} + +String Service::StateTypeToString(ServiceStateType type) +{ + if (type == StateTypeSoft) + return "soft"; + else + return "hard"; +} + +bool Service::IsAllowedChecker(const String& checker) const +{ + Dictionary::Ptr checkers = GetCheckers(); + + if (!checkers) + return true; + + Value pattern; + BOOST_FOREACH(tie(tuples::ignore, pattern), checkers) { + if (Utility::Match(pattern, checker)) + return true; + } + + return false; +} + +void Service::BeginExecuteCheck(const function& callback) +{ + /* don't run another check if there is one pending */ + if (!Get("current_task").IsEmpty()) { + /* we need to call the callback anyway */ + callback(); + + return; + } + + /* keep track of scheduling info in case the check type doesn't provide its own information */ + Dictionary::Ptr scheduleInfo = boost::make_shared(); + scheduleInfo->Set("schedule_start", GetNextCheck()); + scheduleInfo->Set("execution_start", Utility::GetTime()); + + try { + vector arguments; + arguments.push_back(static_cast(GetSelf())); + ScriptTask::Ptr task; + task = InvokeMethod("check", arguments, boost::bind(&Service::CheckCompletedHandler, this, scheduleInfo, _1, callback)); + + if (!task->IsFinished()) + Set("current_task", task); + } catch (...) { + /* something went wrong while setting up the method call - + * reschedule the service and call the callback anyway. */ + + UpdateNextCheck(); + + callback(); + + throw; + } +} + +void Service::CheckCompletedHandler(const Dictionary::Ptr& scheduleInfo, + const ScriptTask::Ptr& task, const function& callback) +{ + Set("current_task", Empty); + + scheduleInfo->Set("execution_end", Utility::GetTime()); + scheduleInfo->Set("schedule_end", Utility::GetTime()); + + Dictionary::Ptr result; + + try { + Value vresult = task->GetResult(); + + if (vresult.IsObjectType()) + result = vresult; + } catch (const exception& ex) { + stringstream msgbuf; + msgbuf << "Exception occured during check for service '" + << GetName() << "': " << diagnostic_information(ex); + String message = msgbuf.str(); + + Logger::Write(LogWarning, "icinga", message); + + result = boost::make_shared(); + result->Set("state", StateUnknown); + result->Set("output", message); + } + + if (result) { + if (!result->Contains("schedule_start")) + result->Set("schedule_start", scheduleInfo->Get("schedule_start")); + + if (!result->Contains("schedule_end")) + result->Set("schedule_end", scheduleInfo->Get("schedule_end")); + + if (!result->Contains("execution_start")) + result->Set("execution_start", scheduleInfo->Get("execution_start")); + + if (!result->Contains("execution_end")) + result->Set("execution_end", scheduleInfo->Get("execution_end")); + + if (!result->Contains("active")) + result->Set("active", 1); + + ProcessCheckResult(result); + } + + /* 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(); +} + +void Service::ProcessCheckResult(const Dictionary::Ptr& cr) +{ + ApplyCheckResult(cr); + + /* flush the current transaction so other instances see the service's + * new state when they receive the CheckResult message */ + DynamicObject::FlushTx(); + + 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); +} diff --git a/lib/icinga/service-comment.cpp b/lib/icinga/service-comment.cpp index 321e10fa4..1b1619fb0 100644 --- a/lib/icinga/service-comment.cpp +++ b/lib/icinga/service-comment.cpp @@ -32,6 +32,13 @@ int Service::GetNextCommentID(void) return m_NextCommentID; } +Dictionary::Ptr Service::GetComments(void) const +{ + Service::ValidateCommentCache(); + + return Get("comments"); +} + String Service::AddComment(CommentType entryType, const String& author, const String& text, double expireTime) { diff --git a/lib/icinga/service-downtime.cpp b/lib/icinga/service-downtime.cpp index 43fcbf83a..c9a18c9a7 100644 --- a/lib/icinga/service-downtime.cpp +++ b/lib/icinga/service-downtime.cpp @@ -32,6 +32,13 @@ int Service::GetNextDowntimeID(void) return m_NextDowntimeID; } +Dictionary::Ptr Service::GetDowntimes(void) const +{ + Service::ValidateDowntimeCache(); + + return Get("downtimes"); +} + String Service::AddDowntime(const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration) diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index a614d886b..2fe15cfb3 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -45,14 +45,6 @@ static AttributeDescription serviceAttributes[] = { REGISTER_TYPE(Service, serviceAttributes); -const int Service::DefaultMaxCheckAttempts = 3; -const int Service::DefaultCheckInterval = 5 * 60; -const int Service::CheckIntervalDivisor = 5; - -boost::signal Service::OnCheckResultReceived; -boost::signal Service::OnCheckerChanged; -boost::signal Service::OnNextCheckChanged; - Service::Service(const Dictionary::Ptr& serializedObject) : DynamicObject(serializedObject) { @@ -120,55 +112,6 @@ Dictionary::Ptr Service::GetMacros(void) const return Get("macros"); } -Dictionary::Ptr Service::GetDowntimes(void) const -{ - Service::ValidateDowntimeCache(); - - return Get("downtimes"); -} - -Dictionary::Ptr Service::GetComments(void) const -{ - Service::ValidateCommentCache(); - - return Get("comments"); -} - -String Service::GetCheckCommand(void) const -{ - return Get("check_command"); -} - -long Service::GetMaxCheckAttempts(void) const -{ - Value value = Get("max_check_attempts"); - - if (value.IsEmpty()) - return DefaultMaxCheckAttempts; - - return value; -} - -double Service::GetCheckInterval(void) const -{ - Value value = Get("check_interval"); - - if (value.IsEmpty()) - return DefaultCheckInterval; - - return value; -} - -double Service::GetRetryInterval(void) const -{ - Value value = Get("retry_interval"); - - if (value.IsEmpty()) - return GetCheckInterval() / CheckIntervalDivisor; - - return value; -} - Dictionary::Ptr Service::GetHostDependencies(void) const { return Get("hostdependencies"); @@ -184,11 +127,6 @@ Dictionary::Ptr Service::GetGroups(void) const return Get("servicegroups"); } -Dictionary::Ptr Service::GetCheckers(void) const -{ - return Get("checkers"); -} - String Service::GetShortName(void) const { Value value = Get("short_name"); @@ -229,220 +167,6 @@ bool Service::IsReachable(void) const return true; } -void Service::SetSchedulingOffset(long offset) -{ - Set("scheduling_offset", offset); -} - -long Service::GetSchedulingOffset(void) -{ - Value value = Get("scheduling_offset"); - - if (value.IsEmpty()) { - value = rand(); - SetSchedulingOffset(value); - } - - return value; -} - -void Service::SetFirstCheck(bool first) -{ - Set("first_check", first ? 1 : 0); -} - -bool Service::GetFirstCheck(void) const -{ - Value value = Get("first_check"); - - if (value.IsEmpty()) - return true; - - return static_cast(value); -} - - -void Service::SetNextCheck(double nextCheck) -{ - Set("next_check", nextCheck); -} - -double Service::GetNextCheck(void) -{ - Value value = Get("next_check"); - - if (value.IsEmpty()) { - UpdateNextCheck(); - - value = Get("next_check"); - - if (value.IsEmpty()) - BOOST_THROW_EXCEPTION(runtime_error("Failed to schedule next check.")); - } - - return value; -} - -void Service::UpdateNextCheck(void) -{ - double interval; - - if (GetStateType() == StateTypeSoft) - interval = GetRetryInterval(); - else - interval = GetCheckInterval(); - - double now = Utility::GetTime(); - double adj = 0; - - if (interval > 1) - adj = fmod(now + GetSchedulingOffset(), interval); - - SetNextCheck(now - adj + interval); -} - -void Service::SetChecker(const String& checker) -{ - Set("checker", checker); -} - -String Service::GetChecker(void) const -{ - return Get("checker"); -} - -void Service::SetCurrentCheckAttempt(long attempt) -{ - Set("check_attempt", attempt); -} - -long Service::GetCurrentCheckAttempt(void) const -{ - Value value = Get("check_attempt"); - - if (value.IsEmpty()) - return 1; - - return value; -} - -void Service::SetState(ServiceState state) -{ - Set("state", static_cast(state)); -} - -ServiceState Service::GetState(void) const -{ - Value value = Get("state"); - - if (value.IsEmpty()) - return StateUnknown; - - int ivalue = static_cast(value); - return static_cast(ivalue); -} - -void Service::SetStateType(ServiceStateType type) -{ - Set("state_type", static_cast(type)); -} - -ServiceStateType Service::GetStateType(void) const -{ - Value value = Get("state_type"); - - if (value.IsEmpty()) - return StateTypeSoft; - - int ivalue = static_cast(value); - return static_cast(ivalue); -} - -void Service::SetLastCheckResult(const Dictionary::Ptr& result) -{ - Set("last_result", result); -} - -Dictionary::Ptr Service::GetLastCheckResult(void) const -{ - return Get("last_result"); -} - -void Service::SetLastStateChange(double ts) -{ - Set("last_state_change", static_cast(ts)); -} - -double Service::GetLastStateChange(void) const -{ - Value value = Get("last_state_change"); - - if (value.IsEmpty()) - return IcingaApplication::GetInstance()->GetStartTime(); - - return value; -} - -void Service::SetLastHardStateChange(double ts) -{ - Set("last_hard_state_change", ts); -} - -double Service::GetLastHardStateChange(void) const -{ - Value value = Get("last_hard_state_change"); - - if (value.IsEmpty()) - value = IcingaApplication::GetInstance()->GetStartTime(); - - return value; -} - -bool Service::GetEnableActiveChecks(void) const -{ - Value value = Get("enable_active_checks"); - - if (value.IsEmpty()) - return true; - - return static_cast(value); -} - -void Service::SetEnablePassiveChecks(bool enabled) -{ - Set("enable_passive_checks", enabled ? 1 : 0); -} - -bool Service::GetEnablePassiveChecks(void) const -{ - Value value = Get("enable_passive_checks"); - - if (value.IsEmpty()) - return true; - - return static_cast(value); -} - -void Service::SetEnableActiveChecks(bool enabled) -{ - Set("enable_active_checks", enabled ? 1 : 0); -} - -bool Service::GetForceNextCheck(void) const -{ - Value value = Get("force_next_check"); - - if (value.IsEmpty()) - return false; - - return static_cast(value); -} - -void Service::SetForceNextCheck(bool forced) -{ - Set("force_next_check", forced ? 1 : 0); -} - AcknowledgementType Service::GetAcknowledgement(void) { Value value = Get("acknowledgement"); @@ -486,138 +210,6 @@ void Service::SetAcknowledgementExpiry(double timestamp) Set("acknowledgement_expiry", timestamp); } -void Service::ApplyCheckResult(const Dictionary::Ptr& cr) -{ - ServiceState old_state = GetState(); - ServiceStateType old_stateType = GetStateType(); - - long attempt = GetCurrentCheckAttempt(); - - if (cr->Get("state") == StateOK) { - if (GetState() == StateOK) - SetStateType(StateTypeHard); - - attempt = 1; - } else { - if (attempt >= GetMaxCheckAttempts()) { - SetStateType(StateTypeHard); - attempt = 1; - } else if (GetStateType() == StateTypeSoft || GetState() == StateOK) { - SetStateType(StateTypeSoft); - attempt++; - } - } - - SetCurrentCheckAttempt(attempt); - - int state = cr->Get("state"); - SetState(static_cast(state)); - - SetLastCheckResult(cr); - - double now = Utility::GetTime(); - - if (old_state != GetState()) { - SetLastStateChange(now); - - /* remove acknowledgements */ - if (GetAcknowledgement() == AcknowledgementNormal || - (GetAcknowledgement() == AcknowledgementSticky && GetStateType() == StateTypeHard && GetState() == StateOK)) { - SetAcknowledgement(AcknowledgementNone); - SetAcknowledgementExpiry(0); - } - - /* reschedule service dependencies */ - BOOST_FOREACH(const Service::Ptr& parent, GetParentServices()) { - parent->SetNextCheck(Utility::GetTime()); - } - - /* reschedule host dependencies */ - BOOST_FOREACH(const Host::Ptr& parent, GetParentHosts()) { - Service::Ptr service = parent->GetHostCheckService(); - - if (service) - service->SetNextCheck(Utility::GetTime()); - } - } - - if (GetState() != StateOK) - TriggerDowntimes(); - - if (GetStateType() == StateTypeHard && (old_state != GetState() || old_stateType == StateTypeSoft)) { - SetLastHardStateChange(now); - - /* Make sure the notification component sees the updated - * state/state_type attributes. */ - DynamicObject::FlushTx(); - - RequestNotifications(NotificationStateChange); - } -} - -ServiceState Service::StateFromString(const String& state) -{ - if (state == "ok") - return StateOK; - else if (state == "warning") - return StateWarning; - else if (state == "critical") - return StateCritical; - else if (state == "uncheckable") - return StateUncheckable; - else - return StateUnknown; -} - -String Service::StateToString(ServiceState state) -{ - switch (state) { - case StateOK: - return "ok"; - case StateWarning: - return "warning"; - case StateCritical: - return "critical"; - case StateUncheckable: - return "uncheckable"; - case StateUnknown: - default: - return "unknown"; - } -} - -ServiceStateType Service::StateTypeFromString(const String& type) -{ - if (type == "soft") - return StateTypeSoft; - else - return StateTypeHard; -} - -String Service::StateTypeToString(ServiceStateType type) -{ - if (type == StateTypeSoft) - return "soft"; - else - return "hard"; -} - -bool Service::IsAllowedChecker(const String& checker) const -{ - Dictionary::Ptr checkers = GetCheckers(); - - if (!checkers) - return true; - - Value pattern; - BOOST_FOREACH(tie(tuples::ignore, pattern), checkers) { - if (Utility::Match(pattern, checker)) - return true; - } - - return false; -} - void Service::OnAttributeChanged(const String& name, const Value& oldValue) { if (name == "checker") @@ -636,117 +228,6 @@ void Service::OnAttributeChanged(const String& name, const Value& oldValue) UpdateSlaveNotifications(); } -void Service::BeginExecuteCheck(const function& callback) -{ - /* don't run another check if there is one pending */ - if (!Get("current_task").IsEmpty()) { - /* we need to call the callback anyway */ - callback(); - - return; - } - - /* keep track of scheduling info in case the check type doesn't provide its own information */ - Dictionary::Ptr scheduleInfo = boost::make_shared(); - scheduleInfo->Set("schedule_start", GetNextCheck()); - scheduleInfo->Set("execution_start", Utility::GetTime()); - - try { - vector arguments; - arguments.push_back(static_cast(GetSelf())); - ScriptTask::Ptr task; - task = InvokeMethod("check", arguments, boost::bind(&Service::CheckCompletedHandler, this, scheduleInfo, _1, callback)); - - if (!task->IsFinished()) - Set("current_task", task); - } catch (...) { - /* something went wrong while setting up the method call - - * reschedule the service and call the callback anyway. */ - - UpdateNextCheck(); - - callback(); - - throw; - } -} - -void Service::CheckCompletedHandler(const Dictionary::Ptr& scheduleInfo, - const ScriptTask::Ptr& task, const function& callback) -{ - Set("current_task", Empty); - - scheduleInfo->Set("execution_end", Utility::GetTime()); - scheduleInfo->Set("schedule_end", Utility::GetTime()); - - Dictionary::Ptr result; - - try { - Value vresult = task->GetResult(); - - if (vresult.IsObjectType()) - result = vresult; - } catch (const exception& ex) { - stringstream msgbuf; - msgbuf << "Exception occured during check for service '" - << GetName() << "': " << diagnostic_information(ex); - String message = msgbuf.str(); - - Logger::Write(LogWarning, "icinga", message); - - result = boost::make_shared(); - result->Set("state", StateUnknown); - result->Set("output", message); - } - - if (result) { - if (!result->Contains("schedule_start")) - result->Set("schedule_start", scheduleInfo->Get("schedule_start")); - - if (!result->Contains("schedule_end")) - result->Set("schedule_end", scheduleInfo->Get("schedule_end")); - - if (!result->Contains("execution_start")) - result->Set("execution_start", scheduleInfo->Get("execution_start")); - - if (!result->Contains("execution_end")) - result->Set("execution_end", scheduleInfo->Get("execution_end")); - - if (!result->Contains("active")) - result->Set("active", 1); - - ProcessCheckResult(result); - } - - /* 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(); -} - -void Service::ProcessCheckResult(const Dictionary::Ptr& cr) -{ - ApplyCheckResult(cr); - - /* flush the current transaction so other instances see the service's - * new state when they receive the CheckResult message */ - DynamicObject::FlushTx(); - - 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); -} - set Service::GetParentHosts(void) const { set parents; @@ -787,3 +268,18 @@ set Service::GetParentServices(void) const return parents; } + +Dynamic::Ptr Service::CalculateDynamicMacros(void) const +{ + Dictionary::Ptr macros = boost::make_shared(); + + macros->Set("SERVICEDESC", GetShortName()); + macros->Set("SERVICEDISPLAYNAME", GetDisplayName()); + macros->Set("SERVICESTATE", StateToString(GetState())); + macros->Set("SERVICESTATEID", GetState()); + macros->Set("SERVICESTATETYPE", StateTypeToString(GetStateType())); + macros->Set("SERVICEATTEMPT", GetCurrentAttempt()); + macros->Set("MAXSERVICEATTEMPT", GetMaxAttempts()); + + return macros; +} diff --git a/lib/icinga/service.h b/lib/icinga/service.h index dfda3399b..bc9f4506c 100644 --- a/lib/icinga/service.h +++ b/lib/icinga/service.h @@ -101,23 +101,27 @@ public: String GetDisplayName(void) const; Host::Ptr GetHost(void) const; Dictionary::Ptr GetMacros(void) const; - Dictionary::Ptr GetDowntimes(void) const; - Dictionary::Ptr GetComments(void) const; - String GetCheckCommand(void) const; - long GetMaxCheckAttempts(void) const; - double GetCheckInterval(void) const; - double GetRetryInterval(void) const; Dictionary::Ptr GetHostDependencies(void) const; Dictionary::Ptr GetServiceDependencies(void) const; Dictionary::Ptr GetGroups(void) const; - Dictionary::Ptr GetCheckers(void) const; String GetShortName(void) const; + Dynamic::Ptr CalculateDynamicMacros(void) const; + set GetParentHosts(void) const; set GetParentServices(void) const; bool IsReachable(void) const; - bool IsInDowntime(void) const; + + AcknowledgementType GetAcknowledgement(void); + void SetAcknowledgement(AcknowledgementType acknowledgement); + + /* Checks */ + Dictionary::Ptr GetCheckers(void) const; + String GetCheckCommand(void) const; + long GetMaxCheckAttempts(void) const; + double GetCheckInterval(void) const; + double GetRetryInterval(void) const; long GetSchedulingOffset(void); void SetSchedulingOffset(long offset); @@ -161,9 +165,6 @@ public: bool GetForceNextCheck(void) const; void SetForceNextCheck(bool forced); - AcknowledgementType GetAcknowledgement(void); - void SetAcknowledgement(AcknowledgementType acknowledgement); - double GetAcknowledgementExpiry(void) const; void SetAcknowledgementExpiry(double timestamp); @@ -185,6 +186,8 @@ public: /* Downtimes */ static int GetNextDowntimeID(void); + Dictionary::Ptr GetDowntimes(void) const; + String AddDowntime(const String& author, const String& comment, double startTime, double endTime, bool fixed, const String& triggeredBy, double duration); @@ -204,9 +207,13 @@ public: static void InvalidateDowntimeCache(void); static void ValidateDowntimeCache(void); + bool IsInDowntime(void) const; + /* Comments */ static int GetNextCommentID(void); + Dictionary::Ptr GetComments(void) const; + String AddComment(CommentType entryType, const String& author, const String& text, double expireTime); -- 2.49.0