]> granicus.if.org Git - icinga2/blob - lib/icinga/notification.cpp
Update documentation.
[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 "base/utility.h"
27 #include <boost/tuple/tuple.hpp>
28 #include <boost/foreach.hpp>
29 #include <boost/exception/diagnostic_information.hpp>
30
31 using namespace icinga;
32
33 REGISTER_TYPE(Notification);
34
35 Notification::Notification(const Dictionary::Ptr& serializedUpdate)
36         : DynamicObject(serializedUpdate)
37 {
38         RegisterAttribute("notification_command", Attribute_Config, &m_NotificationCommand);
39         RegisterAttribute("notification_interval", Attribute_Config, &m_NotificationInterval);
40         RegisterAttribute("notification_period", Attribute_Config, &m_NotificationPeriod);
41         RegisterAttribute("last_notification", Attribute_Replicated, &m_LastNotification);
42         RegisterAttribute("next_notification", Attribute_Replicated, &m_NextNotification);
43         RegisterAttribute("macros", Attribute_Config, &m_Macros);
44         RegisterAttribute("users", Attribute_Config, &m_Users);
45         RegisterAttribute("groups", Attribute_Config, &m_Groups);
46         RegisterAttribute("host_name", Attribute_Config, &m_HostName);
47         RegisterAttribute("service", Attribute_Config, &m_Service);
48         RegisterAttribute("export_macros", Attribute_Config, &m_ExportMacros);
49 }
50
51 Notification::~Notification(void)
52 {
53         Service::InvalidateNotificationsCache();
54 }
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 Service::Ptr Notification::GetService(void) const
64 {
65         Host::Ptr host = Host::GetByName(m_HostName);
66
67         if (!host)
68                 return Service::Ptr();
69
70         if (m_Service.IsEmpty())
71                 return host->GetHostCheckService();
72         else
73                 return host->GetServiceByShortName(m_Service);
74 }
75
76 Value Notification::GetNotificationCommand(void) const
77 {
78         return m_NotificationCommand;
79 }
80
81 Dictionary::Ptr Notification::GetMacros(void) const
82 {
83         return m_Macros;
84 }
85
86 Array::Ptr Notification::GetExportMacros(void) const
87 {
88         return m_ExportMacros;
89 }
90
91 std::set<User::Ptr> Notification::GetUsers(void) const
92 {
93         std::set<User::Ptr> result;
94
95         Array::Ptr users = m_Users;
96
97         if (users) {
98                 ObjectLock olock(users);
99
100                 BOOST_FOREACH(const String& name, users) {
101                         User::Ptr user = User::GetByName(name);
102
103                         if (!user)
104                                 continue;
105
106                         result.insert(user);
107                 }
108         }
109
110         return result;
111 }
112
113 std::set<UserGroup::Ptr> Notification::GetGroups(void) const
114 {
115         std::set<UserGroup::Ptr> result;
116
117         Array::Ptr groups = m_Groups;
118
119         if (groups) {
120                 ObjectLock olock(groups);
121
122                 BOOST_FOREACH(const String& name, groups) {
123                         UserGroup::Ptr ug = UserGroup::GetByName(name);
124
125                         if (!ug)
126                                 continue;
127
128                         result.insert(ug);
129                 }
130         }
131
132         return result;
133 }
134
135 double Notification::GetNotificationInterval(void) const
136 {
137         if (m_NotificationInterval.IsEmpty())
138                 return 300;
139         else
140                 return m_NotificationInterval;
141 }
142
143 TimePeriod::Ptr Notification::GetNotificationPeriod(void) const
144 {
145         return TimePeriod::GetByName(m_NotificationPeriod);
146 }
147
148 double Notification::GetLastNotification(void) const
149 {
150         if (m_LastNotification.IsEmpty())
151                 return 0;
152         else
153                 return m_LastNotification;
154 }
155
156 /**
157  * Sets the timestamp when the last notification was sent.
158  */
159 void Notification::SetLastNotification(double time)
160 {
161         m_LastNotification = time;
162         Touch("last_notification");
163 }
164
165 double Notification::GetNextNotification(void) const
166 {
167         if (m_NextNotification.IsEmpty())
168                 return 0;
169         else
170                 return m_NextNotification;
171 }
172
173 /**
174  * Sets the timestamp when the next periodical notification should be sent.
175  * This does not affect notifications that are sent for state changes.
176  */
177 void Notification::SetNextNotification(double time)
178 {
179         m_NextNotification = time;
180         Touch("next_notification");
181 }
182
183 String Notification::NotificationTypeToString(NotificationType type)
184 {
185         switch (type) {
186                 case NotificationDowntimeStart:
187                         return "DOWNTIMESTART";
188                 case NotificationDowntimeEnd:
189                         return "DOWNTIMEEND";
190                 case NotificationDowntimeRemoved:
191                         return "DOWNTIMECANCELLED";
192                 case NotificationCustom:
193                         return "CUSTOM";
194                 case NotificationAcknowledgement:
195                         return "ACKNOWLEDGEMENT";
196                 case NotificationProblem:
197                         return "PROBLEM";
198                 case NotificationRecovery:
199                         return "RECOVERY";
200                 default:
201                         return "UNKNOWN_NOTIFICATION";
202         }
203 }
204
205 void Notification::BeginExecuteNotification(NotificationType type, const Dictionary::Ptr& cr, bool ignore_timeperiod)
206 {
207         ASSERT(!OwnsLock());
208
209         if (!ignore_timeperiod) {
210                 TimePeriod::Ptr tp = GetNotificationPeriod();
211
212                 if (tp && !tp->IsInside(Utility::GetTime())) {
213                         Log(LogInformation, "icinga", "Not sending notifications for notification object '" + GetName() + "': not in timeperiod");
214                         return;
215                 }
216         }
217
218         {
219                 ObjectLock olock(this);
220
221                 SetLastNotification(Utility::GetTime());
222         }
223
224         std::set<User::Ptr> allUsers;
225
226         std::set<User::Ptr> users = GetUsers();
227         std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin()));
228
229         BOOST_FOREACH(const UserGroup::Ptr& ug, GetGroups()) {
230                 std::set<User::Ptr> members = ug->GetMembers();
231                 std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin()));
232         }
233
234         BOOST_FOREACH(const User::Ptr& user, allUsers) {
235                 Log(LogDebug, "icinga", "Sending notification for user " + user->GetName());
236                 Utility::QueueAsyncCallback(boost::bind(&Notification::ExecuteNotificationHelper, this, type, user, cr, ignore_timeperiod));
237         }
238 }
239
240 void Notification::ExecuteNotificationHelper(NotificationType type, const User::Ptr& user, const Dictionary::Ptr& cr, bool ignore_timeperiod)
241 {
242         ASSERT(!OwnsLock());
243
244         if (!ignore_timeperiod) {
245                 TimePeriod::Ptr tp = user->GetNotificationPeriod();
246
247                 if (tp && !tp->IsInside(Utility::GetTime())) {
248                         Log(LogInformation, "icinga", "Not sending notifications for notification object '" +
249                             GetName() + " and user '" + user->GetName() + "': user not in timeperiod");
250                         return;
251                 }
252         }
253
254         Notification::Ptr self = GetSelf();
255
256         std::vector<Value> arguments;
257         arguments.push_back(self);
258         arguments.push_back(user);
259         arguments.push_back(cr);
260         arguments.push_back(type);
261
262         try {
263                 InvokeMethod("notify", arguments);
264
265                 Log(LogInformation, "icinga", "Completed sending notification for service '" + GetService()->GetName() + "'");
266         } catch (const std::exception& ex) {
267                 std::ostringstream msgbuf;
268                 msgbuf << "Exception occured during notification for service '"
269                        << GetService()->GetName() << "': " << boost::diagnostic_information(ex);
270                 String message = msgbuf.str();
271
272                 Log(LogWarning, "icinga", message);
273         }
274 }
275
276 void Notification::OnAttributeChanged(const String& name)
277 {
278         ASSERT(!OwnsLock());
279
280         if (name == "host_name" || name == "service")
281                 Service::InvalidateNotificationsCache();
282 }
283
284 bool Notification::ResolveMacro(const String& macro, const Dictionary::Ptr&, String *result) const
285 {
286         Dictionary::Ptr macros = GetMacros();
287
288         if (macros && macros->Contains(macro)) {
289                 *result = macros->Get(macro);
290                 return true;
291         }
292
293         return false;
294 }