]> granicus.if.org Git - icinga2/blob - lib/icinga/notification.cpp
Move the notification_interval option to the Notification class.
[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 "icinga/notification.h"
21 #include "icinga/macroprocessor.h"
22 #include "icinga/service.h"
23 #include "base/dynamictype.h"
24 #include "base/objectlock.h"
25 #include "base/logger_fwd.h"
26 #include <boost/tuple/tuple.hpp>
27 #include <boost/foreach.hpp>
28 #include <boost/exception/diagnostic_information.hpp>
29
30 using namespace icinga;
31
32 REGISTER_TYPE(Notification);
33
34 Notification::Notification(const Dictionary::Ptr& serializedUpdate)
35         : DynamicObject(serializedUpdate)
36 {
37         RegisterAttribute("notification_command", Attribute_Config, &m_NotificationCommand);
38         RegisterAttribute("notification_interval", Attribute_Config, &m_NotificationInterval);
39         RegisterAttribute("last_notification", Attribute_Replicated, &m_LastNotification);
40         RegisterAttribute("next_notification", Attribute_Replicated, &m_NextNotification);
41         RegisterAttribute("macros", Attribute_Config, &m_Macros);
42         RegisterAttribute("users", Attribute_Config, &m_Users);
43         RegisterAttribute("groups", Attribute_Config, &m_Groups);
44         RegisterAttribute("host_name", Attribute_Config, &m_HostName);
45         RegisterAttribute("service", Attribute_Config, &m_Service);
46 }
47
48 Notification::~Notification(void)
49 {
50         Service::InvalidateNotificationsCache();
51 }
52
53 /**
54  * @threadsafety Always.
55  */
56 Notification::Ptr Notification::GetByName(const String& name)
57 {
58         DynamicObject::Ptr configObject = DynamicObject::GetObject("Notification", name);
59
60         return dynamic_pointer_cast<Notification>(configObject);
61 }
62
63 /**
64  * @threadsafety Always.
65  */
66 Service::Ptr Notification::GetService(void) const
67 {
68         Host::Ptr host = Host::GetByName(m_HostName);
69
70         if (!host)
71                 return Service::Ptr();
72
73         if (m_Service.IsEmpty())
74                 return host->GetHostCheckService();
75         else
76                 return host->GetServiceByShortName(m_Service);
77 }
78
79 /**
80  * @threadsafety Always.
81  */
82 Value Notification::GetNotificationCommand(void) const
83 {
84         return m_NotificationCommand;
85 }
86
87 /**
88  * @threadsafety Always.
89  */
90 Dictionary::Ptr Notification::GetMacros(void) const
91 {
92         return m_Macros;
93 }
94
95 /**
96  * @threadsafety Always.
97  */
98 std::set<User::Ptr> Notification::GetUsers(void) const
99 {
100         std::set<User::Ptr> result;
101
102         Array::Ptr users = m_Users;
103
104         if (users) {
105                 ObjectLock olock(users);
106
107                 BOOST_FOREACH(const String& name, users) {
108                         User::Ptr user = User::GetByName(name);
109
110                         if (!user)
111                                 continue;
112
113                         result.insert(user);
114                 }
115         }
116
117         return result;
118 }
119
120 /**
121  * @threadsafety Always.
122  */
123 std::set<UserGroup::Ptr> Notification::GetGroups(void) const
124 {
125         std::set<UserGroup::Ptr> result;
126
127         Array::Ptr groups = m_Groups;
128
129         if (groups) {
130                 ObjectLock olock(groups);
131
132                 BOOST_FOREACH(const String& name, groups) {
133                         UserGroup::Ptr ug = UserGroup::GetByName(name);
134
135                         if (!ug)
136                                 continue;
137
138                         result.insert(ug);
139                 }
140         }
141
142         return result;
143 }
144
145 /**
146  * @threadsafety Always.
147  */
148 double Notification::GetNotificationInterval(void) const
149 {
150         if (m_NotificationInterval.IsEmpty())
151                 return 300;
152         else
153                 return m_NotificationInterval;
154 }
155
156 /**
157  * @threadsafety Always.
158  */
159 double Notification::GetLastNotification(void) const
160 {
161         if (m_LastNotification.IsEmpty())
162                 return 0;
163         else
164                 return m_LastNotification;
165 }
166
167 /**
168  * Sets the timestamp when the last notification was sent.
169  */
170 void Notification::SetLastNotification(double time)
171 {
172         m_LastNotification = time;
173         Touch("last_notification");
174 }
175
176 /**
177  * @threadsafety Always.
178  */
179 double Notification::GetNextNotification(void) const
180 {
181         if (m_NextNotification.IsEmpty())
182                 return 0;
183         else
184                 return m_NextNotification;
185 }
186
187 /**
188  * Sets the timestamp when the next periodical notification should be sent.
189  * This does not affect notifications that are sent for state changes.
190  */
191 void Notification::SetNextNotification(double time)
192 {
193         m_NextNotification = time;
194         Touch("next_notification");
195 }
196
197 /**
198  * @threadsafety Always.
199  */
200 String Notification::NotificationTypeToString(NotificationType type)
201 {
202         switch (type) {
203                 case NotificationDowntimeStart:
204                         return "DOWNTIMESTART";
205                 case NotificationDowntimeEnd:
206                         return "DOWNTIMEEND";
207                 case NotificationDowntimeRemoved:
208                         return "DOWNTIMECANCELLED";
209                 case NotificationCustom:
210                         return "CUSTOM";
211                 case NotificationAcknowledgement:
212                         return "ACKNOWLEDGEMENT";
213                 case NotificationProblem:
214                         return "PROBLEM";
215                 case NotificationRecovery:
216                         return "RECOVERY";
217                 default:
218                         return "UNKNOWN_NOTIFICATION";
219         }
220 }
221
222 /**
223  * @threadsafety Always.
224  */
225 void Notification::BeginExecuteNotification(NotificationType type, const Dictionary::Ptr& cr)
226 {
227         ASSERT(!OwnsLock());
228
229         {
230                 ObjectLock olock(this);
231
232                 SetLastNotification(Utility::GetTime());
233         }
234
235         Dictionary::Ptr macros = cr->Get("macros");
236
237         std::set<User::Ptr> allUsers;
238
239         std::set<User::Ptr> users = GetUsers();
240         std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin()));
241
242         BOOST_FOREACH(const UserGroup::Ptr& ug, GetGroups()) {
243                 std::set<User::Ptr> members = ug->GetMembers();
244                 std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin()));
245         }
246
247         BOOST_FOREACH(const User::Ptr& user, allUsers) {
248                 Log(LogDebug, "icinga", "Sending notification for user " + user->GetName());
249                 BeginExecuteNotificationHelper(macros, type, user);
250         }
251
252         if (allUsers.empty()) {
253                 /* Send a notification even if there are no users specified. */
254                 BeginExecuteNotificationHelper(macros, type, User::Ptr());
255         }
256 }
257
258 /**
259  * @threadsafety Always.
260  */
261 void Notification::BeginExecuteNotificationHelper(const Dictionary::Ptr& notificationMacros, NotificationType type, const User::Ptr& user)
262 {
263         ASSERT(!OwnsLock());
264
265         std::vector<Dictionary::Ptr> macroDicts;
266
267         if (user) {
268                 macroDicts.push_back(user->GetMacros());
269                 macroDicts.push_back(user->CalculateDynamicMacros());
270         }
271
272         macroDicts.push_back(notificationMacros);
273
274         Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
275
276         Notification::Ptr self = GetSelf();
277
278         std::vector<Value> arguments;
279         arguments.push_back(self);
280         arguments.push_back(macros);
281         arguments.push_back(type);
282
283         ScriptTask::Ptr task = MakeMethodTask("notify", arguments);
284
285         if (!task) {
286                 Log(LogWarning, "icinga", "Notification object '" + GetName() + "' doesn't have a 'notify' method.");
287
288                 return;
289         }
290
291         {
292                 ObjectLock olock(this);
293
294                 /* We need to keep the task object alive until the completion handler is called. */
295                 m_Tasks.insert(task);
296         }
297
298         task->Start(boost::bind(&Notification::NotificationCompletedHandler, self, _1));
299 }
300
301 /**
302  * @threadsafety Always.
303  */
304 void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
305 {
306         ASSERT(!OwnsLock());
307
308         {
309                 ObjectLock olock(this);
310
311                 m_Tasks.erase(task);
312         }
313
314         try {
315                 task->GetResult();
316
317                 Log(LogInformation, "icinga", "Completed sending notification for service '" + GetService()->GetName() + "'");
318         } catch (const std::exception& ex) {
319                 std::ostringstream msgbuf;
320                 msgbuf << "Exception occured during notification for service '"
321                        << GetService()->GetName() << "': " << boost::diagnostic_information(ex);
322                 String message = msgbuf.str();
323
324                 Log(LogWarning, "icinga", message);
325         }
326 }
327
328 /**
329  * @threadsafety Always.
330  */
331 void Notification::OnAttributeChanged(const String& name)
332 {
333         ASSERT(!OwnsLock());
334
335         if (name == "host_name" || name == "service")
336                 Service::InvalidateNotificationsCache();
337 }