]> granicus.if.org Git - icinga2/blob - lib/icinga/notification.cpp
Fine-grained locks (WIP, Part 9).
[icinga2] / lib / icinga / notification.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/)        *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "i2-icinga.h"
21
22 using namespace icinga;
23
24 REGISTER_TYPE(Notification, NULL);
25
26 Notification::Notification(const Dictionary::Ptr& properties)
27         : DynamicObject(properties)
28 {
29         Service::InvalidateNotificationsCache();
30 }
31
32 Notification::~Notification(void)
33 {
34         Service::InvalidateNotificationsCache();
35 }
36
37 bool Notification::Exists(const String& name)
38 {
39         return (DynamicObject::GetObject("Notification", name));
40 }
41
42 Notification::Ptr Notification::GetByName(const String& name)
43 {
44         DynamicObject::Ptr configObject = DynamicObject::GetObject("Notification", name);
45
46         if (!configObject)
47                 BOOST_THROW_EXCEPTION(invalid_argument("Notification '" + name + "' does not exist."));
48
49         return dynamic_pointer_cast<Notification>(configObject);
50 }
51
52 Service::Ptr Notification::GetService(void) const
53 {
54         Host::Ptr host = Host::GetByName(Get("host_name"));
55         String service = Get("service");
56
57         if (service.IsEmpty())
58                 return host->GetHostCheckService();
59         else
60                 return host->GetServiceByShortName(service);
61 }
62
63 Value Notification::GetNotificationCommand(void) const
64 {
65         return Get("notification_command");
66 }
67
68 Dictionary::Ptr Notification::GetMacros(void) const
69 {
70         return Get("macros");
71 }
72
73 String Notification::NotificationTypeToString(NotificationType type)
74 {
75         switch (type) {
76                 case NotificationDowntimeStart:
77                         return "DOWNTIMESTART";
78                 case NotificationDowntimeEnd:
79                         return "DOWNTIMEEND";
80                 case NotificationDowntimeRemoved:
81                         return "DOWNTIMECANCELLED";
82                 case NotificationCustom:
83                         return "DOWNTIMECUSTOM";
84                 case NotificationProblem:
85                         return "PROBLEM";
86                 case NotificationRecovery:
87                         return "RECOVERY";
88                 default:
89                         return "UNKNOWN_NOTIFICATION";
90         }
91 }
92
93 void Notification::BeginExecuteNotification(const Notification::Ptr& self, NotificationType type)
94 {
95
96         vector<Dictionary::Ptr> macroDicts;
97
98         Dictionary::Ptr notificationMacros = boost::make_shared<Dictionary>();
99         notificationMacros->Set("NOTIFICATIONTYPE", NotificationTypeToString(type));
100         macroDicts.push_back(notificationMacros);
101
102         Service::Ptr service;
103
104         {
105                 ObjectLock olock(self);
106                 macroDicts.push_back(self->GetMacros());
107                 service = self->GetService();
108         }
109
110         Host::Ptr host;
111         String service_name;
112
113         {
114                 ObjectLock olock(service);
115                 macroDicts.push_back(service->GetMacros());
116                 service_name = service->GetName();
117                 host = service->GetHost();
118         }
119
120         macroDicts.push_back(Service::CalculateDynamicMacros(service));
121
122         {
123                 ObjectLock olock(host);
124                 macroDicts.push_back(host->GetMacros());
125                 macroDicts.push_back(Host::CalculateDynamicMacros(host));
126         }
127
128         IcingaApplication::Ptr app = IcingaApplication::GetInstance();
129
130         {
131                 ObjectLock olock(app);
132                 macroDicts.push_back(app->GetMacros());
133         }
134
135         macroDicts.push_back(IcingaApplication::CalculateDynamicMacros(app));
136
137         Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
138
139         vector<Value> arguments;
140         arguments.push_back(self);
141         arguments.push_back(macros);
142         arguments.push_back(type);
143
144         ScriptTask::Ptr task;
145
146         {
147                 ObjectLock olock(self);
148                 task = self->MakeMethodTask("notify", arguments);
149
150                 if (!task) {
151                         Logger::Write(LogWarning, "icinga", "Notification object '" + self->GetName() + "' doesn't have a 'notify' method.");
152
153                         return;
154                 }
155
156                 /* We need to keep the task object alive until the completion handler is called. */
157                 self->m_Tasks.insert(task);
158         }
159
160         task->Start(boost::bind(&Notification::NotificationCompletedHandler, self, _1));
161 }
162
163 void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
164 {
165         m_Tasks.erase(task);
166
167         try {
168                 {
169                         ObjectLock tlock(task);
170                         (void) task->GetResult();
171                 }
172
173                 Logger::Write(LogInformation, "icinga", "Completed sending notification for service '" + GetService()->GetName() + "'");
174         } catch (const exception& ex) {
175                 stringstream msgbuf;
176                 msgbuf << "Exception occured during notification for service '"
177                        << GetService()->GetName() << "': " << diagnostic_information(ex);
178                 String message = msgbuf.str();
179
180                 Logger::Write(LogWarning, "icinga", message);
181         }
182 }
183
184 void Notification::OnAttributeChanged(const String& name, const Value& oldValue)
185 {
186         if (name == "host_name" || name == "service")
187                 Service::InvalidateNotificationsCache();
188 }