diff --git a/components/compat/compatcomponent.cpp b/components/compat/compatcomponent.cpp index 87fcdeeee..7aa3ee7c6 100644 --- a/components/compat/compatcomponent.cpp +++ b/components/compat/compatcomponent.cpp @@ -316,7 +316,7 @@ void CompatComponent::DumpHostObject(std::ostream& fp, const Host::Ptr& host) << "\t" << "passive_checks_enabled" << "\t" << (hc->GetEnablePassiveChecks() ? 1 : 0) << "\n" << "\t" << "notifications_enabled" << "\t" << (hc->GetEnableNotifications() ? 1 : 0) << "\n" << "\t" << "notification_options" << "\t" << "d,u,r" << "\n" - << "\t" << "notification_interval" << "\t" << hc->GetNotificationInterval() << "\n"; + << "\t" << "notification_interval" << "\t" << 1 << "\n"; } else { fp << "\t" << "check_interval" << "\t" << 60 << "\n" << "\t" << "retry_interval" << "\t" << 60 << "\n" @@ -367,6 +367,12 @@ void CompatComponent::DumpServiceStatusAttrs(std::ostream& fp, const Service::Pt state = 2; /* UNREACHABLE */ } + double last_notification = 0; + BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) { + if (notification->GetLastNotification() > last_notification) + last_notification = notification->GetLastNotification(); + } + fp << "\t" << "check_interval=" << service->GetCheckInterval() / 60.0 << "\n" << "\t" << "retry_interval=" << service->GetRetryInterval() / 60.0 << "\n" << "\t" << "has_been_checked=" << (service->GetLastCheckResult() ? 1 : 0) << "\n" @@ -391,7 +397,7 @@ void CompatComponent::DumpServiceStatusAttrs(std::ostream& fp, const Service::Pt << "\t" << "acknowledgement_type=" << static_cast(service->GetAcknowledgement()) << "\n" << "\t" << "acknowledgement_end_time=" << service->GetAcknowledgementExpiry() << "\n" << "\t" << "scheduled_downtime_depth=" << (service->IsInDowntime() ? 1 : 0) << "\n" - << "\t" << "last_notification=" << service->GetLastNotification() << "\n"; + << "\t" << "last_notification=" << last_notification << "\n"; } void CompatComponent::DumpServiceStatus(std::ostream& fp, const Service::Ptr& service) @@ -424,6 +430,12 @@ void CompatComponent::DumpServiceObject(std::ostream& fp, const Service::Ptr& se if (!host) return; + double notification_interval = -1; + BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) { + if (notification_interval == -1 || notification->GetNotificationInterval() < notification_interval) + notification_interval = notification->GetNotificationInterval(); + } + { ObjectLock olock(service); @@ -439,7 +451,7 @@ void CompatComponent::DumpServiceObject(std::ostream& fp, const Service::Ptr& se << "\t" << "passive_checks_enabled" << "\t" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n" << "\t" << "notifications_enabled" << "\t" << (service->GetEnableNotifications() ? 1 : 0) << "\n" << "\t" << "notification_options" << "\t" << "u,w,c,r" << "\n" - << "\t" << "notification_interval" << "\t" << service->GetNotificationInterval() << "\n" + << "\t" << "notification_interval" << "\t" << notification_interval << "\n" << "\t" << "}" << "\n" << "\n"; } diff --git a/components/notification/notificationcomponent.cpp b/components/notification/notificationcomponent.cpp index ac0c79772..0ea55fe3c 100644 --- a/components/notification/notificationcomponent.cpp +++ b/components/notification/notificationcomponent.cpp @@ -21,6 +21,7 @@ #include "icinga/service.h" #include "base/dynamictype.h" #include "base/objectlock.h" +#include "base/logger_fwd.h" #include #include @@ -57,7 +58,7 @@ void NotificationComponent::Stop(void) } /** - * Periodically sends a notification::HelloWorld message. + * Periodically sends notifications. * * @param - Event arguments for the timer. */ @@ -65,8 +66,16 @@ void NotificationComponent::NotificationTimerHandler(void) { double now = Utility::GetTime(); - BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) { - Service::Ptr service = dynamic_pointer_cast(object); + BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Notification")) { + Notification::Ptr notification = dynamic_pointer_cast(object); + + if (notification->GetNotificationInterval() <= 0) + continue; + + if (notification->GetNextNotification() > now) + continue; + + Service::Ptr service = notification->GetService(); bool reachable = service->IsReachable(); bool send_notification; @@ -80,17 +89,25 @@ void NotificationComponent::NotificationTimerHandler(void) if (service->GetState() == StateOK) continue; - if (service->GetNotificationInterval() <= 0) - continue; - - if (service->GetLastNotification() > now - service->GetNotificationInterval()) - continue; - send_notification = reachable && !service->IsInDowntime() && !service->IsAcknowledged(); } - if (send_notification) - service->RequestNotifications(NotificationProblem, service->GetLastCheckResult()); + if (!send_notification) + continue; + + try { + Log(LogInformation, "notification", "Sending reminder notification for service '" + service->GetName() + "'"); + notification->BeginExecuteNotification(NotificationProblem, service->GetLastCheckResult()); + } catch (const std::exception& ex) { + std::ostringstream msgbuf; + msgbuf << "Exception occured during notification for service '" + << GetName() << "': " << boost::diagnostic_information(ex); + String message = msgbuf.str(); + + Log(LogWarning, "icinga", message); + } + + notification->SetNextNotification(Utility::GetTime() + notification->GetNotificationInterval()); } } diff --git a/lib/icinga/externalcommandprocessor.cpp b/lib/icinga/externalcommandprocessor.cpp index d6234d7de..7a2b4834b 100644 --- a/lib/icinga/externalcommandprocessor.cpp +++ b/lib/icinga/externalcommandprocessor.cpp @@ -1134,10 +1134,10 @@ void ExternalCommandProcessor::DelayHostNotification(double, const std::vectorGetNotifications()) { + ObjectLock olock(notification); - hc->SetLastNotification(Convert::ToDouble(arguments[1])); + notification->SetNextNotification(Convert::ToDouble(arguments[1])); } } @@ -1150,10 +1150,10 @@ void ExternalCommandProcessor::DelaySvcNotification(double, const std::vectorGetName()); - { - ObjectLock olock(service); + BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) { + ObjectLock olock(notification); - service->SetLastNotification(Convert::ToDouble(arguments[2])); + notification->SetNextNotification(Convert::ToDouble(arguments[2])); } } diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf index 5ce5ad3f7..eae1fbffb 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -223,7 +223,9 @@ type Notification { %attribute array "notification_command" { %attribute string "*" }, - %attribute string "notification_command" + %attribute string "notification_command", + + %attribute number "notification_interval" } type User { diff --git a/lib/icinga/notification.cpp b/lib/icinga/notification.cpp index 7cc1b1f0c..1a56b8c3b 100644 --- a/lib/icinga/notification.cpp +++ b/lib/icinga/notification.cpp @@ -35,6 +35,9 @@ Notification::Notification(const Dictionary::Ptr& serializedUpdate) : DynamicObject(serializedUpdate) { RegisterAttribute("notification_command", Attribute_Config, &m_NotificationCommand); + RegisterAttribute("notification_interval", Attribute_Config, &m_NotificationInterval); + RegisterAttribute("last_notification", Attribute_Replicated, &m_LastNotification); + RegisterAttribute("next_notification", Attribute_Replicated, &m_NextNotification); RegisterAttribute("macros", Attribute_Config, &m_Macros); RegisterAttribute("users", Attribute_Config, &m_Users); RegisterAttribute("groups", Attribute_Config, &m_Groups); @@ -139,6 +142,58 @@ std::set Notification::GetGroups(void) const return result; } +/** + * @threadsafety Always. + */ +double Notification::GetNotificationInterval(void) const +{ + if (m_NotificationInterval.IsEmpty()) + return 300; + else + return m_NotificationInterval; +} + +/** + * @threadsafety Always. + */ +double Notification::GetLastNotification(void) const +{ + if (m_LastNotification.IsEmpty()) + return 0; + else + return m_LastNotification; +} + +/** + * Sets the timestamp when the last notification was sent. + */ +void Notification::SetLastNotification(double time) +{ + m_LastNotification = time; + Touch("last_notification"); +} + +/** + * @threadsafety Always. + */ +double Notification::GetNextNotification(void) const +{ + if (m_NextNotification.IsEmpty()) + return 0; + else + return m_NextNotification; +} + +/** + * Sets the timestamp when the next periodical notification should be sent. + * This does not affect notifications that are sent for state changes. + */ +void Notification::SetNextNotification(double time) +{ + m_NextNotification = time; + Touch("next_notification"); +} + /** * @threadsafety Always. */ @@ -171,6 +226,12 @@ void Notification::BeginExecuteNotification(NotificationType type, const Diction { ASSERT(!OwnsLock()); + { + ObjectLock olock(this); + + SetLastNotification(Utility::GetTime()); + } + Dictionary::Ptr macros = cr->Get("macros"); std::set allUsers; diff --git a/lib/icinga/notification.h b/lib/icinga/notification.h index 151092f5d..256c260e2 100644 --- a/lib/icinga/notification.h +++ b/lib/icinga/notification.h @@ -64,10 +64,17 @@ public: shared_ptr GetService(void) const; Value GetNotificationCommand(void) const; + double GetNotificationInterval(void) const; Dictionary::Ptr GetMacros(void) const; std::set GetUsers(void) const; std::set GetGroups(void) const; + double GetLastNotification(void) const; + void SetLastNotification(double time); + + double GetNextNotification(void) const; + void SetNextNotification(double time); + void BeginExecuteNotification(NotificationType type, const Dictionary::Ptr& cr); static String NotificationTypeToString(NotificationType type); @@ -77,6 +84,9 @@ protected: private: Attribute m_NotificationCommand; + Attribute m_NotificationInterval; + Attribute m_LastNotification; + Attribute m_NextNotification; Attribute m_Macros; Attribute m_Users; Attribute m_Groups; diff --git a/lib/icinga/service-notification.cpp b/lib/icinga/service-notification.cpp index c7f0d49a7..8c169def2 100644 --- a/lib/icinga/service-notification.cpp +++ b/lib/icinga/service-notification.cpp @@ -41,11 +41,6 @@ static Timer::Ptr l_NotificationsCacheTimer; */ void Service::RequestNotifications(NotificationType type, const Dictionary::Ptr& cr) { - { - ObjectLock olock(this); - SetLastNotification(Utility::GetTime()); - } - RequestMessage msg; msg.SetMethod("icinga::SendNotifications"); @@ -250,7 +245,7 @@ void Service::UpdateSlaveNotifications(void) } } - /* Clone attributes from the service object. */ + /* Clone attributes from the host/service object. */ std::set keys; keys.insert("users"); keys.insert("groups"); @@ -295,26 +290,6 @@ void Service::UpdateSlaveNotifications(void) } } -/** - * @threadsafety Always. - */ -double Service::GetLastNotification(void) const -{ - if (m_LastNotification.IsEmpty()) - return 0; - else - return m_LastNotification; -} - -/** - * @threadsafety Always. - */ -void Service::SetLastNotification(double time) -{ - m_LastNotification = time; - Touch("last_notification"); -} - /** * @threadsafety Always. */ @@ -334,14 +309,3 @@ void Service::SetEnableNotifications(bool enabled) m_EnableNotifications = enabled; Touch("enable_notifications"); } - -/** - * @threadsafety Always. - */ -double Service::GetNotificationInterval(void) const -{ - if (m_NotificationInterval.IsEmpty()) - return 300; - else - return m_NotificationInterval; -} diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index fe1590a71..c1cf433d5 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -75,8 +75,6 @@ Service::Service(const Dictionary::Ptr& serializedObject) RegisterAttribute("downtimes", Attribute_Replicated, &m_Downtimes); RegisterAttribute("enable_notifications", Attribute_Replicated, &m_EnableNotifications); - RegisterAttribute("last_notification", Attribute_Replicated, &m_LastNotification); - RegisterAttribute("notification_interval", Attribute_Config, &m_NotificationInterval); SetSchedulingOffset(rand()); } diff --git a/lib/icinga/service.h b/lib/icinga/service.h index b80108173..028d58cb5 100644 --- a/lib/icinga/service.h +++ b/lib/icinga/service.h @@ -228,8 +228,6 @@ public: bool GetEnableNotifications(void) const; void SetEnableNotifications(bool enabled); - double GetNotificationInterval(void) const; - void RequestNotifications(NotificationType type, const Dictionary::Ptr& cr); void SendNotifications(NotificationType type, const Dictionary::Ptr& cr); @@ -239,9 +237,6 @@ public: void UpdateSlaveNotifications(void); - double GetLastNotification(void) const; - void SetLastNotification(double time); - protected: virtual void OnRegistrationCompleted(void); virtual void OnAttributeChanged(const String& name); @@ -310,8 +305,6 @@ private: /* Notifications */ Attribute m_EnableNotifications; - Attribute m_LastNotification; - Attribute m_NotificationInterval; static void RefreshNotificationsCache(void); };