]> granicus.if.org Git - icinga2/blob - lib/db_ido/dbevents.cpp
Fix Zone::IsGlobal()
[icinga2] / lib / db_ido / dbevents.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 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 "db_ido/dbevents.hpp"
21 #include "db_ido/dbtype.hpp"
22 #include "db_ido/dbvalue.hpp"
23 #include "base/convert.hpp"
24 #include "base/objectlock.hpp"
25 #include "base/initialize.hpp"
26 #include "base/dynamictype.hpp"
27 #include "base/utility.hpp"
28 #include "base/logger.hpp"
29 #include "remote/endpoint.hpp"
30 #include "icinga/notification.hpp"
31 #include "icinga/checkcommand.hpp"
32 #include "icinga/eventcommand.hpp"
33 #include "icinga/externalcommandprocessor.hpp"
34 #include "icinga/compatutility.hpp"
35 #include "icinga/icingaapplication.hpp"
36 #include <boost/foreach.hpp>
37 #include <boost/algorithm/string/join.hpp>
38
39 using namespace icinga;
40
41 INITIALIZE_ONCE(&DbEvents::StaticInitialize);
42
43 void DbEvents::StaticInitialize(void)
44 {
45         /* Status */
46         Checkable::OnCommentAdded.connect(boost::bind(&DbEvents::AddComment, _1, _2));
47         Checkable::OnCommentRemoved.connect(boost::bind(&DbEvents::RemoveComment, _1, _2));
48         Checkable::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntime, _1, _2));
49         Checkable::OnDowntimeRemoved.connect(boost::bind(&DbEvents::RemoveDowntime, _1, _2));
50         Checkable::OnDowntimeTriggered.connect(boost::bind(&DbEvents::TriggerDowntime, _1, _2));
51         Checkable::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgement, _1, _4));
52         Checkable::OnAcknowledgementCleared.connect(boost::bind(&DbEvents::RemoveAcknowledgement, _1));
53
54         Checkable::OnNextCheckChanged.connect(boost::bind(&DbEvents::NextCheckChangedHandler, _1, _2));
55         Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::FlappingChangedHandler, _1, _2));
56         Checkable::OnNotificationSentToAllUsers.connect(boost::bind(&DbEvents::LastNotificationChangedHandler, _1, _2));
57
58         Checkable::OnEnableActiveChecksChanged.connect(boost::bind(&DbEvents::EnableActiveChecksChangedHandler, _1, _2));
59         Checkable::OnEnablePassiveChecksChanged.connect(boost::bind(&DbEvents::EnablePassiveChecksChangedHandler, _1, _2));
60         Checkable::OnEnableNotificationsChanged.connect(boost::bind(&DbEvents::EnableNotificationsChangedHandler, _1, _2));
61         Checkable::OnEnablePerfdataChanged.connect(boost::bind(&DbEvents::EnablePerfdataChangedHandler, _1, _2));
62         Checkable::OnEnableFlappingChanged.connect(boost::bind(&DbEvents::EnableFlappingChangedHandler, _1, _2));
63
64         /* History */
65         Checkable::OnCommentAdded.connect(boost::bind(&DbEvents::AddCommentHistory, _1, _2));
66         Checkable::OnDowntimeAdded.connect(boost::bind(&DbEvents::AddDowntimeHistory, _1, _2));
67         Checkable::OnAcknowledgementSet.connect(boost::bind(&DbEvents::AddAcknowledgementHistory, _1, _2, _3, _4, _5));
68
69         Checkable::OnNotificationSentToAllUsers.connect(boost::bind(&DbEvents::AddNotificationHistory, _1, _2, _3, _4, _5, _6, _7));
70
71         Checkable::OnStateChange.connect(boost::bind(&DbEvents::AddStateChangeHistory, _1, _2, _3));
72
73         Checkable::OnNewCheckResult.connect(boost::bind(&DbEvents::AddCheckResultLogHistory, _1, _2));
74         Checkable::OnNotificationSentToUser.connect(boost::bind(&DbEvents::AddNotificationSentLogHistory, _1, _2, _3, _4, _5, _6, _7));
75         Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::AddFlappingLogHistory, _1, _2));
76         Checkable::OnDowntimeTriggered.connect(boost::bind(&DbEvents::AddTriggerDowntimeLogHistory, _1, _2));
77         Checkable::OnDowntimeRemoved.connect(boost::bind(&DbEvents::AddRemoveDowntimeLogHistory, _1, _2));
78
79         Checkable::OnFlappingChanged.connect(boost::bind(&DbEvents::AddFlappingHistory, _1, _2));
80         Checkable::OnNewCheckResult.connect(boost::bind(&DbEvents::AddServiceCheckHistory, _1, _2));
81
82         Checkable::OnEventCommandExecuted.connect(boost::bind(&DbEvents::AddEventHandlerHistory, _1));
83
84         ExternalCommandProcessor::OnNewExternalCommand.connect(boost::bind(&DbEvents::AddExternalCommandHistory, _1, _2, _3));
85 }
86
87 /* check events */
88 void DbEvents::NextCheckChangedHandler(const Checkable::Ptr& checkable, double nextCheck)
89 {
90         Host::Ptr host;
91         Service::Ptr service;
92         tie(host, service) = GetHostService(checkable);
93
94         DbQuery query1;
95         if (service)
96                 query1.Table = "servicestatus";
97         else
98                 query1.Table = "hoststatus";
99
100         query1.Type = DbQueryUpdate;
101
102         Dictionary::Ptr fields1 = make_shared<Dictionary>();
103         fields1->Set("next_check", DbValue::FromTimestamp(nextCheck));
104
105         query1.Fields = fields1;
106
107         query1.WhereCriteria = make_shared<Dictionary>();
108         if (service)
109                 query1.WhereCriteria->Set("service_object_id", service);
110         else
111                 query1.WhereCriteria->Set("host_object_id", host);
112
113         query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
114
115         DbObject::OnQuery(query1);
116 }
117
118 void DbEvents::FlappingChangedHandler(const Checkable::Ptr& checkable, FlappingState state)
119 {
120         Host::Ptr host;
121         Service::Ptr service;
122         tie(host, service) = GetHostService(checkable);
123
124         DbQuery query1;
125         if (service)
126                 query1.Table = "servicestatus";
127         else
128                 query1.Table = "hoststatus";
129
130         query1.Type = DbQueryUpdate;
131
132         Dictionary::Ptr fields1 = make_shared<Dictionary>();
133         fields1->Set("is_flapping", CompatUtility::GetCheckableIsFlapping(checkable));
134         fields1->Set("percent_state_change", CompatUtility::GetCheckablePercentStateChange(checkable));
135
136         query1.Fields = fields1;
137
138         query1.WhereCriteria = make_shared<Dictionary>();
139         if (service)
140                 query1.WhereCriteria->Set("service_object_id", service);
141         else
142                 query1.WhereCriteria->Set("host_object_id", host);
143
144         query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
145
146         DbObject::OnQuery(query1);
147 }
148
149 void DbEvents::LastNotificationChangedHandler(const Notification::Ptr& notification, const Checkable::Ptr& checkable)
150 {
151         double now = Utility::GetTime();
152         std::pair<unsigned long, unsigned long> now_bag = CompatUtility::ConvertTimestamp(now);
153         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(notification->GetNextNotification());
154
155         Host::Ptr host;
156         Service::Ptr service;
157         tie(host, service) = GetHostService(checkable);
158
159         DbQuery query1;
160         if (service)
161                 query1.Table = "servicestatus";
162         else
163                 query1.Table = "hoststatus";
164
165         query1.Type = DbQueryUpdate;
166
167         Dictionary::Ptr fields1 = make_shared<Dictionary>();
168         fields1->Set("last_notification", DbValue::FromTimestamp(now_bag.first));
169         fields1->Set("next_notification", DbValue::FromTimestamp(time_bag.first));
170         fields1->Set("current_notification_number", notification->GetNotificationNumber());
171
172         query1.Fields = fields1;
173
174         query1.WhereCriteria = make_shared<Dictionary>();
175         if (service)
176                 query1.WhereCriteria->Set("service_object_id", service);
177         else
178                 query1.WhereCriteria->Set("host_object_id", host);
179
180         query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
181
182         DbObject::OnQuery(query1);
183 }
184
185 /* enable changed events */
186 void DbEvents::EnableActiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled)
187 {
188         EnableChangedHandlerInternal(checkable, enabled, EnableActiveChecks);
189 }
190
191 void DbEvents::EnablePassiveChecksChangedHandler(const Checkable::Ptr& checkable, bool enabled)
192 {
193         EnableChangedHandlerInternal(checkable, enabled, EnablePassiveChecks);
194 }
195
196 void DbEvents::EnableNotificationsChangedHandler(const Checkable::Ptr& checkable, bool enabled)
197 {
198         EnableChangedHandlerInternal(checkable, enabled, EnableNotifications);
199 }
200
201 void DbEvents::EnablePerfdataChangedHandler(const Checkable::Ptr& checkable, bool enabled)
202 {
203         EnableChangedHandlerInternal(checkable, enabled, EnablePerfdata);
204 }
205
206 void DbEvents::EnableFlappingChangedHandler(const Checkable::Ptr& checkable, bool enabled)
207 {
208         EnableChangedHandlerInternal(checkable, enabled, EnableFlapping);
209 }
210
211 void DbEvents::EnableChangedHandlerInternal(const Checkable::Ptr& checkable, bool enabled, EnableType type)
212 {
213         Host::Ptr host;
214         Service::Ptr service;
215         tie(host, service) = GetHostService(checkable);
216
217         DbQuery query1;
218         if (service)
219                 query1.Table = "servicestatus";
220         else
221                 query1.Table = "hoststatus";
222
223         query1.Type = DbQueryUpdate;
224
225         Dictionary::Ptr fields1 = make_shared<Dictionary>();
226
227         if (type == EnableActiveChecks) {
228                 fields1->Set("active_checks_enabled", enabled ? 1 : 0);
229         } else if (type == EnablePassiveChecks) {
230                 fields1->Set("passive_checks_enabled", enabled ? 1 : 0);
231         } else if (type == EnableNotifications) {
232                 fields1->Set("notifications_enabled", enabled ? 1 : 0);
233         } else if (type == EnablePerfdata) {
234                 fields1->Set("process_performance_data", enabled ? 1 : 0);
235         } else if (type == EnableFlapping) {
236                 fields1->Set("flap_detection_enabled", enabled ? 1 : 0);
237         }
238
239         query1.Fields = fields1;
240
241         query1.WhereCriteria = make_shared<Dictionary>();
242         if (service)
243                 query1.WhereCriteria->Set("service_object_id", service);
244         else
245                 query1.WhereCriteria->Set("host_object_id", host);
246
247         query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
248
249         DbObject::OnQuery(query1);
250 }
251
252 /* comments */
253 void DbEvents::AddComments(const Checkable::Ptr& checkable)
254 {
255         /* dump all comments */
256         Dictionary::Ptr comments = checkable->GetComments();
257
258         if (comments->GetLength() > 0)
259                 RemoveComments(checkable);
260
261         ObjectLock olock(comments);
262
263         BOOST_FOREACH(const Dictionary::Pair& kv, comments) {
264                 AddComment(checkable, kv.second);
265         }
266 }
267
268 void DbEvents::AddComment(const Checkable::Ptr& checkable, const Comment::Ptr& comment)
269 {
270         AddCommentInternal(checkable, comment, false);
271 }
272
273 void DbEvents::AddCommentHistory(const Checkable::Ptr& checkable, const Comment::Ptr& comment)
274 {
275         AddCommentInternal(checkable, comment, true);
276 }
277
278 void DbEvents::AddCommentInternal(const Checkable::Ptr& checkable, const Comment::Ptr& comment, bool historical)
279 {
280         if (!comment) {
281                 Log(LogWarning, "DbEvents", "comment does not exist. not adding it.");
282                 return;
283         }
284
285         Log(LogDebug, "DbEvents")
286             << "adding service comment (id = " << comment->GetLegacyId() << ") for '" << checkable->GetName() << "'";
287
288         /* add the service comment */
289         AddCommentByType(checkable, comment, historical);
290 }
291
292 void DbEvents::AddCommentByType(const DynamicObject::Ptr& object, const Comment::Ptr& comment, bool historical)
293 {
294         unsigned long entry_time = static_cast<long>(comment->GetEntryTime());
295         unsigned long entry_time_usec = (comment->GetEntryTime() - entry_time) * 1000 * 1000;
296
297         Dictionary::Ptr fields1 = make_shared<Dictionary>();
298         fields1->Set("entry_time", DbValue::FromTimestamp(entry_time));
299         fields1->Set("entry_time_usec", entry_time_usec);
300         fields1->Set("entry_type", comment->GetEntryType());
301         fields1->Set("object_id", object);
302
303         if (object->GetType() == DynamicType::GetByName("Host")) {
304                 fields1->Set("comment_type", 2);
305                 /* requires idoutils 1.10 schema fix */
306                 fields1->Set("internal_comment_id", comment->GetLegacyId());
307         } else if (object->GetType() == DynamicType::GetByName("Service")) {
308                 fields1->Set("comment_type", 1);
309                 fields1->Set("internal_comment_id", comment->GetLegacyId());
310         } else {
311                 Log(LogDebug, "DbEvents", "unknown object type for adding comment.");
312                 return;
313         }
314
315         fields1->Set("comment_time", DbValue::FromTimestamp(entry_time)); /* same as entry_time */
316         fields1->Set("author_name", comment->GetAuthor());
317         fields1->Set("comment_data", comment->GetText());
318         fields1->Set("is_persistent", 1);
319         fields1->Set("comment_source", 1); /* external */
320         fields1->Set("expires", (comment->GetExpireTime() > 0) ? 1 : 0);
321         fields1->Set("expiration_time", DbValue::FromTimestamp(comment->GetExpireTime()));
322         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
323
324         String node = IcingaApplication::GetInstance()->GetNodeName();
325
326         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
327         if (endpoint)
328                 fields1->Set("endpoint_object_id", endpoint);
329
330         DbQuery query1;
331         if (!historical) {
332                 query1.Table = "comments";
333         } else {
334                 query1.Table = "commenthistory";
335         }
336         query1.Type = DbQueryInsert;
337         query1.Category = DbCatComment;
338         query1.Fields = fields1;
339         DbObject::OnQuery(query1);
340 }
341
342 void DbEvents::RemoveComments(const Checkable::Ptr& checkable)
343 {
344         Log(LogDebug, "DbEvents")
345             << "removing service comments for '" << checkable->GetName() << "'";
346
347         DbQuery query1;
348         query1.Table = "comments";
349         query1.Type = DbQueryDelete;
350         query1.Category = DbCatComment;
351         query1.WhereCriteria = make_shared<Dictionary>();
352         query1.WhereCriteria->Set("object_id", checkable);
353         DbObject::OnQuery(query1);
354 }
355
356 void DbEvents::RemoveComment(const Checkable::Ptr& checkable, const Comment::Ptr& comment)
357 {
358         if (!comment) {
359                 Log(LogWarning, "DbEvents", "comment does not exist. not deleting it.");
360                 return;
361         }
362
363         Log(LogDebug, "DbEvents")
364             << "removing service comment (id = " << comment->GetLegacyId() << ") for '" << checkable->GetName() << "'";
365
366         /* Status */
367         DbQuery query1;
368         query1.Table = "comments";
369         query1.Type = DbQueryDelete;
370         query1.Category = DbCatComment;
371         query1.WhereCriteria = make_shared<Dictionary>();
372         query1.WhereCriteria->Set("object_id", checkable);
373         query1.WhereCriteria->Set("internal_comment_id", comment->GetLegacyId());
374         DbObject::OnQuery(query1);
375
376         /* History - update deletion time for service/host */
377         unsigned long entry_time = static_cast<long>(comment->GetEntryTime());
378
379         double now = Utility::GetTime();
380         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
381
382         DbQuery query2;
383         query2.Table = "commenthistory";
384         query2.Type = DbQueryUpdate;
385         query2.Category = DbCatComment;
386
387         Dictionary::Ptr fields2 = make_shared<Dictionary>();
388         fields2->Set("deletion_time", DbValue::FromTimestamp(time_bag.first));
389         fields2->Set("deletion_time_usec", time_bag.second);
390         query2.Fields = fields2;
391
392         query2.WhereCriteria = make_shared<Dictionary>();
393         query2.WhereCriteria->Set("internal_comment_id", comment->GetLegacyId());
394         query2.WhereCriteria->Set("comment_time", DbValue::FromTimestamp(entry_time));
395         query2.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
396
397         DbObject::OnQuery(query2);
398 }
399
400 /* downtimes */
401 void DbEvents::AddDowntimes(const Checkable::Ptr& checkable)
402 {
403         /* dump all downtimes */
404         Dictionary::Ptr downtimes = checkable->GetDowntimes();
405
406         if (downtimes->GetLength() > 0)
407                 RemoveDowntimes(checkable);
408
409         ObjectLock olock(downtimes);
410
411         BOOST_FOREACH(const Dictionary::Pair& kv, downtimes) {
412                 AddDowntime(checkable, kv.second);
413         }
414 }
415
416 void DbEvents::AddDowntime(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
417 {
418         AddDowntimeInternal(checkable, downtime, false);
419 }
420
421 void DbEvents::AddDowntimeHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
422 {
423         AddDowntimeInternal(checkable, downtime, true);
424 }
425
426 void DbEvents::AddDowntimeInternal(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, bool historical)
427 {
428         if (!downtime) {
429                 Log(LogWarning, "DbEvents", "downtime does not exist. not adding it.");
430                 return;
431         }
432
433         Log(LogDebug, "DbEvents")
434             << "adding service downtime (id = " << downtime->GetLegacyId() << ") for '" << checkable->GetName() << "'";
435
436         /* add the downtime */
437         AddDowntimeByType(checkable, downtime, historical);}
438
439 void DbEvents::AddDowntimeByType(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime, bool historical)
440 {
441         Dictionary::Ptr fields1 = make_shared<Dictionary>();
442         fields1->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
443         fields1->Set("object_id", checkable);
444
445         if (checkable->GetType() == DynamicType::GetByName("Host")) {
446                 fields1->Set("downtime_type", 2);
447                 /* requires idoutils 1.10 schema fix */
448                 fields1->Set("internal_downtime_id", downtime->GetLegacyId());
449         } else if (checkable->GetType() == DynamicType::GetByName("Service")) {
450                 fields1->Set("downtime_type", 1);
451                 fields1->Set("internal_downtime_id", downtime->GetLegacyId());
452         } else {
453                 Log(LogDebug, "DbEvents", "unknown object type for adding downtime.");
454                 return;
455         }
456
457         fields1->Set("author_name", downtime->GetAuthor());
458         fields1->Set("comment_data", downtime->GetComment());
459         fields1->Set("triggered_by_id", Service::GetDowntimeByID(downtime->GetTriggeredBy()));
460         fields1->Set("is_fixed", downtime->GetFixed());
461         fields1->Set("duration", downtime->GetDuration());
462         fields1->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
463         fields1->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
464         fields1->Set("was_started", Empty);
465         fields1->Set("actual_start_time", Empty);
466         fields1->Set("actual_start_time_usec", Empty);
467         fields1->Set("is_in_effect", Empty);
468         fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
469         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
470
471         String node = IcingaApplication::GetInstance()->GetNodeName();
472
473         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
474         if (endpoint)
475                 fields1->Set("endpoint_object_id", endpoint);
476
477         DbQuery query1;
478
479         if (!historical)
480                 query1.Table = "scheduleddowntime";
481         else
482                 query1.Table = "downtimehistory";
483
484         query1.Type = DbQueryInsert;
485         query1.Category = DbCatDowntime;
486         query1.Fields = fields1;
487         DbObject::OnQuery(query1);
488 }
489
490 void DbEvents::RemoveDowntimes(const Checkable::Ptr& checkable)
491 {
492         Log(LogDebug, "DbEvents")
493             << "removing service downtimes for '" << checkable->GetName() << "'";
494
495         DbQuery query1;
496         query1.Table = "scheduleddowntime";
497         query1.Type = DbQueryDelete;
498         query1.Category = DbCatDowntime;
499         query1.WhereCriteria = make_shared<Dictionary>();
500         query1.WhereCriteria->Set("object_id", checkable);
501         DbObject::OnQuery(query1);
502 }
503
504 void DbEvents::RemoveDowntime(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
505 {
506         if (!downtime) {
507                 Log(LogWarning, "DbEvents", "downtime does not exist. not adding it.");
508                 return;
509         }
510
511         Log(LogDebug, "DbEvents")
512             << "removing service downtime (id = " << downtime->GetLegacyId() << ") for '" << checkable->GetName() << "'";
513
514         /* Status */
515         DbQuery query1;
516         query1.Table = "scheduleddowntime";
517         query1.Type = DbQueryDelete;
518         query1.Category = DbCatDowntime;
519         query1.WhereCriteria = make_shared<Dictionary>();
520         query1.WhereCriteria->Set("object_id", checkable);
521         query1.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
522         DbObject::OnQuery(query1);
523
524         /* History - update actual_end_time, was_cancelled for service (and host in case) */
525         double now = Utility::GetTime();
526         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
527
528         DbQuery query3;
529         query3.Table = "downtimehistory";
530         query3.Type = DbQueryUpdate;
531         query3.Category = DbCatDowntime;
532
533         Dictionary::Ptr fields3 = make_shared<Dictionary>();
534         fields3->Set("was_cancelled", downtime->GetWasCancelled() ? 1 : 0);
535         fields3->Set("actual_end_time", DbValue::FromTimestamp(time_bag.first));
536         fields3->Set("actual_end_time_usec", time_bag.second);
537         query3.Fields = fields3;
538
539         query3.WhereCriteria = make_shared<Dictionary>();
540         query3.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
541         query3.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
542         query3.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
543         query3.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
544         query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
545
546         DbObject::OnQuery(query3);
547 }
548
549 void DbEvents::TriggerDowntime(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
550 {
551         if (!downtime) {
552                 Log(LogWarning, "DbEvents", "downtime does not exist. not updating it.");
553                 return;
554         }
555
556         Log(LogDebug, "DbEvents")
557             << "updating triggered service downtime (id = " << downtime->GetLegacyId() << ") for '" << checkable->GetName() << "'";
558
559         double now = Utility::GetTime();
560         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
561
562         /* Status */
563         DbQuery query1;
564         query1.Table = "scheduleddowntime";
565         query1.Type = DbQueryUpdate;
566         query1.Category = DbCatDowntime;
567
568         Dictionary::Ptr fields1 = make_shared<Dictionary>();
569         fields1->Set("was_started", 1);
570         fields1->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first));
571         fields1->Set("actual_start_time_usec", time_bag.second);
572         fields1->Set("is_in_effect", 1);
573         fields1->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
574         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
575
576         query1.WhereCriteria = make_shared<Dictionary>();
577         query1.WhereCriteria->Set("object_id", checkable);
578         query1.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
579
580         query1.Fields = fields1;
581         DbObject::OnQuery(query1);
582
583         /* History - downtime was started for service (and host in case) */
584         DbQuery query3;
585         query3.Table = "downtimehistory";
586         query3.Type = DbQueryUpdate;
587         query3.Category = DbCatDowntime;
588
589         Dictionary::Ptr fields3 = make_shared<Dictionary>();
590         fields3->Set("was_started", 1);
591         fields3->Set("is_in_effect", 1);
592         fields3->Set("actual_start_time", DbValue::FromTimestamp(time_bag.first));
593         fields3->Set("actual_start_time_usec", time_bag.second);
594         fields3->Set("trigger_time", DbValue::FromTimestamp(downtime->GetTriggerTime()));
595         query3.Fields = fields3;
596
597         query3.WhereCriteria = make_shared<Dictionary>();
598         query3.WhereCriteria->Set("internal_downtime_id", downtime->GetLegacyId());
599         query3.WhereCriteria->Set("entry_time", DbValue::FromTimestamp(downtime->GetEntryTime()));
600         query3.WhereCriteria->Set("scheduled_start_time", DbValue::FromTimestamp(downtime->GetStartTime()));
601         query3.WhereCriteria->Set("scheduled_end_time", DbValue::FromTimestamp(downtime->GetEndTime()));
602         query3.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
603
604         DbObject::OnQuery(query3);
605
606         /* host/service status */
607         Host::Ptr host;
608         Service::Ptr service;
609         tie(host, service) = GetHostService(checkable);
610
611         DbQuery query4;
612         if (service)
613                 query4.Table = "servicestatus";
614         else
615                 query4.Table = "hoststatus";
616
617         query4.Type = DbQueryUpdate;
618
619         Dictionary::Ptr fields4 = make_shared<Dictionary>();
620         fields4->Set("scheduled_downtime_depth", checkable->GetDowntimeDepth());
621
622         query4.Fields = fields4;
623
624         query4.WhereCriteria = make_shared<Dictionary>();
625         if (service)
626                 query4.WhereCriteria->Set("service_object_id", service);
627         else
628                 query4.WhereCriteria->Set("host_object_id", host);
629
630         query4.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
631
632         DbObject::OnQuery(query4);
633 }
634
635 /* acknowledgements */
636 void DbEvents::AddAcknowledgementHistory(const Checkable::Ptr& checkable, const String& author, const String& comment,
637     AcknowledgementType type, double expiry)
638 {
639         Log(LogDebug, "DbEvents")
640             << "add acknowledgement history for '" << checkable->GetName() << "'";
641
642         double now = Utility::GetTime();
643         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
644
645         unsigned long end_time = static_cast<long>(expiry);
646
647         DbQuery query1;
648         query1.Table = "acknowledgements";
649         query1.Type = DbQueryInsert;
650         query1.Category = DbCatAcknowledgement;
651
652         Host::Ptr host;
653         Service::Ptr service;
654         tie(host, service) = GetHostService(checkable);
655
656         Dictionary::Ptr fields1 = make_shared<Dictionary>();
657         fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first));
658         fields1->Set("entry_time_usec", time_bag.second);
659         fields1->Set("acknowledgement_type", type);
660         fields1->Set("object_id", checkable);
661         fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
662         fields1->Set("author_name", author);
663         fields1->Set("comment_data", comment);
664         fields1->Set("is_sticky", type == AcknowledgementSticky ? 1 : 0);
665         fields1->Set("end_time", DbValue::FromTimestamp(end_time));
666         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
667
668         String node = IcingaApplication::GetInstance()->GetNodeName();
669
670         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
671         if (endpoint)
672                 fields1->Set("endpoint_object_id", endpoint);
673
674         query1.Fields = fields1;
675         DbObject::OnQuery(query1);
676 }
677
678 void DbEvents::AddAcknowledgement(const Checkable::Ptr& checkable, AcknowledgementType type)
679 {
680         Log(LogDebug, "DbEvents")
681             << "add acknowledgement for '" << checkable->GetName() << "'";
682
683         AddAcknowledgementInternal(checkable, type, true);
684 }
685
686 void DbEvents::RemoveAcknowledgement(const Checkable::Ptr& checkable)
687 {
688         Log(LogDebug, "DbEvents")
689             << "remove acknowledgement for '" << checkable->GetName() << "'";
690
691         AddAcknowledgementInternal(checkable, AcknowledgementNone, false);
692 }
693
694 void DbEvents::AddAcknowledgementInternal(const Checkable::Ptr& checkable, AcknowledgementType type, bool add)
695 {
696         Host::Ptr host;
697         Service::Ptr service;
698         tie(host, service) = GetHostService(checkable);
699
700         DbQuery query1;
701         if (service)
702                 query1.Table = "servicestatus";
703         else
704                 query1.Table = "hoststatus";
705
706         query1.Type = DbQueryUpdate;
707         query1.Category = DbCatAcknowledgement;
708
709         Dictionary::Ptr fields1 = make_shared<Dictionary>();
710         fields1->Set("acknowledgement_type", type);
711         fields1->Set("problem_has_been_acknowledged", add ? 1 : 0);
712         query1.Fields = fields1;
713
714         query1.WhereCriteria = make_shared<Dictionary>();
715         if (service)
716                 query1.WhereCriteria->Set("service_object_id", service);
717         else
718                 query1.WhereCriteria->Set("host_object_id", host);
719
720         query1.WhereCriteria->Set("instance_id", 0); /* DbConnection class fills in real ID */
721
722         DbObject::OnQuery(query1);
723 }
724
725 /* notifications */
726 void DbEvents::AddNotificationHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const std::set<User::Ptr>& users, NotificationType type,
727     const CheckResult::Ptr& cr, const String& author, const String& text)
728 {
729         Log(LogDebug, "DbEvents")
730             << "add notification history for '" << checkable->GetName() << "'";
731
732         /* start and end happen at the same time */
733         double now = Utility::GetTime();
734         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
735
736         DbQuery query1;
737         query1.Table = "notifications";
738         query1.Type = DbQueryInsert;
739         query1.Category = DbCatNotification;
740         /* store the object ptr for caching the insert id for this object */
741         query1.NotificationObject = notification;
742
743         Host::Ptr host;
744         Service::Ptr service;
745         tie(host, service) = GetHostService(checkable);
746
747         Dictionary::Ptr fields1 = make_shared<Dictionary>();
748         fields1->Set("notification_type", 1); /* service */
749         fields1->Set("notification_reason", CompatUtility::MapNotificationReasonType(type));
750         fields1->Set("object_id", checkable);
751         fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
752         fields1->Set("start_time_usec", time_bag.second);
753         fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first));
754         fields1->Set("end_time_usec", time_bag.second);
755         fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
756
757         if (cr) {
758                 fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
759                 fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
760         }
761
762         fields1->Set("escalated", 0);
763         fields1->Set("contacts_notified", static_cast<long>(users.size()));
764         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
765
766         String node = IcingaApplication::GetInstance()->GetNodeName();
767
768         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
769         if (endpoint)
770                 fields1->Set("endpoint_object_id", endpoint);
771
772         query1.Fields = fields1;
773         DbObject::OnQuery(query1);
774
775         DbQuery query2;
776         query2.Table = "contactnotifications";
777         query2.Type = DbQueryInsert;
778         query2.Category = DbCatNotification;
779
780         /* filtered users */
781         BOOST_FOREACH(const User::Ptr& user, users) {
782                 Log(LogDebug, "DbEvents")
783                     << "add contact notification history for service '" << checkable->GetName() << "' and user '" << user->GetName() << "'.";
784
785                 Dictionary::Ptr fields2 = make_shared<Dictionary>();
786                 fields2->Set("contact_object_id", user);
787                 fields2->Set("start_time", DbValue::FromTimestamp(time_bag.first));
788                 fields2->Set("start_time_usec", time_bag.second);
789                 fields2->Set("end_time", DbValue::FromTimestamp(time_bag.first));
790                 fields2->Set("end_time_usec", time_bag.second);
791
792                 fields2->Set("notification_id", notification); /* DbConnection class fills in real ID from notification insert id cache */
793                 fields2->Set("instance_id", 0); /* DbConnection class fills in real ID */
794
795                 query2.Fields = fields2;
796                 DbObject::OnQuery(query2);
797         }
798 }
799
800 /* statehistory */
801 void DbEvents::AddStateChangeHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr, StateType type)
802 {
803         Log(LogDebug, "DbEvents")
804             << "add state change history for '" << checkable->GetName() << "'";
805
806         double now = Utility::GetTime();
807         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
808
809         DbQuery query1;
810         query1.Table = "statehistory";
811         query1.Type = DbQueryInsert;
812         query1.Category = DbCatStateHistory;
813
814         Host::Ptr host;
815         Service::Ptr service;
816         tie(host, service) = GetHostService(checkable);
817
818         Dictionary::Ptr fields1 = make_shared<Dictionary>();
819         fields1->Set("state_time", DbValue::FromTimestamp(time_bag.first));
820         fields1->Set("state_time_usec", time_bag.second);
821         fields1->Set("object_id", checkable);
822         fields1->Set("state_change", 1); /* service */
823         fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
824         fields1->Set("state_type", checkable->GetStateType());
825         fields1->Set("current_check_attempt", checkable->GetCheckAttempt());
826         fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts());
827
828         if (service) {
829                 fields1->Set("last_state", service->GetLastState());
830                 fields1->Set("last_hard_state", service->GetLastHardState());
831         } else {
832                 fields1->Set("last_state", host->GetLastState());
833                 fields1->Set("last_hard_state", host->GetLastHardState());
834         }
835
836         if (cr) {
837                 fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
838                 fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
839                 fields1->Set("check_source", cr->GetCheckSource());
840         }
841
842         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
843
844         String node = IcingaApplication::GetInstance()->GetNodeName();
845
846         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
847         if (endpoint)
848                 fields1->Set("endpoint_object_id", endpoint);
849
850         query1.Fields = fields1;
851         DbObject::OnQuery(query1);
852 }
853
854 /* logentries */
855 void DbEvents::AddCheckResultLogHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr)
856 {
857         Dictionary::Ptr vars_after = cr->GetVarsAfter();
858
859         long state_after = vars_after->Get("state");
860         long stateType_after = vars_after->Get("state_type");
861         long attempt_after = vars_after->Get("attempt");
862         bool reachable_after = vars_after->Get("reachable");
863
864         Dictionary::Ptr vars_before = cr->GetVarsBefore();
865
866         if (vars_before) {
867                 long state_before = vars_before->Get("state");
868                 long stateType_before = vars_before->Get("state_type");
869                 long attempt_before = vars_before->Get("attempt");
870                 bool reachable_before = vars_before->Get("reachable");
871
872                 if (state_before == state_after && stateType_before == stateType_after &&
873                     attempt_before == attempt_after && reachable_before == reachable_after)
874                         return; /* Nothing changed, ignore this checkresult. */
875         }
876
877         LogEntryType type;
878         String output;
879
880         if (cr)
881                 output = CompatUtility::GetCheckResultOutput(cr);
882
883         Host::Ptr host;
884         Service::Ptr service;
885         tie(host, service) = GetHostService(checkable);
886
887         std::ostringstream msgbuf;
888
889         if (service) {
890                 msgbuf << "SERVICE ALERT: "
891                        << host->GetName() << ";"
892                        << service->GetShortName() << ";"
893                        << Service::StateToString(static_cast<ServiceState>(state_after)) << ";"
894                        << Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
895                        << attempt_after << ";"
896                        << output << ""
897                        << "";
898
899                 switch (service->GetState()) {
900                         case ServiceOK:
901                                 type = LogEntryTypeServiceOk;
902                                 break;
903                         case ServiceUnknown:
904                                 type = LogEntryTypeServiceUnknown;
905                                 break;
906                         case ServiceWarning:
907                                 type = LogEntryTypeServiceWarning;
908                                 break;
909                         case ServiceCritical:
910                                 type = LogEntryTypeServiceCritical;
911                                 break;
912                         default:
913                                 Log(LogCritical, "DbEvents")
914                                     << "Unknown service state: " << state_after;
915                                 return;
916                 }
917         } else {
918                 String state = Host::StateToString(Host::CalculateState(static_cast<ServiceState>(state_after)));
919
920                 if (!reachable_after)
921                         state = "UNREACHABLE";
922
923                 msgbuf << "HOST ALERT: "
924                        << host->GetName() << ";"
925                        << state << ";"
926                        << Service::StateTypeToString(static_cast<StateType>(stateType_after)) << ";"
927                        << attempt_after << ";"
928                        << output << ""
929                        << "";
930
931                 switch (host->GetState()) {
932                         case HostUp:
933                                 type = LogEntryTypeHostUp;
934                                 break;
935                         case HostDown:
936                                 type = LogEntryTypeHostDown;
937                                 break;
938                         default:
939                                 Log(LogCritical, "DbEvents")
940                                     << "Unknown host state: " << state_after;
941                                 return;
942                 }
943
944                 if (!reachable_after)
945                         type = LogEntryTypeHostUnreachable;
946         }
947
948         AddLogHistory(checkable, msgbuf.str(), type);
949 }
950
951 void DbEvents::AddTriggerDowntimeLogHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
952 {
953         if (!downtime)
954                 return;
955
956         Host::Ptr host;
957         Service::Ptr service;
958         tie(host, service) = GetHostService(checkable);
959
960         std::ostringstream msgbuf;
961
962         if (service) {
963                 msgbuf << "SERVICE DOWNTIME ALERT: "
964                         << host->GetName() << ";"
965                         << service->GetShortName() << ";"
966                         << "STARTED" << "; "
967                         << "Service has entered a period of scheduled downtime."
968                         << "";
969         } else {
970                 msgbuf << "HOST DOWNTIME ALERT: "
971                         << host->GetName() << ";"
972                         << "STARTED" << "; "
973                         << "Service has entered a period of scheduled downtime."
974                         << "";
975         }
976
977         AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
978 }
979
980 void DbEvents::AddRemoveDowntimeLogHistory(const Checkable::Ptr& checkable, const Downtime::Ptr& downtime)
981 {
982         if (!downtime)
983                 return;
984
985         String downtime_output;
986         String downtime_state_str;
987
988         if (downtime->GetWasCancelled()) {
989                 downtime_output = "Scheduled downtime for service has been cancelled.";
990                 downtime_state_str = "CANCELLED";
991         } else {
992                 downtime_output = "Service has exited from a period of scheduled downtime.";
993                 downtime_state_str = "STOPPED";
994         }
995
996         Host::Ptr host;
997         Service::Ptr service;
998         tie(host, service) = GetHostService(checkable);
999
1000         std::ostringstream msgbuf;
1001
1002         if (service) {
1003                 msgbuf << "SERVICE DOWNTIME ALERT: "
1004                         << host->GetName() << ";"
1005                         << service->GetShortName() << ";"
1006                         << downtime_state_str << "; "
1007                         << downtime_output
1008                         << "";
1009         } else {
1010                 msgbuf << "HOST DOWNTIME ALERT: "
1011                         << host->GetName() << ";"
1012                         << downtime_state_str << "; "
1013                         << downtime_output
1014                         << "";
1015         }
1016
1017         AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
1018 }
1019
1020 void DbEvents::AddNotificationSentLogHistory(const Notification::Ptr& notification, const Checkable::Ptr& checkable, const User::Ptr& user,
1021     NotificationType notification_type, const CheckResult::Ptr& cr,
1022     const String& author, const String& comment_text)
1023 {
1024         CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
1025
1026         String check_command = "";
1027         if (commandObj)
1028                 check_command = commandObj->GetName();
1029
1030         String notification_type_str = Notification::NotificationTypeToString(notification_type);
1031
1032         String author_comment = "";
1033         if (notification_type == NotificationCustom || notification_type == NotificationAcknowledgement) {
1034                 author_comment = ";" + author + ";" + comment_text;
1035         }
1036
1037         if (!cr)
1038                 return;
1039
1040         String output;
1041
1042         if (cr)
1043                 output = CompatUtility::GetCheckResultOutput(cr);
1044
1045         Host::Ptr host;
1046         Service::Ptr service;
1047         tie(host, service) = GetHostService(checkable);
1048
1049         std::ostringstream msgbuf;
1050
1051         if (service) {
1052                 msgbuf << "SERVICE NOTIFICATION: "
1053                        << user->GetName() << ";"
1054                        << host->GetName() << ";"
1055                        << service->GetShortName() << ";"
1056                        << notification_type_str << " "
1057                        << "(" << Service::StateToString(service->GetState()) << ");"
1058                        << check_command << ";"
1059                        << output << author_comment
1060                        << "";
1061         } else {
1062                 msgbuf << "HOST NOTIFICATION: "
1063                        << user->GetName() << ";"
1064                        << host->GetName() << ";"
1065                        << notification_type_str << " "
1066                        << "(" << Host::StateToString(host->GetState()) << ");"
1067                        << check_command << ";"
1068                        << output << author_comment
1069                        << "";
1070         }
1071
1072         AddLogHistory(checkable, msgbuf.str(), LogEntryTypeHostNotification);
1073 }
1074
1075 void DbEvents::AddFlappingLogHistory(const Checkable::Ptr& checkable, FlappingState flapping_state)
1076 {
1077         String flapping_state_str;
1078         String flapping_output;
1079
1080         switch (flapping_state) {
1081                 case FlappingStarted:
1082                         flapping_output = "Service appears to have started flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change >= " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
1083                         flapping_state_str = "STARTED";
1084                         break;
1085                 case FlappingStopped:
1086                         flapping_output = "Service appears to have stopped flapping (" + Convert::ToString(checkable->GetFlappingCurrent()) + "% change < " + Convert::ToString(checkable->GetFlappingThreshold()) + "% threshold)";
1087                         flapping_state_str = "STOPPED";
1088                         break;
1089                 case FlappingDisabled:
1090                         flapping_output = "Flap detection has been disabled";
1091                         flapping_state_str = "DISABLED";
1092                         break;
1093                 default:
1094                         Log(LogCritical, "DbEvents")
1095                             << "Unknown flapping state: " << flapping_state;
1096                         return;
1097         }
1098
1099         Host::Ptr host;
1100         Service::Ptr service;
1101         tie(host, service) = GetHostService(checkable);
1102
1103         std::ostringstream msgbuf;
1104
1105         if (service) {
1106                 msgbuf << "SERVICE FLAPPING ALERT: "
1107                        << host->GetName() << ";"
1108                        << service->GetShortName() << ";"
1109                        << flapping_state_str << "; "
1110                        << flapping_output
1111                        << "";
1112         } else {
1113                 msgbuf << "HOST FLAPPING ALERT: "
1114                        << host->GetName() << ";"
1115                        << flapping_state_str << "; "
1116                        << flapping_output
1117                        << "";
1118         }
1119
1120         AddLogHistory(checkable, msgbuf.str(), LogEntryTypeInfoMessage);
1121 }
1122
1123 void DbEvents::AddLogHistory(const Checkable::Ptr& checkable, String buffer, LogEntryType type)
1124 {
1125         Log(LogDebug, "DbEvents")
1126             << "add log entry history for '" << checkable->GetName() << "'";
1127
1128         double now = Utility::GetTime();
1129         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
1130
1131         DbQuery query1;
1132         query1.Table = "logentries";
1133         query1.Type = DbQueryInsert;
1134         query1.Category = DbCatLog;
1135
1136         Dictionary::Ptr fields1 = make_shared<Dictionary>();
1137         fields1->Set("logentry_time", DbValue::FromTimestamp(time_bag.first));
1138         fields1->Set("entry_time", DbValue::FromTimestamp(time_bag.first));
1139         fields1->Set("entry_time_usec", time_bag.second);
1140         fields1->Set("object_id", checkable); // added in 1.10 see #4754
1141         fields1->Set("logentry_type", type);
1142         fields1->Set("logentry_data", buffer);
1143
1144         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1145
1146         String node = IcingaApplication::GetInstance()->GetNodeName();
1147
1148         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1149         if (endpoint)
1150                 fields1->Set("endpoint_object_id", endpoint);
1151
1152         query1.Fields = fields1;
1153         DbObject::OnQuery(query1);
1154 }
1155
1156 /* flappinghistory */
1157 void DbEvents::AddFlappingHistory(const Checkable::Ptr& checkable, FlappingState flapping_state)
1158 {
1159         Log(LogDebug, "DbEvents")
1160             << "add flapping history for '" << checkable->GetName() << "'";
1161
1162         double now = Utility::GetTime();
1163         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
1164
1165         DbQuery query1;
1166         query1.Table = "flappinghistory";
1167         query1.Type = DbQueryInsert;
1168         query1.Category = DbCatFlapping;
1169
1170         Dictionary::Ptr fields1 = make_shared<Dictionary>();
1171
1172         fields1->Set("event_time", DbValue::FromTimestamp(time_bag.first));
1173         fields1->Set("event_time_usec", time_bag.second);
1174
1175         switch (flapping_state) {
1176                 case FlappingStarted:
1177                         fields1->Set("event_type", 1000);
1178                         break;
1179                 case FlappingStopped:
1180                         fields1->Set("event_type", 1001);
1181                         fields1->Set("reason_type", 1);
1182                         break;
1183                 case FlappingDisabled:
1184                         fields1->Set("event_type", 1001);
1185                         fields1->Set("reason_type", 2);
1186                         break;
1187                 default:
1188                         Log(LogDebug, "DbEvents")
1189                             << "Unhandled flapping state: " << flapping_state;
1190                         return;
1191         }
1192
1193         Host::Ptr host;
1194         Service::Ptr service;
1195         tie(host, service) = GetHostService(checkable);
1196
1197         fields1->Set("flapping_type", service ? 1 : 0);
1198         fields1->Set("object_id", checkable);
1199         fields1->Set("percent_state_change", checkable->GetFlappingCurrent());
1200         fields1->Set("low_threshold", checkable->GetFlappingThreshold());
1201         fields1->Set("high_threshold", checkable->GetFlappingThreshold());
1202
1203         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1204
1205         String node = IcingaApplication::GetInstance()->GetNodeName();
1206
1207         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1208         if (endpoint)
1209                 fields1->Set("endpoint_object_id", endpoint);
1210
1211         query1.Fields = fields1;
1212         DbObject::OnQuery(query1);
1213 }
1214
1215 /* servicechecks */
1216 void DbEvents::AddServiceCheckHistory(const Checkable::Ptr& checkable, const CheckResult::Ptr &cr)
1217 {
1218         if (!cr)
1219                 return;
1220
1221         Log(LogDebug, "DbEvents")
1222             << "add service check history for '" << checkable->GetName() << "'";
1223
1224         Host::Ptr host;
1225         Service::Ptr service;
1226         tie(host, service) = GetHostService(checkable);
1227
1228         std::ostringstream msgbuf;
1229
1230         DbQuery query1;
1231         query1.Table = service ? "servicechecks" : "hostchecks";
1232         query1.Type = DbQueryInsert;
1233         query1.Category = DbCatCheck;
1234
1235         Dictionary::Ptr fields1 = make_shared<Dictionary>();
1236         double execution_time = Service::CalculateExecutionTime(cr);
1237
1238         fields1->Set("check_type", CompatUtility::GetCheckableCheckType(checkable));
1239         fields1->Set("current_check_attempt", checkable->GetCheckAttempt());
1240         fields1->Set("max_check_attempts", checkable->GetMaxCheckAttempts());
1241         fields1->Set("state_type", checkable->GetStateType());
1242
1243         double now = Utility::GetTime();
1244         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
1245
1246         double end = now + execution_time;
1247         std::pair<unsigned long, unsigned long> time_bag_end = CompatUtility::ConvertTimestamp(end);
1248
1249         fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
1250         fields1->Set("start_time_usec", time_bag.second);
1251         fields1->Set("end_time", DbValue::FromTimestamp(time_bag_end.first));
1252         fields1->Set("end_time_usec", time_bag_end.second);
1253         fields1->Set("command_object_id", checkable->GetCheckCommand());
1254         fields1->Set("command_args", Empty);
1255         fields1->Set("command_line", cr->GetCommand());
1256         fields1->Set("execution_time", Convert::ToString(execution_time));
1257         fields1->Set("latency", Convert::ToString(Service::CalculateLatency(cr)));
1258         fields1->Set("return_code", cr->GetExitStatus());
1259         fields1->Set("output", CompatUtility::GetCheckResultOutput(cr));
1260         fields1->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
1261         fields1->Set("perfdata", CompatUtility::GetCheckResultPerfdata(cr));
1262
1263         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1264
1265         if (service) {
1266                 fields1->Set("service_object_id", service);
1267                 fields1->Set("state", service->GetState());
1268         } else {
1269                 fields1->Set("host_object_id", host);
1270                 fields1->Set("state", host->GetState());
1271         }
1272
1273         String node = IcingaApplication::GetInstance()->GetNodeName();
1274
1275         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1276         if (endpoint)
1277                 fields1->Set("endpoint_object_id", endpoint);
1278
1279         query1.Fields = fields1;
1280         DbObject::OnQuery(query1);
1281 }
1282
1283 /* eventhandlers */
1284 void DbEvents::AddEventHandlerHistory(const Checkable::Ptr& checkable)
1285 {
1286         Log(LogDebug, "DbEvents")
1287             << "add eventhandler history for '" << checkable->GetName() << "'";
1288
1289         double now = Utility::GetTime();
1290         std::pair<unsigned long, unsigned long> time_bag = CompatUtility::ConvertTimestamp(now);
1291
1292         DbQuery query1;
1293         query1.Table = "eventhandlers";
1294         query1.Type = DbQueryInsert;
1295         query1.Category = DbCatEventHandler;
1296
1297         Dictionary::Ptr fields1 = make_shared<Dictionary>();
1298
1299         Host::Ptr host;
1300         Service::Ptr service;
1301         tie(host, service) = GetHostService(checkable);
1302
1303         fields1->Set("eventhandler_type", service ? 1 : 0);
1304         fields1->Set("object_id", checkable);
1305         fields1->Set("state", service ? static_cast<int>(service->GetState()) : static_cast<int>(host->GetState()));
1306         fields1->Set("state_type", checkable->GetStateType());
1307
1308         fields1->Set("start_time", DbValue::FromTimestamp(time_bag.first));
1309         fields1->Set("start_time_usec", time_bag.second);
1310         fields1->Set("end_time", DbValue::FromTimestamp(time_bag.first));
1311         fields1->Set("end_time_usec", time_bag.second);
1312         fields1->Set("command_object_id", checkable->GetEventCommand());
1313
1314         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1315
1316         String node = IcingaApplication::GetInstance()->GetNodeName();
1317
1318         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1319         if (endpoint)
1320                 fields1->Set("endpoint_object_id", endpoint);
1321
1322         query1.Fields = fields1;
1323         DbObject::OnQuery(query1);
1324 }
1325
1326 /* externalcommands */
1327 void DbEvents::AddExternalCommandHistory(double time, const String& command, const std::vector<String>& arguments)
1328 {
1329         Log(LogDebug, "DbEvents", "add external command history");
1330
1331         DbQuery query1;
1332         query1.Table = "externalcommands";
1333         query1.Type = DbQueryInsert;
1334         query1.Category = DbCatExternalCommand;
1335
1336         Dictionary::Ptr fields1 = make_shared<Dictionary>();
1337
1338         fields1->Set("entry_time", DbValue::FromTimestamp(static_cast<long>(time)));
1339         fields1->Set("command_type", CompatUtility::MapExternalCommandType(command));
1340         fields1->Set("command_name", command);
1341         fields1->Set("command_args", boost::algorithm::join(arguments, ";"));
1342
1343         fields1->Set("instance_id", 0); /* DbConnection class fills in real ID */
1344
1345         String node = IcingaApplication::GetInstance()->GetNodeName();
1346
1347         Endpoint::Ptr endpoint = Endpoint::GetByName(node);
1348         if (endpoint)
1349                 fields1->Set("endpoint_object_id", endpoint);
1350
1351         query1.Fields = fields1;
1352         DbObject::OnQuery(query1);
1353 }