/****************************************************************************** * 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; map > Service::m_NotificationsCache; bool Service::m_NotificationsCacheValid; void Service::RequestNotifications(NotificationType type) const { RequestMessage msg; msg.SetMethod("icinga::SendNotifications"); NotificationRequestMessage params; msg.SetParams(params); params.SetService(GetName()); params.SetType(type); Logger::Write(LogDebug, "icinga", "Sending notification anycast request for service '" + GetName() + "'"); EndpointManager::GetInstance()->SendAnycastMessage(Endpoint::Ptr(), msg); } void Service::SendNotifications(NotificationType type) { Logger::Write(LogInformation, "icinga", "Sending notifications for service '" + GetName() + "'"); set notifications = GetNotifications(); if (notifications.size() == 0) Logger::Write(LogInformation, "icinga", "Service '" + GetName() + "' does not have any notifications."); BOOST_FOREACH(const Notification::Ptr& notification, notifications) { try { Notification::BeginExecuteNotification(notification, type); } catch (const exception& ex) { stringstream msgbuf; msgbuf << "Exception occured during notification for service '" << GetName() << "': " << diagnostic_information(ex); String message = msgbuf.str(); Logger::Write(LogWarning, "icinga", message); } } SetLastNotification(Utility::GetTime()); } void Service::InvalidateNotificationsCache(void) { m_NotificationsCacheValid = false; m_NotificationsCache.clear(); } void Service::ValidateNotificationsCache(void) { if (m_NotificationsCacheValid) return; m_NotificationsCache.clear(); BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Notification")) { const Notification::Ptr& notification = static_pointer_cast(object); m_NotificationsCache[notification->GetService()->GetName()].insert(notification); } m_NotificationsCacheValid = true; } set Service::GetNotifications(void) const { set notifications; ValidateNotificationsCache(); BOOST_FOREACH(const Notification::WeakPtr& wservice, m_NotificationsCache[GetName()]) { Notification::Ptr notification = wservice.lock(); if (!notification) continue; notifications.insert(notification); } return notifications; } template static void CopyNotificationAttributes(TDict notificationDesc, const ConfigItemBuilder::Ptr& builder) { /* TODO: we only need to copy macros if this is an inline definition, * i.e. "typeid(notificationDesc)" != Notification, however for now we just * copy them anyway. */ Value macros = notificationDesc->Get("macros"); if (!macros.IsEmpty()) builder->AddExpression("macros", OperatorPlus, macros); Value users = notificationDesc->Get("users"); if (!users.IsEmpty()) builder->AddExpression("users", OperatorPlus, users); /*Value notificationInterval = notificationDesc->Get("notification_interval"); if (!notificationInterval.IsEmpty()) builder->AddExpression("notification_interval", OperatorSet, notificationInterval);*/ } void Service::UpdateSlaveNotifications(void) { ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName()); /* Don't create slave notifications unless we own this object * and it's not a template. */ if (!item || IsAbstract()) return; Dictionary::Ptr oldNotifications = Get("slave_notifications"); Dictionary::Ptr newNotifications; newNotifications = boost::make_shared(); vector notificationDescsList; String host_name; { Host::Ptr host = GetHost(); ObjectLock olock(host); notificationDescsList.push_back(host->Get("notifications")); host_name = host->GetName(); } notificationDescsList.push_back(Get("notifications")); BOOST_FOREACH(const Dictionary::Ptr& notificationDescs, notificationDescsList) { if (!notificationDescs) continue; String nfcname; Value nfcdesc; BOOST_FOREACH(tie(nfcname, nfcdesc), notificationDescs) { if (nfcdesc.IsScalar()) nfcname = nfcdesc; stringstream namebuf; namebuf << GetName() << "-" << nfcname; String name = namebuf.str(); ConfigItemBuilder::Ptr builder = boost::make_shared(item->GetDebugInfo()); builder->SetType("Notification"); builder->SetName(name); builder->AddExpression("host_name", OperatorSet, host_name); builder->AddExpression("service", OperatorSet, GetName()); CopyNotificationAttributes(this, builder); if (nfcdesc.IsScalar()) { builder->AddParent(nfcdesc); } else if (nfcdesc.IsObjectType()) { Dictionary::Ptr notification = nfcdesc; Dictionary::Ptr templates = notification->Get("templates"); if (templates) { String tmpl; BOOST_FOREACH(tie(tuples::ignore, tmpl), templates) { builder->AddParent(tmpl); } } else { builder->AddParent(nfcname); } CopyNotificationAttributes(notification, builder); } else { BOOST_THROW_EXCEPTION(invalid_argument("Notification description must be either a string or a dictionary.")); } ConfigItem::Ptr notificationItem = builder->Compile(); ConfigItem::Commit(notificationItem); newNotifications->Set(name, notificationItem); } } if (oldNotifications) { ConfigItem::Ptr notification; BOOST_FOREACH(tie(tuples::ignore, notification), oldNotifications) { if (!notification) continue; if (!newNotifications->Contains(notification->GetName())) notification->Unregister(); } } Set("slave_notifications", newNotifications); } double Service::GetLastNotification(void) const { Value value = Get("last_notification"); if (value.IsEmpty()) value = 0; return value; } void Service::SetLastNotification(double time) { Set("last_notification", time); } double Service::GetNextNotification(void) const { Value value = Get("next_notification"); if (value.IsEmpty()) value = 0; return value; } void Service::SetNextNotification(double time) { Set("next_notification", time); }