]> granicus.if.org Git - icinga2/blob - lib/compat/statusdatawriter.cpp
Merge pull request #5906 from sahnd/feature/check_openmanage
[icinga2] / lib / compat / statusdatawriter.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
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 "compat/statusdatawriter.hpp"
21 #include "compat/statusdatawriter.tcpp"
22 #include "icinga/icingaapplication.hpp"
23 #include "icinga/cib.hpp"
24 #include "icinga/hostgroup.hpp"
25 #include "icinga/servicegroup.hpp"
26 #include "icinga/checkcommand.hpp"
27 #include "icinga/eventcommand.hpp"
28 #include "icinga/timeperiod.hpp"
29 #include "icinga/notificationcommand.hpp"
30 #include "icinga/compatutility.hpp"
31 #include "icinga/dependency.hpp"
32 #include "base/configtype.hpp"
33 #include "base/objectlock.hpp"
34 #include "base/json.hpp"
35 #include "base/convert.hpp"
36 #include "base/logger.hpp"
37 #include "base/exception.hpp"
38 #include "base/application.hpp"
39 #include "base/context.hpp"
40 #include "base/statsfunction.hpp"
41 #include <boost/tuple/tuple.hpp>
42 #include <boost/algorithm/string.hpp>
43 #include <boost/algorithm/string/replace.hpp>
44 #include <fstream>
45
46 using namespace icinga;
47
48 REGISTER_TYPE(StatusDataWriter);
49
50 REGISTER_STATSFUNCTION(StatusDataWriter, &StatusDataWriter::StatsFunc);
51
52 void StatusDataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
53 {
54         Dictionary::Ptr nodes = new Dictionary();
55
56         for (const StatusDataWriter::Ptr& statusdatawriter : ConfigType::GetObjectsByType<StatusDataWriter>()) {
57                 nodes->Set(statusdatawriter->GetName(), 1); //add more stats
58         }
59
60         status->Set("statusdatawriter", nodes);
61 }
62
63 /**
64  * Hint: The reason why we're using "\n" rather than std::endl is because
65  * std::endl also _flushes_ the output stream which severely degrades
66  * performance (see https://stackoverflow.com/questions/213907/c-stdendl-vs-n).
67  */
68
69 /**
70  * Starts the component.
71  */
72 void StatusDataWriter::Start(bool runtimeCreated)
73 {
74         ObjectImpl<StatusDataWriter>::Start(runtimeCreated);
75
76         Log(LogInformation, "StatusDataWriter")
77                 << "'" << GetName() << "' started.";
78
79         m_ObjectsCacheOutdated = true;
80
81         m_StatusTimer = new Timer();
82         m_StatusTimer->SetInterval(GetUpdateInterval());
83         m_StatusTimer->OnTimerExpired.connect(std::bind(&StatusDataWriter::StatusTimerHandler, this));
84         m_StatusTimer->Start();
85         m_StatusTimer->Reschedule(0);
86
87         ConfigObject::OnVersionChanged.connect(std::bind(&StatusDataWriter::ObjectHandler, this));
88         ConfigObject::OnActiveChanged.connect(std::bind(&StatusDataWriter::ObjectHandler, this));
89 }
90
91 /**
92  * Stops the component.
93  */
94 void StatusDataWriter::Stop(bool runtimeRemoved)
95 {
96         Log(LogInformation, "StatusDataWriter")
97                 << "'" << GetName() << "' stopped.";
98
99         ObjectImpl<StatusDataWriter>::Stop(runtimeRemoved);
100 }
101
102 void StatusDataWriter::DumpComments(std::ostream& fp, const Checkable::Ptr& checkable)
103 {
104         Host::Ptr host;
105         Service::Ptr service;
106         tie(host, service) = GetHostService(checkable);
107
108         for (const Comment::Ptr& comment : checkable->GetComments()) {
109                 if (comment->IsExpired())
110                         continue;
111
112                 if (service)
113                         fp << "servicecomment {" << "\n"
114                                 << "\t" << "service_description=" << service->GetShortName() << "\n";
115                 else
116                         fp << "hostcomment {" << "\n";
117
118                 fp << "\t" "host_name=" << host->GetName() << "\n"
119                         "\t" "comment_id=" << comment->GetLegacyId() << "\n"
120                         "\t" "entry_time=" << comment->GetEntryTime() << "\n"
121                         "\t" "entry_type=" << comment->GetEntryType() << "\n"
122                         "\t" "persistent=" "1" "\n"
123                         "\t" "author=" << comment->GetAuthor() << "\n"
124                         "\t" "comment_data=" << comment->GetText() << "\n"
125                         "\t" "expires=" << (comment->GetExpireTime() != 0 ? 1 : 0) << "\n"
126                         "\t" "expire_time=" << comment->GetExpireTime() << "\n"
127                         "\t" "}" "\n"
128                         "\n";
129         }
130 }
131
132 void StatusDataWriter::DumpTimePeriod(std::ostream& fp, const TimePeriod::Ptr& tp)
133 {
134         fp << "define timeperiod {" "\n"
135                 "\t" "timeperiod_name" "\t" << tp->GetName() << "\n"
136                 "\t" "alias" "\t" << tp->GetName() << "\n";
137
138         Dictionary::Ptr ranges = tp->GetRanges();
139
140         if (ranges) {
141                 ObjectLock olock(ranges);
142                 for (const Dictionary::Pair& kv : ranges) {
143                         fp << "\t" << kv.first << "\t" << kv.second << "\n";
144                 }
145         }
146
147         fp << "\t" "}" "\n" "\n";
148 }
149
150 void StatusDataWriter::DumpCommand(std::ostream& fp, const Command::Ptr& command)
151 {
152         fp << "define command {" "\n"
153                 "\t" "command_name\t";
154
155         fp << CompatUtility::GetCommandName(command) << "\n";
156
157         fp << "\t" "command_line" "\t" << CompatUtility::GetCommandLine(command);
158
159         fp << "\n";
160
161         DumpCustomAttributes(fp, command);
162
163         fp << "\n" "\t" "}" "\n" "\n";
164 }
165
166 void StatusDataWriter::DumpDowntimes(std::ostream& fp, const Checkable::Ptr& checkable)
167 {
168         Host::Ptr host;
169         Service::Ptr service;
170         tie(host, service) = GetHostService(checkable);
171
172         for (const Downtime::Ptr& downtime : checkable->GetDowntimes()) {
173                 if (downtime->IsExpired())
174                         continue;
175
176                 if (service)
177                         fp << "servicedowntime {" << "\n"
178                                 "\t" "service_description=" << service->GetShortName() << "\n";
179                 else
180                         fp << "hostdowntime {" "\n";
181
182                 Downtime::Ptr triggeredByObj = Downtime::GetByName(downtime->GetTriggeredBy());
183                 int triggeredByLegacy = 0;
184                 if (triggeredByObj)
185                         triggeredByLegacy = triggeredByObj->GetLegacyId();
186
187                 fp << "\t" << "host_name=" << host->GetName() << "\n"
188                         "\t" "downtime_id=" << downtime->GetLegacyId() << "\n"
189                         "\t" "entry_time=" << downtime->GetEntryTime() << "\n"
190                         "\t" "start_time=" << downtime->GetStartTime() << "\n"
191                         "\t" "end_time=" << downtime->GetEndTime() << "\n"
192                         "\t" "triggered_by=" << triggeredByLegacy << "\n"
193                         "\t" "fixed=" << static_cast<long>(downtime->GetFixed()) << "\n"
194                         "\t" "duration=" << static_cast<long>(downtime->GetDuration()) << "\n"
195                         "\t" "is_in_effect=" << (downtime->IsInEffect() ? 1 : 0) << "\n"
196                         "\t" "author=" << downtime->GetAuthor() << "\n"
197                         "\t" "comment=" << downtime->GetComment() << "\n"
198                         "\t" "trigger_time=" << downtime->GetTriggerTime() << "\n"
199                         "\t" "}" "\n"
200                         "\n";
201         }
202 }
203
204 void StatusDataWriter::DumpHostStatus(std::ostream& fp, const Host::Ptr& host)
205 {
206         fp << "hoststatus {" "\n" "\t" "host_name=" << host->GetName() << "\n";
207
208         {
209                 ObjectLock olock(host);
210                 DumpCheckableStatusAttrs(fp, host);
211         }
212
213         /* ugly but cgis parse only that */
214         fp << "\t" "last_time_up=" << host->GetLastStateUp() << "\n"
215                 "\t" "last_time_down=" << host->GetLastStateDown() << "\n"
216                 "\t" "last_time_unreachable=" << host->GetLastStateUnreachable() << "\n";
217
218         fp << "\t" "}" "\n" "\n";
219
220         DumpDowntimes(fp, host);
221         DumpComments(fp, host);
222 }
223
224 void StatusDataWriter::DumpHostObject(std::ostream& fp, const Host::Ptr& host)
225 {
226         String notes = host->GetNotes();
227         String notes_url = host->GetNotesUrl();
228         String action_url = host->GetActionUrl();
229         String icon_image = host->GetIconImage();
230         String icon_image_alt = host->GetIconImageAlt();
231         String display_name = host->GetDisplayName();
232         String address = host->GetAddress();
233         String address6 = host->GetAddress6();
234
235         fp << "define host {" "\n"
236                 "\t" "host_name" "\t" << host->GetName() << "\n";
237         if (!display_name.IsEmpty()) {
238                 fp << "\t" "display_name" "\t" << host->GetDisplayName() << "\n"
239                         "\t" "alias" "\t" << host->GetDisplayName() << "\n";
240         }
241         if (!address.IsEmpty())
242                 fp << "\t" "address" "\t" << address << "\n";
243         if (!address6.IsEmpty())
244                 fp << "\t" "address6" "\t" << address6 << "\n";
245         if (!notes.IsEmpty())
246                 fp << "\t" "notes" "\t" << notes << "\n";
247         if (!notes_url.IsEmpty())
248                 fp << "\t" "notes_url" "\t" << notes_url << "\n";
249         if (!action_url.IsEmpty())
250                 fp << "\t" "action_url" "\t" << action_url << "\n";
251         if (!icon_image.IsEmpty())
252                 fp << "\t" "icon_image" "\t" << icon_image << "\n";
253         if (!icon_image_alt.IsEmpty())
254                 fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n";
255
256         std::set<Checkable::Ptr> parents = host->GetParents();
257
258         if (!parents.empty()) {
259                 fp << "\t" "parents" "\t";
260                 DumpNameList(fp, parents);
261                 fp << "\n";
262         }
263
264         ObjectLock olock(host);
265
266         fp << "\t" "check_interval" "\t" << CompatUtility::GetCheckableCheckInterval(host) << "\n"
267                 "\t" "retry_interval" "\t" << CompatUtility::GetCheckableRetryInterval(host) << "\n"
268                 "\t" "max_check_attempts" "\t" << host->GetMaxCheckAttempts() << "\n"
269                 "\t" "active_checks_enabled" "\t" << CompatUtility::GetCheckableActiveChecksEnabled(host) << "\n"
270                 "\t" "passive_checks_enabled" "\t" << CompatUtility::GetCheckablePassiveChecksEnabled(host) << "\n"
271                 "\t" "notifications_enabled" "\t" << CompatUtility::GetCheckableNotificationsEnabled(host) << "\n"
272                 "\t" "notification_options" "\t" << CompatUtility::GetCheckableNotificationNotificationOptions(host) << "\n"
273                 "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(host) << "\n"
274                 "\t" "event_handler_enabled" "\t" << CompatUtility::GetCheckableEventHandlerEnabled(host) << "\n";
275
276         CheckCommand::Ptr checkcommand = host->GetCheckCommand();
277         if (checkcommand)
278                 fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(host) << "\n";
279
280         EventCommand::Ptr eventcommand = host->GetEventCommand();
281         if (eventcommand && host->GetEnableEventHandler())
282                 fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n";
283
284         fp << "\t" "check_period" "\t" << CompatUtility::GetCheckableCheckPeriod(host) << "\n";
285
286         fp << "\t" "contacts" "\t";
287         DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(host));
288         fp << "\n";
289
290         fp << "\t" "contact_groups" "\t";
291         DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(host));
292         fp << "\n";
293
294         fp << "\t" << "initial_state" "\t" "o" "\n"
295                 "\t" "low_flap_threshold" "\t" << host->GetFlappingThresholdLow() << "\n"
296                 "\t" "high_flap_threshold" "\t" << host->GetFlappingThresholdHigh() << "\n"
297                 "\t" "process_perf_data" "\t" << CompatUtility::GetCheckableProcessPerformanceData(host) << "\n"
298                 "\t" "check_freshness" "\t" "1" "\n";
299
300         fp << "\t" "host_groups" "\t";
301         bool first = true;
302
303         Array::Ptr groups = host->GetGroups();
304
305         if (groups) {
306                 ObjectLock olock(groups);
307
308                 for (const String& name : groups) {
309                         HostGroup::Ptr hg = HostGroup::GetByName(name);
310
311                         if (hg) {
312                                 if (!first)
313                                         fp << ",";
314                                 else
315                                         first = false;
316
317                                 fp << hg->GetName();
318                         }
319                 }
320         }
321
322         fp << "\n";
323
324         DumpCustomAttributes(fp, host);
325
326         fp << "\t" "}" "\n" "\n";
327 }
328
329 void StatusDataWriter::DumpCheckableStatusAttrs(std::ostream& fp, const Checkable::Ptr& checkable)
330 {
331         CheckResult::Ptr cr = checkable->GetLastCheckResult();
332
333         EventCommand::Ptr eventcommand = checkable->GetEventCommand();
334         CheckCommand::Ptr checkcommand = checkable->GetCheckCommand();
335
336         fp << "\t" << "check_command=" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(checkable) << "\n"
337                 "\t" "event_handler=" << CompatUtility::GetCommandName(eventcommand) << "\n"
338                 "\t" "check_period=" << CompatUtility::GetCheckableCheckPeriod(checkable) << "\n"
339                 "\t" "check_interval=" << CompatUtility::GetCheckableCheckInterval(checkable) << "\n"
340                 "\t" "retry_interval=" << CompatUtility::GetCheckableRetryInterval(checkable) << "\n"
341                 "\t" "has_been_checked=" << CompatUtility::GetCheckableHasBeenChecked(checkable) << "\n"
342                 "\t" "should_be_scheduled=" << checkable->GetEnableActiveChecks() << "\n"
343                 "\t" "event_handler_enabled=" << CompatUtility::GetCheckableEventHandlerEnabled(checkable) << "\n";
344
345         if (cr) {
346                 fp << "\t" << "check_execution_time=" << Convert::ToString(cr->CalculateExecutionTime()) << "\n"
347                         "\t" "check_latency=" << Convert::ToString(cr->CalculateLatency()) << "\n";
348         }
349
350         Host::Ptr host;
351         Service::Ptr service;
352         tie(host, service) = GetHostService(checkable);
353
354         if (service) {
355                 fp << "\t" "current_state=" << service->GetState() << "\n"
356                         "\t" "last_hard_state=" << service->GetLastHardState() << "\n"
357                         "\t" "last_time_ok=" << static_cast<int>(service->GetLastStateOK()) << "\n"
358                         "\t" "last_time_warn=" << static_cast<int>(service->GetLastStateWarning()) << "\n"
359                         "\t" "last_time_critical=" << static_cast<int>(service->GetLastStateCritical()) << "\n"
360                         "\t" "last_time_unknown=" << static_cast<int>(service->GetLastStateUnknown()) << "\n";
361         } else {
362                 fp << "\t" "current_state=" << CompatUtility::GetHostCurrentState(host) << "\n"
363                         "\t" "last_hard_state=" << host->GetLastHardState() << "\n"
364                         "\t" "last_time_up=" << static_cast<int>(host->GetLastStateUp()) << "\n"
365                         "\t" "last_time_down=" << static_cast<int>(host->GetLastStateDown()) << "\n";
366         }
367
368         fp << "\t" "state_type=" << checkable->GetStateType() << "\n"
369                 "\t" "plugin_output=" << CompatUtility::GetCheckResultOutput(cr) << "\n"
370                 "\t" "long_plugin_output=" << CompatUtility::GetCheckResultLongOutput(cr) << "\n"
371                 "\t" "performance_data=" << CompatUtility::GetCheckResultPerfdata(cr) << "\n";
372
373         if (cr) {
374                 fp << "\t" << "check_source=" << cr->GetCheckSource() << "\n"
375                 "\t" "last_check=" << static_cast<long>(cr->GetScheduleEnd()) << "\n";
376         }
377
378         fp << "\t" << "next_check=" << static_cast<long>(checkable->GetNextCheck()) << "\n"
379                 "\t" "current_attempt=" << checkable->GetCheckAttempt() << "\n"
380                 "\t" "max_attempts=" << checkable->GetMaxCheckAttempts() << "\n"
381                 "\t" "last_state_change=" << static_cast<long>(checkable->GetLastStateChange()) << "\n"
382                 "\t" "last_hard_state_change=" << static_cast<long>(checkable->GetLastHardStateChange()) << "\n"
383                 "\t" "last_update=" << static_cast<long>(time(nullptr)) << "\n"
384                 "\t" "notifications_enabled=" << CompatUtility::GetCheckableNotificationsEnabled(checkable) << "\n"
385                 "\t" "active_checks_enabled=" << CompatUtility::GetCheckableActiveChecksEnabled(checkable) << "\n"
386                 "\t" "passive_checks_enabled=" << CompatUtility::GetCheckablePassiveChecksEnabled(checkable) << "\n"
387                 "\t" "flap_detection_enabled=" << CompatUtility::GetCheckableFlapDetectionEnabled(checkable) << "\n"
388                 "\t" "is_flapping=" << CompatUtility::GetCheckableIsFlapping(checkable) << "\n"
389                 "\t" "percent_state_change=" << CompatUtility::GetCheckablePercentStateChange(checkable) << "\n"
390                 "\t" "problem_has_been_acknowledged=" << CompatUtility::GetCheckableProblemHasBeenAcknowledged(checkable) << "\n"
391                 "\t" "acknowledgement_type=" << CompatUtility::GetCheckableAcknowledgementType(checkable) << "\n"
392                 "\t" "acknowledgement_end_time=" << checkable->GetAcknowledgementExpiry() << "\n"
393                 "\t" "scheduled_downtime_depth=" << checkable->GetDowntimeDepth() << "\n"
394                 "\t" "last_notification=" << CompatUtility::GetCheckableNotificationLastNotification(checkable) << "\n"
395                 "\t" "next_notification=" << CompatUtility::GetCheckableNotificationNextNotification(checkable) << "\n"
396                 "\t" "current_notification_number=" << CompatUtility::GetCheckableNotificationNotificationNumber(checkable) << "\n"
397                 "\t" "is_reachable=" << CompatUtility::GetCheckableIsReachable(checkable) << "\n";
398 }
399
400 void StatusDataWriter::DumpServiceStatus(std::ostream& fp, const Service::Ptr& service)
401 {
402         Host::Ptr host = service->GetHost();
403
404         fp << "servicestatus {" "\n"
405                 "\t" "host_name=" << host->GetName() << "\n"
406                 "\t" "service_description=" << service->GetShortName() << "\n";
407
408         {
409                 ObjectLock olock(service);
410                 DumpCheckableStatusAttrs(fp, service);
411         }
412
413         fp << "\t" "}" "\n" "\n";
414
415         DumpDowntimes(fp, service);
416         DumpComments(fp, service);
417 }
418
419 void StatusDataWriter::DumpServiceObject(std::ostream& fp, const Service::Ptr& service)
420 {
421         Host::Ptr host = service->GetHost();
422
423         {
424                 ObjectLock olock(service);
425
426                 fp << "define service {" "\n"
427                         "\t" "host_name" "\t" << host->GetName() << "\n"
428                         "\t" "service_description" "\t" << service->GetShortName() << "\n"
429                         "\t" "display_name" "\t" << service->GetDisplayName() << "\n"
430                         "\t" "check_period" "\t" << CompatUtility::GetCheckableCheckPeriod(service) << "\n"
431                         "\t" "check_interval" "\t" << CompatUtility::GetCheckableCheckInterval(service) << "\n"
432                         "\t" "retry_interval" "\t" << CompatUtility::GetCheckableRetryInterval(service) << "\n"
433                         "\t" "max_check_attempts" "\t" << service->GetMaxCheckAttempts() << "\n"
434                         "\t" "active_checks_enabled" "\t" << CompatUtility::GetCheckableActiveChecksEnabled(service) << "\n"
435                         "\t" "passive_checks_enabled" "\t" << CompatUtility::GetCheckablePassiveChecksEnabled(service) << "\n"
436                         "\t" "flap_detection_enabled" "\t" << CompatUtility::GetCheckableFlapDetectionEnabled(service) << "\n"
437                         "\t" "is_volatile" "\t" << CompatUtility::GetCheckableIsVolatile(service) << "\n"
438                         "\t" "notifications_enabled" "\t" << CompatUtility::GetCheckableNotificationsEnabled(service) << "\n"
439                         "\t" "notification_options" "\t" << CompatUtility::GetCheckableNotificationNotificationOptions(service) << "\n"
440                         "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(service) << "\n"
441                         "\t" "notification_period" "\t" << "" << "\n"
442                         "\t" "event_handler_enabled" "\t" << CompatUtility::GetCheckableEventHandlerEnabled(service) << "\n";
443
444                 CheckCommand::Ptr checkcommand = service->GetCheckCommand();
445                 if (checkcommand)
446                         fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(service)<< "\n";
447
448                 EventCommand::Ptr eventcommand = service->GetEventCommand();
449                 if (eventcommand && service->GetEnableEventHandler())
450                         fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n";
451
452                 fp << "\t" "contacts" "\t";
453                 DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(service));
454                 fp << "\n";
455
456                 fp << "\t" "contact_groups" "\t";
457                 DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(service));
458                 fp << "\n";
459
460                 String notes = service->GetNotes();
461                 String notes_url = service->GetNotesUrl();
462                 String action_url = service->GetActionUrl();
463                 String icon_image = service->GetIconImage();
464                 String icon_image_alt = service->GetIconImageAlt();
465
466                 fp << "\t" "initial_state" "\t" "o" "\n"
467                         "\t" "low_flap_threshold" "\t" << service->GetFlappingThresholdLow() << "\n"
468                         "\t" "high_flap_threshold" "\t" << service->GetFlappingThresholdHigh() << "\n"
469                         "\t" "process_perf_data" "\t" << CompatUtility::GetCheckableProcessPerformanceData(service) << "\n"
470                         "\t" "check_freshness" << "\t" "1" "\n";
471                 if (!notes.IsEmpty())
472                         fp << "\t" "notes" "\t" << notes << "\n";
473                 if (!notes_url.IsEmpty())
474                         fp << "\t" "notes_url" "\t" << notes_url << "\n";
475                 if (!action_url.IsEmpty())
476                         fp << "\t" "action_url" "\t" << action_url << "\n";
477                 if (!icon_image.IsEmpty())
478                         fp << "\t" "icon_image" "\t" << icon_image << "\n";
479                 if (!icon_image_alt.IsEmpty())
480                         fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n";
481         }
482
483         fp << "\t" "service_groups" "\t";
484         bool first = true;
485
486         Array::Ptr groups = service->GetGroups();
487
488         if (groups) {
489                 ObjectLock olock(groups);
490
491                 for (const String& name : groups) {
492                         ServiceGroup::Ptr sg = ServiceGroup::GetByName(name);
493
494                         if (sg) {
495                                 if (!first)
496                                         fp << ",";
497                                 else
498                                         first = false;
499
500                                 fp << sg->GetName();
501                         }
502                 }
503         }
504
505         fp << "\n";
506
507         DumpCustomAttributes(fp, service);
508
509         fp << "\t" "}" "\n" "\n";
510 }
511
512 void StatusDataWriter::DumpCustomAttributes(std::ostream& fp, const CustomVarObject::Ptr& object)
513 {
514         Dictionary::Ptr vars = object->GetVars();
515
516         if (!vars)
517                 return;
518
519         bool is_json = false;
520
521         ObjectLock olock(vars);
522         for (const Dictionary::Pair& kv : vars) {
523                 if (kv.first.IsEmpty())
524                         continue;
525
526                 Value value;
527
528                 if (kv.second.IsObjectType<Array>() || kv.second.IsObjectType<Dictionary>()) {
529                         value = JsonEncode(kv.second);
530                         is_json = true;
531                 } else
532                         value = CompatUtility::EscapeString(kv.second);
533
534                 fp << "\t" "_" << kv.first << "\t" << value << "\n";
535         }
536
537         if (is_json)
538                 fp << "\t" "_is_json" "\t" "1" "\n";
539 }
540
541 void StatusDataWriter::UpdateObjectsCache()
542 {
543         CONTEXT("Writing objects.cache file");
544
545         String objectsPath = GetObjectsPath();
546
547         std::fstream objectfp;
548         String tempObjectsPath = Utility::CreateTempFile(objectsPath + ".XXXXXX", 0644, objectfp);
549
550         objectfp << std::fixed;
551
552         objectfp << "# Icinga objects cache file" "\n"
553                         "# This file is auto-generated. Do not modify this file." "\n"
554                         "\n";
555
556         for (const Host::Ptr& host : ConfigType::GetObjectsByType<Host>()) {
557                 std::ostringstream tempobjectfp;
558                 tempobjectfp << std::fixed;
559                 DumpHostObject(tempobjectfp, host);
560                 objectfp << tempobjectfp.str();
561
562                 for (const Service::Ptr& service : host->GetServices()) {
563                         std::ostringstream tempobjectfp;
564                         tempobjectfp << std::fixed;
565                         DumpServiceObject(tempobjectfp, service);
566                         objectfp << tempobjectfp.str();
567                 }
568         }
569
570         for (const HostGroup::Ptr& hg : ConfigType::GetObjectsByType<HostGroup>()) {
571                 std::ostringstream tempobjectfp;
572                 tempobjectfp << std::fixed;
573
574                 String display_name = hg->GetDisplayName();
575                 String notes = hg->GetNotes();
576                 String notes_url = hg->GetNotesUrl();
577                 String action_url = hg->GetActionUrl();
578
579                 tempobjectfp << "define hostgroup {" "\n"
580                                 "\t" "hostgroup_name" "\t" << hg->GetName() << "\n";
581
582                 if (!display_name.IsEmpty())
583                         tempobjectfp << "\t" "alias" "\t" << display_name << "\n";
584                 if (!notes.IsEmpty())
585                         tempobjectfp << "\t" "notes" "\t" << notes << "\n";
586                 if (!notes_url.IsEmpty())
587                         tempobjectfp << "\t" "notes_url" "\t" << notes_url << "\n";
588                 if (!action_url.IsEmpty())
589                         tempobjectfp << "\t" "action_url" "\t" << action_url << "\n";
590
591                 DumpCustomAttributes(tempobjectfp, hg);
592
593                 tempobjectfp << "\t" "members" "\t";
594                 DumpNameList(tempobjectfp, hg->GetMembers());
595                 tempobjectfp << "\n" "\t" "}" "\n";
596
597                 objectfp << tempobjectfp.str();
598         }
599
600         for (const ServiceGroup::Ptr& sg : ConfigType::GetObjectsByType<ServiceGroup>()) {
601                 std::ostringstream tempobjectfp;
602                 tempobjectfp << std::fixed;
603
604                 String display_name = sg->GetDisplayName();
605                 String notes = sg->GetNotes();
606                 String notes_url = sg->GetNotesUrl();
607                 String action_url = sg->GetActionUrl();
608
609                 tempobjectfp << "define servicegroup {" "\n"
610                         "\t" "servicegroup_name" "\t" << sg->GetName() << "\n";
611
612                 if (!display_name.IsEmpty())
613                         tempobjectfp << "\t" "alias" "\t" << display_name << "\n";
614                 if (!notes.IsEmpty())
615                         tempobjectfp << "\t" "notes" "\t" << notes << "\n";
616                 if (!notes_url.IsEmpty())
617                         tempobjectfp << "\t" "notes_url" "\t" << notes_url << "\n";
618                 if (!action_url.IsEmpty())
619                         tempobjectfp << "\t" "action_url" "\t" << action_url << "\n";
620
621                 DumpCustomAttributes(tempobjectfp, sg);
622
623                 tempobjectfp << "\t" "members" "\t";
624
625                 std::vector<String> sglist;
626                 for (const Service::Ptr& service : sg->GetMembers()) {
627                         Host::Ptr host = service->GetHost();
628
629                         sglist.emplace_back(host->GetName());
630                         sglist.emplace_back(service->GetShortName());
631                 }
632
633                 DumpStringList(tempobjectfp, sglist);
634
635                 tempobjectfp << "\n" "}" "\n";
636
637                 objectfp << tempobjectfp.str();
638         }
639
640         for (const User::Ptr& user : ConfigType::GetObjectsByType<User>()) {
641                 std::ostringstream tempobjectfp;
642                 tempobjectfp << std::fixed;
643
644                 String email = user->GetEmail();
645                 String pager = user->GetPager();
646                 String alias = user->GetDisplayName();
647
648                 tempobjectfp << "define contact {" "\n"
649                                 "\t" "contact_name" "\t" << user->GetName() << "\n";
650
651                 if (!alias.IsEmpty())
652                         tempobjectfp << "\t" "alias" "\t" << alias << "\n";
653                 if (!email.IsEmpty())
654                         tempobjectfp << "\t" "email" "\t" << email << "\n";
655                 if (!pager.IsEmpty())
656                         tempobjectfp << "\t" "pager" "\t" << pager << "\n";
657
658                 tempobjectfp << "\t" "service_notification_options" "\t" "w,u,c,r,f,s" "\n"
659                         "\t" "host_notification_options""\t" "d,u,r,f,s" "\n"
660                         "\t" "host_notifications_enabled" "\t" "1" "\n"
661                         "\t" "service_notifications_enabled" "\t" "1" "\n"
662                         "\t" "}" "\n"
663                         "\n";
664
665                 objectfp << tempobjectfp.str();
666         }
667
668         for (const UserGroup::Ptr& ug : ConfigType::GetObjectsByType<UserGroup>()) {
669                 std::ostringstream tempobjectfp;
670                 tempobjectfp << std::fixed;
671
672                 tempobjectfp << "define contactgroup {" "\n"
673                                 "\t" "contactgroup_name" "\t" << ug->GetName() << "\n"
674                                 "\t" "alias" "\t" << ug->GetDisplayName() << "\n";
675
676                 tempobjectfp << "\t" "members" "\t";
677                 DumpNameList(tempobjectfp, ug->GetMembers());
678                 tempobjectfp << "\n"
679                                 "\t" "}" "\n";
680
681                 objectfp << tempobjectfp.str();
682         }
683
684         for (const Command::Ptr& command : ConfigType::GetObjectsByType<CheckCommand>()) {
685                 DumpCommand(objectfp, command);
686         }
687
688         for (const Command::Ptr& command : ConfigType::GetObjectsByType<NotificationCommand>()) {
689                 DumpCommand(objectfp, command);
690         }
691
692         for (const Command::Ptr& command : ConfigType::GetObjectsByType<EventCommand>()) {
693                 DumpCommand(objectfp, command);
694         }
695
696         for (const TimePeriod::Ptr& tp : ConfigType::GetObjectsByType<TimePeriod>()) {
697                 DumpTimePeriod(objectfp, tp);
698         }
699
700         for (const Dependency::Ptr& dep : ConfigType::GetObjectsByType<Dependency>()) {
701                 Checkable::Ptr parent = dep->GetParent();
702
703                 if (!parent) {
704                         Log(LogDebug, "StatusDataWriter")
705                                 << "Missing parent for dependency '" << dep->GetName() << "'.";
706                         continue;
707                 }
708
709                 Host::Ptr parent_host;
710                 Service::Ptr parent_service;
711                 tie(parent_host, parent_service) = GetHostService(parent);
712
713                 Checkable::Ptr child = dep->GetChild();
714
715                 if (!child) {
716                         Log(LogDebug, "StatusDataWriter")
717                                 << "Missing child for dependency '" << dep->GetName() << "'.";
718                         continue;
719                 }
720
721                 Host::Ptr child_host;
722                 Service::Ptr child_service;
723                 tie(child_host, child_service) = GetHostService(child);
724
725                 int state_filter = dep->GetStateFilter();
726                 std::vector<String> failure_criteria;
727                 if (state_filter & StateFilterOK || state_filter & StateFilterUp)
728                         failure_criteria.emplace_back("o");
729                 if (state_filter & StateFilterWarning)
730                         failure_criteria.emplace_back("w");
731                 if (state_filter & StateFilterCritical)
732                         failure_criteria.emplace_back("c");
733                 if (state_filter & StateFilterUnknown)
734                         failure_criteria.emplace_back("u");
735                 if (state_filter & StateFilterDown)
736                         failure_criteria.emplace_back("d");
737
738                 String criteria = boost::algorithm::join(failure_criteria, ",");
739
740                 /* Icinga 1.x only allows host->host, service->service dependencies */
741                 if (!child_service && !parent_service) {
742                         objectfp << "define hostdependency {" "\n"
743                                         "\t" "dependent_host_name" "\t" << child_host->GetName() << "\n"
744                                         "\t" "host_name" "\t" << parent_host->GetName() << "\n"
745                                         "\t" "execution_failure_criteria" "\t" << criteria << "\n"
746                                         "\t" "notification_failure_criteria" "\t" << criteria << "\n"
747                                         "\t" "}" "\n"
748                                         "\n";
749                 } else if (child_service && parent_service){
750
751                         objectfp << "define servicedependency {" "\n"
752                                         "\t" "dependent_host_name" "\t" << child_service->GetHost()->GetName() << "\n"
753                                         "\t" "dependent_service_description" "\t" << child_service->GetShortName() << "\n"
754                                         "\t" "host_name" "\t" << parent_service->GetHost()->GetName() << "\n"
755                                         "\t" "service_description" "\t" << parent_service->GetShortName() << "\n"
756                                         "\t" "execution_failure_criteria" "\t" << criteria << "\n"
757                                         "\t" "notification_failure_criteria" "\t" << criteria << "\n"
758                                         "\t" "}" "\n"
759                                         "\n";
760                 }
761         }
762
763         objectfp.close();
764
765 #ifdef _WIN32
766         _unlink(objectsPath.CStr());
767 #endif /* _WIN32 */
768
769         if (rename(tempObjectsPath.CStr(), objectsPath.CStr()) < 0) {
770                 BOOST_THROW_EXCEPTION(posix_error()
771                         << boost::errinfo_api_function("rename")
772                         << boost::errinfo_errno(errno)
773                         << boost::errinfo_file_name(tempObjectsPath));
774         }
775 }
776
777 /**
778  * Periodically writes the status.dat and objects.cache files.
779  */
780 void StatusDataWriter::StatusTimerHandler()
781 {
782         if (m_ObjectsCacheOutdated) {
783                 UpdateObjectsCache();
784                 m_ObjectsCacheOutdated = false;
785         }
786
787         double start = Utility::GetTime();
788
789         String statusPath = GetStatusPath();
790
791         std::fstream statusfp;
792         String tempStatusPath = Utility::CreateTempFile(statusPath + ".XXXXXX", 0644, statusfp);
793
794         statusfp << std::fixed;
795
796         statusfp << "# Icinga status file" "\n"
797                         "# This file is auto-generated. Do not modify this file." "\n"
798                         "\n";
799
800         statusfp << "info {" "\n"
801                         "\t" "created=" << Utility::GetTime() << "\n"
802                         "\t" "version=" << Application::GetAppVersion() << "\n"
803                         "\t" "}" "\n"
804                         "\n";
805
806         statusfp << "programstatus {" "\n"
807                         "\t" "icinga_pid=" << Utility::GetPid() << "\n"
808                         "\t" "daemon_mode=1" "\n"
809                         "\t" "program_start=" << static_cast<long>(Application::GetStartTime()) << "\n"
810                         "\t" "active_host_checks_enabled=" << (IcingaApplication::GetInstance()->GetEnableHostChecks() ? 1 : 0) << "\n"
811                         "\t" "passive_host_checks_enabled=1" "\n"
812                         "\t" "active_service_checks_enabled=" << (IcingaApplication::GetInstance()->GetEnableServiceChecks() ? 1 : 0) << "\n"
813                         "\t" "passive_service_checks_enabled=1" "\n"
814                         "\t" "check_service_freshness=1" "\n"
815                         "\t" "check_host_freshness=1" "\n"
816                         "\t" "enable_notifications=" << (IcingaApplication::GetInstance()->GetEnableNotifications() ? 1 : 0) << "\n"
817                         "\t" "enable_event_handlers=" << (IcingaApplication::GetInstance()->GetEnableEventHandlers() ? 1 : 0) << "\n"
818                         "\t" "enable_flap_detection=" << (IcingaApplication::GetInstance()->GetEnableFlapping() ? 1 : 0) << "\n"
819                         "\t" "enable_failure_prediction=0" "\n"
820                         "\t" "process_performance_data=" << (IcingaApplication::GetInstance()->GetEnablePerfdata() ? 1 : 0) << "\n"
821                         "\t" "active_scheduled_host_check_stats=" << CIB::GetActiveHostChecksStatistics(60) << "," << CIB::GetActiveHostChecksStatistics(5 * 60) << "," << CIB::GetActiveHostChecksStatistics(15 * 60) << "\n"
822                         "\t" "passive_host_check_stats=" << CIB::GetPassiveHostChecksStatistics(60) << "," << CIB::GetPassiveHostChecksStatistics(5 * 60) << "," << CIB::GetPassiveHostChecksStatistics(15 * 60) << "\n"
823                         "\t" "active_scheduled_service_check_stats=" << CIB::GetActiveServiceChecksStatistics(60) << "," << CIB::GetActiveServiceChecksStatistics(5 * 60) << "," << CIB::GetActiveServiceChecksStatistics(15 * 60) << "\n"
824                         "\t" "passive_service_check_stats=" << CIB::GetPassiveServiceChecksStatistics(60) << "," << CIB::GetPassiveServiceChecksStatistics(5 * 60) << "," << CIB::GetPassiveServiceChecksStatistics(15 * 60) << "\n"
825                         "\t" "next_downtime_id=" << Downtime::GetNextDowntimeID() << "\n"
826                         "\t" "next_comment_id=" << Comment::GetNextCommentID() << "\n";
827
828         statusfp << "\t" "}" "\n"
829                         "\n";
830
831         for (const Host::Ptr& host : ConfigType::GetObjectsByType<Host>()) {
832                 std::ostringstream tempstatusfp;
833                 tempstatusfp << std::fixed;
834                 DumpHostStatus(tempstatusfp, host);
835                 statusfp << tempstatusfp.str();
836
837                 for (const Service::Ptr& service : host->GetServices()) {
838                         std::ostringstream tempstatusfp;
839                         tempstatusfp << std::fixed;
840                         DumpServiceStatus(tempstatusfp, service);
841                         statusfp << tempstatusfp.str();
842                 }
843         }
844
845         statusfp.close();
846
847 #ifdef _WIN32
848         _unlink(statusPath.CStr());
849 #endif /* _WIN32 */
850
851         if (rename(tempStatusPath.CStr(), statusPath.CStr()) < 0) {
852                 BOOST_THROW_EXCEPTION(posix_error()
853                         << boost::errinfo_api_function("rename")
854                         << boost::errinfo_errno(errno)
855                         << boost::errinfo_file_name(tempStatusPath));
856         }
857
858         Log(LogNotice, "StatusDataWriter")
859                 << "Writing status.dat file took " << Utility::FormatDuration(Utility::GetTime() - start);
860 }
861
862 void StatusDataWriter::ObjectHandler()
863 {
864         m_ObjectsCacheOutdated = true;
865 }