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