1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "compat/statusdatawriter.hpp"
4 #include "compat/statusdatawriter-ti.cpp"
5 #include "icinga/icingaapplication.hpp"
6 #include "icinga/cib.hpp"
7 #include "icinga/hostgroup.hpp"
8 #include "icinga/servicegroup.hpp"
9 #include "icinga/checkcommand.hpp"
10 #include "icinga/eventcommand.hpp"
11 #include "icinga/timeperiod.hpp"
12 #include "icinga/notificationcommand.hpp"
13 #include "icinga/compatutility.hpp"
14 #include "icinga/pluginutility.hpp"
15 #include "icinga/dependency.hpp"
16 #include "base/configtype.hpp"
17 #include "base/objectlock.hpp"
18 #include "base/json.hpp"
19 #include "base/convert.hpp"
20 #include "base/logger.hpp"
21 #include "base/exception.hpp"
22 #include "base/application.hpp"
23 #include "base/context.hpp"
24 #include "base/statsfunction.hpp"
25 #include <boost/algorithm/string.hpp>
26 #include <boost/algorithm/string/replace.hpp>
27 #include <fstream>
28
29 using namespace icinga;
30
31 REGISTER_TYPE(StatusDataWriter);
32
33 REGISTER_STATSFUNCTION(StatusDataWriter, &StatusDataWriter::StatsFunc);
34
StatsFunc(const Dictionary::Ptr & status,const Array::Ptr &)35 void StatusDataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
36 {
37 DictionaryData nodes;
38
39 for (const StatusDataWriter::Ptr& statusdatawriter : ConfigType::GetObjectsByType<StatusDataWriter>()) {
40 nodes.emplace_back(statusdatawriter->GetName(), 1); //add more stats
41 }
42
43 status->Set("statusdatawriter", new Dictionary(std::move(nodes)));
44 }
45
46 /**
47 * Hint: The reason why we're using "\n" rather than std::endl is because
48 * std::endl also _flushes_ the output stream which severely degrades
49 * performance (see https://stackoverflow.com/questions/213907/c-stdendl-vs-n).
50 */
51
52 /**
53 * Starts the component.
54 */
Start(bool runtimeCreated)55 void StatusDataWriter::Start(bool runtimeCreated)
56 {
57 ObjectImpl<StatusDataWriter>::Start(runtimeCreated);
58
59 Log(LogInformation, "StatusDataWriter")
60 << "'" << GetName() << "' started.";
61
62 Log(LogWarning, "StatusDataWriter")
63 << "This feature is DEPRECATED and may be removed in future releases. Check the roadmap at https://github.com/Icinga/icinga2/milestones";
64
65 m_ObjectsCacheOutdated = true;
66
67 m_StatusTimer = new Timer();
68 m_StatusTimer->SetInterval(GetUpdateInterval());
69 m_StatusTimer->OnTimerExpired.connect([this](const Timer * const&){ StatusTimerHandler(); });
70 m_StatusTimer->Start();
71 m_StatusTimer->Reschedule(0);
72
73 ConfigObject::OnVersionChanged.connect([this](const ConfigObject::Ptr&, const Value&) { ObjectHandler(); });
74 ConfigObject::OnActiveChanged.connect([this](const ConfigObject::Ptr&, const Value&) { ObjectHandler(); });
75 }
76
77 /**
78 * Stops the component.
79 */
Stop(bool runtimeRemoved)80 void StatusDataWriter::Stop(bool runtimeRemoved)
81 {
82 Log(LogInformation, "StatusDataWriter")
83 << "'" << GetName() << "' stopped.";
84
85 ObjectImpl<StatusDataWriter>::Stop(runtimeRemoved);
86 }
87
DumpComments(std::ostream & fp,const Checkable::Ptr & checkable)88 void StatusDataWriter::DumpComments(std::ostream& fp, const Checkable::Ptr& checkable)
89 {
90 Host::Ptr host;
91 Service::Ptr service;
92 tie(host, service) = GetHostService(checkable);
93
94 for (const Comment::Ptr& comment : checkable->GetComments()) {
95 if (comment->IsExpired())
96 continue;
97
98 if (service)
99 fp << "servicecomment {" << "\n"
100 << "\t" << "service_description=" << service->GetShortName() << "\n";
101 else
102 fp << "hostcomment {" << "\n";
103
104 fp << "\t" "host_name=" << host->GetName() << "\n"
105 "\t" "comment_id=" << comment->GetLegacyId() << "\n"
106 "\t" "entry_time=" << comment->GetEntryTime() << "\n"
107 "\t" "entry_type=" << comment->GetEntryType() << "\n"
108 "\t" "persistent=" "1" "\n"
109 "\t" "author=" << comment->GetAuthor() << "\n"
110 "\t" "comment_data=" << comment->GetText() << "\n"
111 "\t" "expires=" << (comment->GetExpireTime() != 0 ? 1 : 0) << "\n"
112 "\t" "expire_time=" << comment->GetExpireTime() << "\n"
113 "\t" "}" "\n"
114 "\n";
115 }
116 }
117
DumpTimePeriod(std::ostream & fp,const TimePeriod::Ptr & tp)118 void StatusDataWriter::DumpTimePeriod(std::ostream& fp, const TimePeriod::Ptr& tp)
119 {
120 fp << "define timeperiod {" "\n"
121 "\t" "timeperiod_name" "\t" << tp->GetName() << "\n"
122 "\t" "alias" "\t" << tp->GetName() << "\n";
123
124 Dictionary::Ptr ranges = tp->GetRanges();
125
126 if (ranges) {
127 ObjectLock olock(ranges);
128 for (const Dictionary::Pair& kv : ranges) {
129 fp << "\t" << kv.first << "\t" << kv.second << "\n";
130 }
131 }
132
133 fp << "\t" "}" "\n" "\n";
134 }
135
DumpCommand(std::ostream & fp,const Command::Ptr & command)136 void StatusDataWriter::DumpCommand(std::ostream& fp, const Command::Ptr& command)
137 {
138 fp << "define command {" "\n"
139 "\t" "command_name\t";
140
141 fp << CompatUtility::GetCommandName(command) << "\n";
142
143 fp << "\t" "command_line" "\t" << CompatUtility::GetCommandLine(command);
144
145 fp << "\n";
146
147 DumpCustomAttributes(fp, command);
148
149 fp << "\n" "\t" "}" "\n" "\n";
150 }
151
DumpDowntimes(std::ostream & fp,const Checkable::Ptr & checkable)152 void StatusDataWriter::DumpDowntimes(std::ostream& fp, const Checkable::Ptr& checkable)
153 {
154 Host::Ptr host;
155 Service::Ptr service;
156 tie(host, service) = GetHostService(checkable);
157
158 for (const Downtime::Ptr& downtime : checkable->GetDowntimes()) {
159 if (downtime->IsExpired())
160 continue;
161
162 if (service)
163 fp << "servicedowntime {" << "\n"
164 "\t" "service_description=" << service->GetShortName() << "\n";
165 else
166 fp << "hostdowntime {" "\n";
167
168 Downtime::Ptr triggeredByObj = Downtime::GetByName(downtime->GetTriggeredBy());
169 int triggeredByLegacy = 0;
170 if (triggeredByObj)
171 triggeredByLegacy = triggeredByObj->GetLegacyId();
172
173 fp << "\t" << "host_name=" << host->GetName() << "\n"
174 "\t" "downtime_id=" << downtime->GetLegacyId() << "\n"
175 "\t" "entry_time=" << downtime->GetEntryTime() << "\n"
176 "\t" "start_time=" << downtime->GetStartTime() << "\n"
177 "\t" "end_time=" << downtime->GetEndTime() << "\n"
178 "\t" "triggered_by=" << triggeredByLegacy << "\n"
179 "\t" "fixed=" << static_cast<long>(downtime->GetFixed()) << "\n"
180 "\t" "duration=" << static_cast<long>(downtime->GetDuration()) << "\n"
181 "\t" "is_in_effect=" << (downtime->IsInEffect() ? 1 : 0) << "\n"
182 "\t" "author=" << downtime->GetAuthor() << "\n"
183 "\t" "comment=" << downtime->GetComment() << "\n"
184 "\t" "trigger_time=" << downtime->GetTriggerTime() << "\n"
185 "\t" "}" "\n"
186 "\n";
187 }
188 }
189
DumpHostStatus(std::ostream & fp,const Host::Ptr & host)190 void StatusDataWriter::DumpHostStatus(std::ostream& fp, const Host::Ptr& host)
191 {
192 fp << "hoststatus {" "\n" "\t" "host_name=" << host->GetName() << "\n";
193
194 {
195 ObjectLock olock(host);
196 DumpCheckableStatusAttrs(fp, host);
197 }
198
199 /* ugly but cgis parse only that */
200 fp << "\t" "last_time_up=" << host->GetLastStateUp() << "\n"
201 "\t" "last_time_down=" << host->GetLastStateDown() << "\n"
202 "\t" "last_time_unreachable=" << host->GetLastStateUnreachable() << "\n";
203
204 fp << "\t" "}" "\n" "\n";
205
206 DumpDowntimes(fp, host);
207 DumpComments(fp, host);
208 }
209
DumpHostObject(std::ostream & fp,const Host::Ptr & host)210 void StatusDataWriter::DumpHostObject(std::ostream& fp, const Host::Ptr& host)
211 {
212 String notes = host->GetNotes();
213 String notes_url = host->GetNotesUrl();
214 String action_url = host->GetActionUrl();
215 String icon_image = host->GetIconImage();
216 String icon_image_alt = host->GetIconImageAlt();
217 String display_name = host->GetDisplayName();
218 String address = host->GetAddress();
219 String address6 = host->GetAddress6();
220
221 fp << "define host {" "\n"
222 "\t" "host_name" "\t" << host->GetName() << "\n";
223 if (!display_name.IsEmpty()) {
224 fp << "\t" "display_name" "\t" << host->GetDisplayName() << "\n"
225 "\t" "alias" "\t" << host->GetDisplayName() << "\n";
226 }
227 if (!address.IsEmpty())
228 fp << "\t" "address" "\t" << address << "\n";
229 if (!address6.IsEmpty())
230 fp << "\t" "address6" "\t" << address6 << "\n";
231 if (!notes.IsEmpty())
232 fp << "\t" "notes" "\t" << notes << "\n";
233 if (!notes_url.IsEmpty())
234 fp << "\t" "notes_url" "\t" << notes_url << "\n";
235 if (!action_url.IsEmpty())
236 fp << "\t" "action_url" "\t" << action_url << "\n";
237 if (!icon_image.IsEmpty())
238 fp << "\t" "icon_image" "\t" << icon_image << "\n";
239 if (!icon_image_alt.IsEmpty())
240 fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n";
241
242 std::set<Checkable::Ptr> parents = host->GetParents();
243
244 if (!parents.empty()) {
245 fp << "\t" "parents" "\t";
246 DumpNameList(fp, parents);
247 fp << "\n";
248 }
249
250 ObjectLock olock(host);
251
252 fp << "\t" "check_interval" "\t" << (host->GetCheckInterval() / 60.0) << "\n"
253 "\t" "retry_interval" "\t" << (host->GetRetryInterval() / 60.0) << "\n"
254 "\t" "max_check_attempts" "\t" << host->GetMaxCheckAttempts() << "\n"
255 "\t" "active_checks_enabled" "\t" << Convert::ToLong(host->GetEnableActiveChecks()) << "\n"
256 "\t" "passive_checks_enabled" "\t" << Convert::ToLong(host->GetEnablePassiveChecks()) << "\n"
257 "\t" "notifications_enabled" "\t" << Convert::ToLong(host->GetEnableNotifications()) << "\n"
258 "\t" "notification_options" "\t" << GetNotificationOptions(host) << "\n"
259 "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(host) << "\n"
260 "\t" "event_handler_enabled" "\t" << Convert::ToLong(host->GetEnableEventHandler()) << "\n";
261
262 CheckCommand::Ptr checkcommand = host->GetCheckCommand();
263 if (checkcommand)
264 fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(host) << "\n";
265
266 EventCommand::Ptr eventcommand = host->GetEventCommand();
267 if (eventcommand && host->GetEnableEventHandler())
268 fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n";
269
270 TimePeriod::Ptr checkPeriod = host->GetCheckPeriod();
271 if (checkPeriod)
272 fp << "\t" "check_period" "\t" << checkPeriod->GetName() << "\n";
273
274 fp << "\t" "contacts" "\t";
275 DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(host));
276 fp << "\n";
277
278 fp << "\t" "contact_groups" "\t";
279 DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(host));
280 fp << "\n";
281
282 fp << "\t" << "initial_state" "\t" "o" "\n"
283 "\t" "low_flap_threshold" "\t" << host->GetFlappingThresholdLow() << "\n"
284 "\t" "high_flap_threshold" "\t" << host->GetFlappingThresholdHigh() << "\n"
285 "\t" "process_perf_data" "\t" << Convert::ToLong(host->GetEnablePerfdata()) << "\n"
286 "\t" "check_freshness" "\t" "1" "\n";
287
288 fp << "\t" "host_groups" "\t";
289 bool first = true;
290
291 Array::Ptr groups = host->GetGroups();
292
293 if (groups) {
294 ObjectLock olock(groups);
295
296 for (const String& name : groups) {
297 HostGroup::Ptr hg = HostGroup::GetByName(name);
298
299 if (hg) {
300 if (!first)
301 fp << ",";
302 else
303 first = false;
304
305 fp << hg->GetName();
306 }
307 }
308 }
309
310 fp << "\n";
311
312 DumpCustomAttributes(fp, host);
313
314 fp << "\t" "}" "\n" "\n";
315 }
316
DumpCheckableStatusAttrs(std::ostream & fp,const Checkable::Ptr & checkable)317 void StatusDataWriter::DumpCheckableStatusAttrs(std::ostream& fp, const Checkable::Ptr& checkable)
318 {
319 CheckResult::Ptr cr = checkable->GetLastCheckResult();
320
321 EventCommand::Ptr eventcommand = checkable->GetEventCommand();
322 CheckCommand::Ptr checkcommand = checkable->GetCheckCommand();
323
324 fp << "\t" << "check_command=" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(checkable) << "\n"
325 "\t" "event_handler=" << CompatUtility::GetCommandName(eventcommand) << "\n"
326 "\t" "check_interval=" << (checkable->GetCheckInterval() / 60.0) << "\n"
327 "\t" "retry_interval=" << (checkable->GetRetryInterval() / 60.0) << "\n"
328 "\t" "has_been_checked=" << Convert::ToLong(checkable->HasBeenChecked()) << "\n"
329 "\t" "should_be_scheduled=" << checkable->GetEnableActiveChecks() << "\n"
330 "\t" "event_handler_enabled=" << Convert::ToLong(checkable->GetEnableEventHandler()) << "\n";
331
332 TimePeriod::Ptr checkPeriod = checkable->GetCheckPeriod();
333 if (checkPeriod)
334 fp << "\t" "check_period" "\t" << checkPeriod->GetName() << "\n";
335
336 if (cr) {
337 fp << "\t" << "check_execution_time=" << Convert::ToString(cr->CalculateExecutionTime()) << "\n"
338 "\t" "check_latency=" << Convert::ToString(cr->CalculateLatency()) << "\n";
339 }
340
341 Host::Ptr host;
342 Service::Ptr service;
343 tie(host, service) = GetHostService(checkable);
344
345 if (service) {
346 fp << "\t" "current_state=" << service->GetState() << "\n"
347 "\t" "last_hard_state=" << service->GetLastHardState() << "\n"
348 "\t" "last_time_ok=" << static_cast<int>(service->GetLastStateOK()) << "\n"
349 "\t" "last_time_warn=" << static_cast<int>(service->GetLastStateWarning()) << "\n"
350 "\t" "last_time_critical=" << static_cast<int>(service->GetLastStateCritical()) << "\n"
351 "\t" "last_time_unknown=" << static_cast<int>(service->GetLastStateUnknown()) << "\n";
352 } else {
353 int currentState = host->GetState();
354
355 if (currentState != HostUp && !host->IsReachable())
356 currentState = 2; /* hardcoded compat state */
357
358 fp << "\t" "current_state=" << currentState << "\n"
359 "\t" "last_hard_state=" << host->GetLastHardState() << "\n"
360 "\t" "last_time_up=" << static_cast<int>(host->GetLastStateUp()) << "\n"
361 "\t" "last_time_down=" << static_cast<int>(host->GetLastStateDown()) << "\n";
362 }
363
364 fp << "\t" "state_type=" << checkable->GetStateType() << "\n"
365 "\t" "last_check=" << static_cast<long>(host->GetLastCheck()) << "\n";
366
367 if (cr) {
368 fp << "\t" "plugin_output=" << CompatUtility::GetCheckResultOutput(cr) << "\n"
369 "\t" "long_plugin_output=" << CompatUtility::GetCheckResultLongOutput(cr) << "\n"
370 "\t" "performance_data=" << PluginUtility::FormatPerfdata(cr->GetPerformanceData()) << "\n";
371 }
372
373 fp << "\t" << "next_check=" << static_cast<long>(checkable->GetNextCheck()) << "\n"
374 "\t" "current_attempt=" << checkable->GetCheckAttempt() << "\n"
375 "\t" "max_attempts=" << checkable->GetMaxCheckAttempts() << "\n"
376 "\t" "last_state_change=" << static_cast<long>(checkable->GetLastStateChange()) << "\n"
377 "\t" "last_hard_state_change=" << static_cast<long>(checkable->GetLastHardStateChange()) << "\n"
378 "\t" "last_update=" << static_cast<long>(Utility::GetTime()) << "\n"
379 "\t" "notifications_enabled=" << Convert::ToLong(checkable->GetEnableNotifications()) << "\n"
380 "\t" "active_checks_enabled=" << Convert::ToLong(checkable->GetEnableActiveChecks()) << "\n"
381 "\t" "passive_checks_enabled=" << Convert::ToLong(checkable->GetEnablePassiveChecks()) << "\n"
382 "\t" "flap_detection_enabled=" << Convert::ToLong(checkable->GetEnableFlapping()) << "\n"
383 "\t" "is_flapping=" << Convert::ToLong(checkable->IsFlapping()) << "\n"
384 "\t" "percent_state_change=" << checkable->GetFlappingCurrent() << "\n"
385 "\t" "problem_has_been_acknowledged=" << (checkable->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
386 "\t" "acknowledgement_type=" << checkable->GetAcknowledgement() << "\n"
387 "\t" "acknowledgement_end_time=" << checkable->GetAcknowledgementExpiry() << "\n"
388 "\t" "scheduled_downtime_depth=" << checkable->GetDowntimeDepth() << "\n"
389 "\t" "last_notification=" << CompatUtility::GetCheckableNotificationLastNotification(checkable) << "\n"
390 "\t" "next_notification=" << CompatUtility::GetCheckableNotificationNextNotification(checkable) << "\n"
391 "\t" "current_notification_number=" << CompatUtility::GetCheckableNotificationNotificationNumber(checkable) << "\n"
392 "\t" "is_reachable=" << Convert::ToLong(checkable->IsReachable()) << "\n";
393 }
394
DumpServiceStatus(std::ostream & fp,const Service::Ptr & service)395 void StatusDataWriter::DumpServiceStatus(std::ostream& fp, const Service::Ptr& service)
396 {
397 Host::Ptr host = service->GetHost();
398
399 fp << "servicestatus {" "\n"
400 "\t" "host_name=" << host->GetName() << "\n"
401 "\t" "service_description=" << service->GetShortName() << "\n";
402
403 {
404 ObjectLock olock(service);
405 DumpCheckableStatusAttrs(fp, service);
406 }
407
408 fp << "\t" "}" "\n" "\n";
409
410 DumpDowntimes(fp, service);
411 DumpComments(fp, service);
412 }
413
DumpServiceObject(std::ostream & fp,const Service::Ptr & service)414 void StatusDataWriter::DumpServiceObject(std::ostream& fp, const Service::Ptr& service)
415 {
416 Host::Ptr host = service->GetHost();
417
418 {
419 ObjectLock olock(service);
420
421 fp << "define service {" "\n"
422 "\t" "host_name" "\t" << host->GetName() << "\n"
423 "\t" "service_description" "\t" << service->GetShortName() << "\n"
424 "\t" "display_name" "\t" << service->GetDisplayName() << "\n"
425 "\t" "check_interval" "\t" << (service->GetCheckInterval() / 60.0) << "\n"
426 "\t" "retry_interval" "\t" << (service->GetRetryInterval() / 60.0) << "\n"
427 "\t" "max_check_attempts" "\t" << service->GetMaxCheckAttempts() << "\n"
428 "\t" "active_checks_enabled" "\t" << Convert::ToLong(service->GetEnableActiveChecks()) << "\n"
429 "\t" "passive_checks_enabled" "\t" << Convert::ToLong(service->GetEnablePassiveChecks()) << "\n"
430 "\t" "flap_detection_enabled" "\t" << Convert::ToLong(service->GetEnableFlapping()) << "\n"
431 "\t" "is_volatile" "\t" << Convert::ToLong(service->GetVolatile()) << "\n"
432 "\t" "notifications_enabled" "\t" << Convert::ToLong(service->GetEnableNotifications()) << "\n"
433 "\t" "notification_options" "\t" << GetNotificationOptions(service) << "\n"
434 "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(service) << "\n"
435 "\t" "notification_period" "\t" << "" << "\n"
436 "\t" "event_handler_enabled" "\t" << Convert::ToLong(service->GetEnableEventHandler()) << "\n";
437
438 CheckCommand::Ptr checkcommand = service->GetCheckCommand();
439 if (checkcommand)
440 fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(service)<< "\n";
441
442 EventCommand::Ptr eventcommand = service->GetEventCommand();
443 if (eventcommand && service->GetEnableEventHandler())
444 fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n";
445
446 TimePeriod::Ptr checkPeriod = service->GetCheckPeriod();
447 if (checkPeriod)
448 fp << "\t" "check_period" "\t" << checkPeriod->GetName() << "\n";
449
450 fp << "\t" "contacts" "\t";
451 DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(service));
452 fp << "\n";
453
454 fp << "\t" "contact_groups" "\t";
455 DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(service));
456 fp << "\n";
457
458 String notes = service->GetNotes();
459 String notes_url = service->GetNotesUrl();
460 String action_url = service->GetActionUrl();
461 String icon_image = service->GetIconImage();
462 String icon_image_alt = service->GetIconImageAlt();
463
464 fp << "\t" "initial_state" "\t" "o" "\n"
465 "\t" "low_flap_threshold" "\t" << service->GetFlappingThresholdLow() << "\n"
466 "\t" "high_flap_threshold" "\t" << service->GetFlappingThresholdHigh() << "\n"
467 "\t" "process_perf_data" "\t" << Convert::ToLong(service->GetEnablePerfdata()) << "\n"
468 "\t" "check_freshness" << "\t" "1" "\n";
469
470 if (!notes.IsEmpty())
471 fp << "\t" "notes" "\t" << notes << "\n";
472 if (!notes_url.IsEmpty())
473 fp << "\t" "notes_url" "\t" << notes_url << "\n";
474 if (!action_url.IsEmpty())
475 fp << "\t" "action_url" "\t" << action_url << "\n";
476 if (!icon_image.IsEmpty())
477 fp << "\t" "icon_image" "\t" << icon_image << "\n";
478 if (!icon_image_alt.IsEmpty())
479 fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n";
480 }
481
482 fp << "\t" "service_groups" "\t";
483 bool first = true;
484
485 Array::Ptr groups = service->GetGroups();
486
487 if (groups) {
488 ObjectLock olock(groups);
489
490 for (const String& name : groups) {
491 ServiceGroup::Ptr sg = ServiceGroup::GetByName(name);
492
493 if (sg) {
494 if (!first)
495 fp << ",";
496 else
497 first = false;
498
499 fp << sg->GetName();
500 }
501 }
502 }
503
504 fp << "\n";
505
506 DumpCustomAttributes(fp, service);
507
508 fp << "\t" "}" "\n" "\n";
509 }
510
DumpCustomAttributes(std::ostream & fp,const CustomVarObject::Ptr & object)511 void StatusDataWriter::DumpCustomAttributes(std::ostream& fp, const CustomVarObject::Ptr& object)
512 {
513 Dictionary::Ptr vars = object->GetVars();
514
515 if (!vars)
516 return;
517
518 bool is_json = false;
519
520 ObjectLock olock(vars);
521 for (const Dictionary::Pair& kv : vars) {
522 if (kv.first.IsEmpty())
523 continue;
524
525 Value value;
526
527 if (kv.second.IsObjectType<Array>() || kv.second.IsObjectType<Dictionary>()) {
528 value = JsonEncode(kv.second);
529 is_json = true;
530 } else
531 value = CompatUtility::EscapeString(kv.second);
532
533 fp << "\t" "_" << kv.first << "\t" << value << "\n";
534 }
535
536 if (is_json)
537 fp << "\t" "_is_json" "\t" "1" "\n";
538 }
539
UpdateObjectsCache()540 void StatusDataWriter::UpdateObjectsCache()
541 {
542 CONTEXT("Writing objects.cache file");
543
544 /* Use the compat path here from the .ti generated class. */
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 Utility::RenameFile(tempObjectsPath, objectsPath);
766 }
767
768 /**
769 * Periodically writes the status.dat and objects.cache files.
770 */
StatusTimerHandler()771 void StatusDataWriter::StatusTimerHandler()
772 {
773 if (m_ObjectsCacheOutdated) {
774 UpdateObjectsCache();
775 m_ObjectsCacheOutdated = false;
776 }
777
778 double start = Utility::GetTime();
779
780 String statusPath = GetStatusPath();
781
782 std::fstream statusfp;
783 String tempStatusPath = Utility::CreateTempFile(statusPath + ".XXXXXX", 0644, statusfp);
784
785 statusfp << std::fixed;
786
787 statusfp << "# Icinga status file" "\n"
788 "# This file is auto-generated. Do not modify this file." "\n"
789 "\n";
790
791 statusfp << "info {" "\n"
792 "\t" "created=" << Utility::GetTime() << "\n"
793 "\t" "version=" << Application::GetAppVersion() << "\n"
794 "\t" "}" "\n"
795 "\n";
796
797 statusfp << "programstatus {" "\n"
798 "\t" "icinga_pid=" << Utility::GetPid() << "\n"
799 "\t" "daemon_mode=1" "\n"
800 "\t" "program_start=" << static_cast<long>(Application::GetStartTime()) << "\n"
801 "\t" "active_host_checks_enabled=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableHostChecks()) << "\n"
802 "\t" "passive_host_checks_enabled=1" "\n"
803 "\t" "active_service_checks_enabled=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableServiceChecks()) << "\n"
804 "\t" "passive_service_checks_enabled=1" "\n"
805 "\t" "check_service_freshness=1" "\n"
806 "\t" "check_host_freshness=1" "\n"
807 "\t" "enable_notifications=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableNotifications()) << "\n"
808 "\t" "enable_event_handlers=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableEventHandlers()) << "\n"
809 "\t" "enable_flap_detection=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableFlapping()) << "\n"
810 "\t" "enable_failure_prediction=0" "\n"
811 "\t" "process_performance_data=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnablePerfdata()) << "\n"
812 "\t" "active_scheduled_host_check_stats=" << CIB::GetActiveHostChecksStatistics(60) << "," << CIB::GetActiveHostChecksStatistics(5 * 60) << "," << CIB::GetActiveHostChecksStatistics(15 * 60) << "\n"
813 "\t" "passive_host_check_stats=" << CIB::GetPassiveHostChecksStatistics(60) << "," << CIB::GetPassiveHostChecksStatistics(5 * 60) << "," << CIB::GetPassiveHostChecksStatistics(15 * 60) << "\n"
814 "\t" "active_scheduled_service_check_stats=" << CIB::GetActiveServiceChecksStatistics(60) << "," << CIB::GetActiveServiceChecksStatistics(5 * 60) << "," << CIB::GetActiveServiceChecksStatistics(15 * 60) << "\n"
815 "\t" "passive_service_check_stats=" << CIB::GetPassiveServiceChecksStatistics(60) << "," << CIB::GetPassiveServiceChecksStatistics(5 * 60) << "," << CIB::GetPassiveServiceChecksStatistics(15 * 60) << "\n"
816 "\t" "next_downtime_id=" << Downtime::GetNextDowntimeID() << "\n"
817 "\t" "next_comment_id=" << Comment::GetNextCommentID() << "\n";
818
819 statusfp << "\t" "}" "\n"
820 "\n";
821
822 for (const Host::Ptr& host : ConfigType::GetObjectsByType<Host>()) {
823 std::ostringstream tempstatusfp;
824 tempstatusfp << std::fixed;
825 DumpHostStatus(tempstatusfp, host);
826 statusfp << tempstatusfp.str();
827
828 for (const Service::Ptr& service : host->GetServices()) {
829 std::ostringstream tempstatusfp;
830 tempstatusfp << std::fixed;
831 DumpServiceStatus(tempstatusfp, service);
832 statusfp << tempstatusfp.str();
833 }
834 }
835
836 statusfp.close();
837
838 Utility::RenameFile(tempStatusPath, statusPath);
839
840 Log(LogNotice, "StatusDataWriter")
841 << "Writing status.dat file took " << Utility::FormatDuration(Utility::GetTime() - start);
842 }
843
ObjectHandler()844 void StatusDataWriter::ObjectHandler()
845 {
846 m_ObjectsCacheOutdated = true;
847 }
848
GetNotificationOptions(const Checkable::Ptr & checkable)849 String StatusDataWriter::GetNotificationOptions(const Checkable::Ptr& checkable)
850 {
851 Host::Ptr host;
852 Service::Ptr service;
853 tie(host, service) = GetHostService(checkable);
854
855 unsigned long notification_type_filter = 0;
856 unsigned long notification_state_filter = 0;
857
858 for (const Notification::Ptr& notification : checkable->GetNotifications()) {
859 notification_type_filter |= notification->GetTypeFilter();
860 notification_state_filter |= notification->GetStateFilter();
861 }
862
863 std::vector<String> notification_options;
864
865 /* notification state filters */
866 if (service) {
867 if (notification_state_filter & ServiceWarning) {
868 notification_options.push_back("w");
869 }
870 if (notification_state_filter & ServiceUnknown) {
871 notification_options.push_back("u");
872 }
873 if (notification_state_filter & ServiceCritical) {
874 notification_options.push_back("c");
875 }
876 } else {
877 if (notification_state_filter & HostDown) {
878 notification_options.push_back("d");
879 }
880 }
881
882 /* notification type filters */
883 if (notification_type_filter & NotificationRecovery) {
884 notification_options.push_back("r");
885 }
886 if ((notification_type_filter & NotificationFlappingStart) ||
887 (notification_type_filter & NotificationFlappingEnd)) {
888 notification_options.push_back("f");
889 }
890 if ((notification_type_filter & NotificationDowntimeStart) ||
891 (notification_type_filter & NotificationDowntimeEnd) ||
892 (notification_type_filter & NotificationDowntimeRemoved)) {
893 notification_options.push_back("s");
894 }
895
896 return boost::algorithm::join(notification_options, ",");
897 }
898