1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
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. *
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. *
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 ******************************************************************************/
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/pluginutility.hpp"
32 #include "icinga/dependency.hpp"
33 #include "base/configtype.hpp"
34 #include "base/objectlock.hpp"
35 #include "base/json.hpp"
36 #include "base/convert.hpp"
37 #include "base/logger.hpp"
38 #include "base/exception.hpp"
39 #include "base/application.hpp"
40 #include "base/context.hpp"
41 #include "base/statsfunction.hpp"
42 #include <boost/tuple/tuple.hpp>
43 #include <boost/algorithm/string.hpp>
44 #include <boost/algorithm/string/replace.hpp>
47 using namespace icinga;
49 REGISTER_TYPE(StatusDataWriter);
51 REGISTER_STATSFUNCTION(StatusDataWriter, &StatusDataWriter::StatsFunc);
53 void StatusDataWriter::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
57 for (const StatusDataWriter::Ptr& statusdatawriter : ConfigType::GetObjectsByType<StatusDataWriter>()) {
58 nodes.emplace_back(statusdatawriter->GetName(), 1); //add more stats
61 status->Set("statusdatawriter", new Dictionary(std::move(nodes)));
65 * Hint: The reason why we're using "\n" rather than std::endl is because
66 * std::endl also _flushes_ the output stream which severely degrades
67 * performance (see https://stackoverflow.com/questions/213907/c-stdendl-vs-n).
71 * Starts the component.
73 void StatusDataWriter::Start(bool runtimeCreated)
75 ObjectImpl<StatusDataWriter>::Start(runtimeCreated);
77 Log(LogInformation, "StatusDataWriter")
78 << "'" << GetName() << "' started.";
80 m_ObjectsCacheOutdated = true;
82 m_StatusTimer = new Timer();
83 m_StatusTimer->SetInterval(GetUpdateInterval());
84 m_StatusTimer->OnTimerExpired.connect(std::bind(&StatusDataWriter::StatusTimerHandler, this));
85 m_StatusTimer->Start();
86 m_StatusTimer->Reschedule(0);
88 ConfigObject::OnVersionChanged.connect(std::bind(&StatusDataWriter::ObjectHandler, this));
89 ConfigObject::OnActiveChanged.connect(std::bind(&StatusDataWriter::ObjectHandler, this));
93 * Stops the component.
95 void StatusDataWriter::Stop(bool runtimeRemoved)
97 Log(LogInformation, "StatusDataWriter")
98 << "'" << GetName() << "' stopped.";
100 ObjectImpl<StatusDataWriter>::Stop(runtimeRemoved);
103 void StatusDataWriter::DumpComments(std::ostream& fp, const Checkable::Ptr& checkable)
106 Service::Ptr service;
107 tie(host, service) = GetHostService(checkable);
109 for (const Comment::Ptr& comment : checkable->GetComments()) {
110 if (comment->IsExpired())
114 fp << "servicecomment {" << "\n"
115 << "\t" << "service_description=" << service->GetShortName() << "\n";
117 fp << "hostcomment {" << "\n";
119 fp << "\t" "host_name=" << host->GetName() << "\n"
120 "\t" "comment_id=" << comment->GetLegacyId() << "\n"
121 "\t" "entry_time=" << comment->GetEntryTime() << "\n"
122 "\t" "entry_type=" << comment->GetEntryType() << "\n"
123 "\t" "persistent=" "1" "\n"
124 "\t" "author=" << comment->GetAuthor() << "\n"
125 "\t" "comment_data=" << comment->GetText() << "\n"
126 "\t" "expires=" << (comment->GetExpireTime() != 0 ? 1 : 0) << "\n"
127 "\t" "expire_time=" << comment->GetExpireTime() << "\n"
133 void StatusDataWriter::DumpTimePeriod(std::ostream& fp, const TimePeriod::Ptr& tp)
135 fp << "define timeperiod {" "\n"
136 "\t" "timeperiod_name" "\t" << tp->GetName() << "\n"
137 "\t" "alias" "\t" << tp->GetName() << "\n";
139 Dictionary::Ptr ranges = tp->GetRanges();
142 ObjectLock olock(ranges);
143 for (const Dictionary::Pair& kv : ranges) {
144 fp << "\t" << kv.first << "\t" << kv.second << "\n";
148 fp << "\t" "}" "\n" "\n";
151 void StatusDataWriter::DumpCommand(std::ostream& fp, const Command::Ptr& command)
153 fp << "define command {" "\n"
154 "\t" "command_name\t";
156 fp << CompatUtility::GetCommandName(command) << "\n";
158 fp << "\t" "command_line" "\t" << CompatUtility::GetCommandLine(command);
162 DumpCustomAttributes(fp, command);
164 fp << "\n" "\t" "}" "\n" "\n";
167 void StatusDataWriter::DumpDowntimes(std::ostream& fp, const Checkable::Ptr& checkable)
170 Service::Ptr service;
171 tie(host, service) = GetHostService(checkable);
173 for (const Downtime::Ptr& downtime : checkable->GetDowntimes()) {
174 if (downtime->IsExpired())
178 fp << "servicedowntime {" << "\n"
179 "\t" "service_description=" << service->GetShortName() << "\n";
181 fp << "hostdowntime {" "\n";
183 Downtime::Ptr triggeredByObj = Downtime::GetByName(downtime->GetTriggeredBy());
184 int triggeredByLegacy = 0;
186 triggeredByLegacy = triggeredByObj->GetLegacyId();
188 fp << "\t" << "host_name=" << host->GetName() << "\n"
189 "\t" "downtime_id=" << downtime->GetLegacyId() << "\n"
190 "\t" "entry_time=" << downtime->GetEntryTime() << "\n"
191 "\t" "start_time=" << downtime->GetStartTime() << "\n"
192 "\t" "end_time=" << downtime->GetEndTime() << "\n"
193 "\t" "triggered_by=" << triggeredByLegacy << "\n"
194 "\t" "fixed=" << static_cast<long>(downtime->GetFixed()) << "\n"
195 "\t" "duration=" << static_cast<long>(downtime->GetDuration()) << "\n"
196 "\t" "is_in_effect=" << (downtime->IsInEffect() ? 1 : 0) << "\n"
197 "\t" "author=" << downtime->GetAuthor() << "\n"
198 "\t" "comment=" << downtime->GetComment() << "\n"
199 "\t" "trigger_time=" << downtime->GetTriggerTime() << "\n"
205 void StatusDataWriter::DumpHostStatus(std::ostream& fp, const Host::Ptr& host)
207 fp << "hoststatus {" "\n" "\t" "host_name=" << host->GetName() << "\n";
210 ObjectLock olock(host);
211 DumpCheckableStatusAttrs(fp, host);
214 /* ugly but cgis parse only that */
215 fp << "\t" "last_time_up=" << host->GetLastStateUp() << "\n"
216 "\t" "last_time_down=" << host->GetLastStateDown() << "\n"
217 "\t" "last_time_unreachable=" << host->GetLastStateUnreachable() << "\n";
219 fp << "\t" "}" "\n" "\n";
221 DumpDowntimes(fp, host);
222 DumpComments(fp, host);
225 void StatusDataWriter::DumpHostObject(std::ostream& fp, const Host::Ptr& host)
227 String notes = host->GetNotes();
228 String notes_url = host->GetNotesUrl();
229 String action_url = host->GetActionUrl();
230 String icon_image = host->GetIconImage();
231 String icon_image_alt = host->GetIconImageAlt();
232 String display_name = host->GetDisplayName();
233 String address = host->GetAddress();
234 String address6 = host->GetAddress6();
236 fp << "define host {" "\n"
237 "\t" "host_name" "\t" << host->GetName() << "\n";
238 if (!display_name.IsEmpty()) {
239 fp << "\t" "display_name" "\t" << host->GetDisplayName() << "\n"
240 "\t" "alias" "\t" << host->GetDisplayName() << "\n";
242 if (!address.IsEmpty())
243 fp << "\t" "address" "\t" << address << "\n";
244 if (!address6.IsEmpty())
245 fp << "\t" "address6" "\t" << address6 << "\n";
246 if (!notes.IsEmpty())
247 fp << "\t" "notes" "\t" << notes << "\n";
248 if (!notes_url.IsEmpty())
249 fp << "\t" "notes_url" "\t" << notes_url << "\n";
250 if (!action_url.IsEmpty())
251 fp << "\t" "action_url" "\t" << action_url << "\n";
252 if (!icon_image.IsEmpty())
253 fp << "\t" "icon_image" "\t" << icon_image << "\n";
254 if (!icon_image_alt.IsEmpty())
255 fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n";
257 std::set<Checkable::Ptr> parents = host->GetParents();
259 if (!parents.empty()) {
260 fp << "\t" "parents" "\t";
261 DumpNameList(fp, parents);
265 ObjectLock olock(host);
267 fp << "\t" "check_interval" "\t" << (host->GetCheckInterval() / 60.0) << "\n"
268 "\t" "retry_interval" "\t" << (host->GetRetryInterval() / 60.0) << "\n"
269 "\t" "max_check_attempts" "\t" << host->GetMaxCheckAttempts() << "\n"
270 "\t" "active_checks_enabled" "\t" << Convert::ToLong(host->GetEnableActiveChecks()) << "\n"
271 "\t" "passive_checks_enabled" "\t" << Convert::ToLong(host->GetEnablePassiveChecks()) << "\n"
272 "\t" "notifications_enabled" "\t" << Convert::ToLong(host->GetEnableNotifications()) << "\n"
273 "\t" "notification_options" "\t" << GetNotificationOptions(host) << "\n"
274 "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(host) << "\n"
275 "\t" "event_handler_enabled" "\t" << Convert::ToLong(host->GetEnableEventHandler()) << "\n";
277 CheckCommand::Ptr checkcommand = host->GetCheckCommand();
279 fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(host) << "\n";
281 EventCommand::Ptr eventcommand = host->GetEventCommand();
282 if (eventcommand && host->GetEnableEventHandler())
283 fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n";
285 TimePeriod::Ptr checkPeriod = host->GetCheckPeriod();
287 fp << "\t" "check_period" "\t" << checkPeriod->GetName() << "\n";
289 fp << "\t" "contacts" "\t";
290 DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(host));
293 fp << "\t" "contact_groups" "\t";
294 DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(host));
297 fp << "\t" << "initial_state" "\t" "o" "\n"
298 "\t" "low_flap_threshold" "\t" << host->GetFlappingThresholdLow() << "\n"
299 "\t" "high_flap_threshold" "\t" << host->GetFlappingThresholdHigh() << "\n"
300 "\t" "process_perf_data" "\t" << Convert::ToLong(host->GetEnablePerfdata()) << "\n"
301 "\t" "check_freshness" "\t" "1" "\n";
303 fp << "\t" "host_groups" "\t";
306 Array::Ptr groups = host->GetGroups();
309 ObjectLock olock(groups);
311 for (const String& name : groups) {
312 HostGroup::Ptr hg = HostGroup::GetByName(name);
327 DumpCustomAttributes(fp, host);
329 fp << "\t" "}" "\n" "\n";
332 void StatusDataWriter::DumpCheckableStatusAttrs(std::ostream& fp, const Checkable::Ptr& checkable)
334 CheckResult::Ptr cr = checkable->GetLastCheckResult();
336 EventCommand::Ptr eventcommand = checkable->GetEventCommand();
337 CheckCommand::Ptr checkcommand = checkable->GetCheckCommand();
339 fp << "\t" << "check_command=" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(checkable) << "\n"
340 "\t" "event_handler=" << CompatUtility::GetCommandName(eventcommand) << "\n"
341 "\t" "check_interval=" << (checkable->GetCheckInterval() / 60.0) << "\n"
342 "\t" "retry_interval=" << (checkable->GetRetryInterval() / 60.0) << "\n"
343 "\t" "has_been_checked=" << Convert::ToLong(checkable->HasBeenChecked()) << "\n"
344 "\t" "should_be_scheduled=" << checkable->GetEnableActiveChecks() << "\n"
345 "\t" "event_handler_enabled=" << Convert::ToLong(checkable->GetEnableEventHandler()) << "\n";
347 TimePeriod::Ptr checkPeriod = checkable->GetCheckPeriod();
349 fp << "\t" "check_period" "\t" << checkPeriod->GetName() << "\n";
352 fp << "\t" << "check_execution_time=" << Convert::ToString(cr->CalculateExecutionTime()) << "\n"
353 "\t" "check_latency=" << Convert::ToString(cr->CalculateLatency()) << "\n";
357 Service::Ptr service;
358 tie(host, service) = GetHostService(checkable);
361 fp << "\t" "current_state=" << service->GetState() << "\n"
362 "\t" "last_hard_state=" << service->GetLastHardState() << "\n"
363 "\t" "last_time_ok=" << static_cast<int>(service->GetLastStateOK()) << "\n"
364 "\t" "last_time_warn=" << static_cast<int>(service->GetLastStateWarning()) << "\n"
365 "\t" "last_time_critical=" << static_cast<int>(service->GetLastStateCritical()) << "\n"
366 "\t" "last_time_unknown=" << static_cast<int>(service->GetLastStateUnknown()) << "\n";
368 int currentState = host->GetState();
370 if (currentState != HostUp && !host->IsReachable())
371 currentState = 2; /* hardcoded compat state */
373 fp << "\t" "current_state=" << currentState << "\n"
374 "\t" "last_hard_state=" << host->GetLastHardState() << "\n"
375 "\t" "last_time_up=" << static_cast<int>(host->GetLastStateUp()) << "\n"
376 "\t" "last_time_down=" << static_cast<int>(host->GetLastStateDown()) << "\n";
379 fp << "\t" "state_type=" << checkable->GetStateType() << "\n"
380 "\t" "last_check=" << static_cast<long>(host->GetLastCheck()) << "\n";
383 fp << "\t" "plugin_output=" << CompatUtility::GetCheckResultOutput(cr) << "\n"
384 "\t" "long_plugin_output=" << CompatUtility::GetCheckResultLongOutput(cr) << "\n"
385 "\t" "performance_data=" << PluginUtility::FormatPerfdata(cr->GetPerformanceData()) << "\n";
388 fp << "\t" << "next_check=" << static_cast<long>(checkable->GetNextCheck()) << "\n"
389 "\t" "current_attempt=" << checkable->GetCheckAttempt() << "\n"
390 "\t" "max_attempts=" << checkable->GetMaxCheckAttempts() << "\n"
391 "\t" "last_state_change=" << static_cast<long>(checkable->GetLastStateChange()) << "\n"
392 "\t" "last_hard_state_change=" << static_cast<long>(checkable->GetLastHardStateChange()) << "\n"
393 "\t" "last_update=" << static_cast<long>(Utility::GetTime()) << "\n"
394 "\t" "notifications_enabled" "\t" << Convert::ToLong(checkable->GetEnableNotifications()) << "\n"
395 "\t" "active_checks_enabled=" << Convert::ToLong(checkable->GetEnableActiveChecks()) << "\n"
396 "\t" "passive_checks_enabled=" << Convert::ToLong(checkable->GetEnablePassiveChecks()) << "\n"
397 "\t" "flap_detection_enabled=" << Convert::ToLong(checkable->GetEnableFlapping()) << "\n"
398 "\t" "is_flapping=" << Convert::ToLong(checkable->IsFlapping()) << "\n"
399 "\t" "percent_state_change=" << checkable->GetFlappingCurrent() << "\n"
400 "\t" "problem_has_been_acknowledged=" << (checkable->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
401 "\t" "acknowledgement_type=" << checkable->GetAcknowledgement() << "\n"
402 "\t" "acknowledgement_end_time=" << checkable->GetAcknowledgementExpiry() << "\n"
403 "\t" "scheduled_downtime_depth=" << checkable->GetDowntimeDepth() << "\n"
404 "\t" "last_notification=" << CompatUtility::GetCheckableNotificationLastNotification(checkable) << "\n"
405 "\t" "next_notification=" << CompatUtility::GetCheckableNotificationNextNotification(checkable) << "\n"
406 "\t" "current_notification_number=" << CompatUtility::GetCheckableNotificationNotificationNumber(checkable) << "\n"
407 "\t" "is_reachable=" << Convert::ToLong(checkable->IsReachable()) << "\n";
410 void StatusDataWriter::DumpServiceStatus(std::ostream& fp, const Service::Ptr& service)
412 Host::Ptr host = service->GetHost();
414 fp << "servicestatus {" "\n"
415 "\t" "host_name=" << host->GetName() << "\n"
416 "\t" "service_description=" << service->GetShortName() << "\n";
419 ObjectLock olock(service);
420 DumpCheckableStatusAttrs(fp, service);
423 fp << "\t" "}" "\n" "\n";
425 DumpDowntimes(fp, service);
426 DumpComments(fp, service);
429 void StatusDataWriter::DumpServiceObject(std::ostream& fp, const Service::Ptr& service)
431 Host::Ptr host = service->GetHost();
434 ObjectLock olock(service);
436 fp << "define service {" "\n"
437 "\t" "host_name" "\t" << host->GetName() << "\n"
438 "\t" "service_description" "\t" << service->GetShortName() << "\n"
439 "\t" "display_name" "\t" << service->GetDisplayName() << "\n"
440 "\t" "check_interval" "\t" << (service->GetCheckInterval() / 60.0) << "\n"
441 "\t" "retry_interval" "\t" << (service->GetRetryInterval() / 60.0) << "\n"
442 "\t" "max_check_attempts" "\t" << service->GetMaxCheckAttempts() << "\n"
443 "\t" "active_checks_enabled" "\t" << Convert::ToLong(service->GetEnableActiveChecks()) << "\n"
444 "\t" "passive_checks_enabled" "\t" << Convert::ToLong(service->GetEnablePassiveChecks()) << "\n"
445 "\t" "flap_detection_enabled" "\t" << Convert::ToLong(service->GetEnableFlapping()) << "\n"
446 "\t" "is_volatile" "\t" << Convert::ToLong(service->GetVolatile()) << "\n"
447 "\t" "notifications_enabled" "\t" << Convert::ToLong(service->GetEnableNotifications()) << "\n"
448 "\t" "notification_options" "\t" << GetNotificationOptions(service) << "\n"
449 "\t" "notification_interval" "\t" << CompatUtility::GetCheckableNotificationNotificationInterval(service) << "\n"
450 "\t" "notification_period" "\t" << "" << "\n"
451 "\t" "event_handler_enabled" "\t" << Convert::ToLong(service->GetEnableEventHandler()) << "\n";
453 CheckCommand::Ptr checkcommand = service->GetCheckCommand();
455 fp << "\t" "check_command" "\t" << CompatUtility::GetCommandName(checkcommand) << "!" << CompatUtility::GetCheckableCommandArgs(service)<< "\n";
457 EventCommand::Ptr eventcommand = service->GetEventCommand();
458 if (eventcommand && service->GetEnableEventHandler())
459 fp << "\t" "event_handler" "\t" << CompatUtility::GetCommandName(eventcommand) << "\n";
461 TimePeriod::Ptr checkPeriod = service->GetCheckPeriod();
463 fp << "\t" "check_period" "\t" << checkPeriod->GetName() << "\n";
465 fp << "\t" "contacts" "\t";
466 DumpNameList(fp, CompatUtility::GetCheckableNotificationUsers(service));
469 fp << "\t" "contact_groups" "\t";
470 DumpNameList(fp, CompatUtility::GetCheckableNotificationUserGroups(service));
473 String notes = service->GetNotes();
474 String notes_url = service->GetNotesUrl();
475 String action_url = service->GetActionUrl();
476 String icon_image = service->GetIconImage();
477 String icon_image_alt = service->GetIconImageAlt();
479 fp << "\t" "initial_state" "\t" "o" "\n"
480 "\t" "low_flap_threshold" "\t" << service->GetFlappingThresholdLow() << "\n"
481 "\t" "high_flap_threshold" "\t" << service->GetFlappingThresholdHigh() << "\n"
482 "\t" "process_perf_data" "\t" << Convert::ToLong(service->GetEnablePerfdata()) << "\n"
483 "\t" "check_freshness" << "\t" "1" "\n";
485 if (!notes.IsEmpty())
486 fp << "\t" "notes" "\t" << notes << "\n";
487 if (!notes_url.IsEmpty())
488 fp << "\t" "notes_url" "\t" << notes_url << "\n";
489 if (!action_url.IsEmpty())
490 fp << "\t" "action_url" "\t" << action_url << "\n";
491 if (!icon_image.IsEmpty())
492 fp << "\t" "icon_image" "\t" << icon_image << "\n";
493 if (!icon_image_alt.IsEmpty())
494 fp << "\t" "icon_image_alt" "\t" << icon_image_alt << "\n";
497 fp << "\t" "service_groups" "\t";
500 Array::Ptr groups = service->GetGroups();
503 ObjectLock olock(groups);
505 for (const String& name : groups) {
506 ServiceGroup::Ptr sg = ServiceGroup::GetByName(name);
521 DumpCustomAttributes(fp, service);
523 fp << "\t" "}" "\n" "\n";
526 void StatusDataWriter::DumpCustomAttributes(std::ostream& fp, const CustomVarObject::Ptr& object)
528 Dictionary::Ptr vars = object->GetVars();
533 bool is_json = false;
535 ObjectLock olock(vars);
536 for (const Dictionary::Pair& kv : vars) {
537 if (kv.first.IsEmpty())
542 if (kv.second.IsObjectType<Array>() || kv.second.IsObjectType<Dictionary>()) {
543 value = JsonEncode(kv.second);
546 value = CompatUtility::EscapeString(kv.second);
548 fp << "\t" "_" << kv.first << "\t" << value << "\n";
552 fp << "\t" "_is_json" "\t" "1" "\n";
555 void StatusDataWriter::UpdateObjectsCache()
557 CONTEXT("Writing objects.cache file");
559 String objectsPath = GetObjectsPath();
561 std::fstream objectfp;
562 String tempObjectsPath = Utility::CreateTempFile(objectsPath + ".XXXXXX", 0644, objectfp);
564 objectfp << std::fixed;
566 objectfp << "# Icinga objects cache file" "\n"
567 "# This file is auto-generated. Do not modify this file." "\n"
570 for (const Host::Ptr& host : ConfigType::GetObjectsByType<Host>()) {
571 std::ostringstream tempobjectfp;
572 tempobjectfp << std::fixed;
573 DumpHostObject(tempobjectfp, host);
574 objectfp << tempobjectfp.str();
576 for (const Service::Ptr& service : host->GetServices()) {
577 std::ostringstream tempobjectfp;
578 tempobjectfp << std::fixed;
579 DumpServiceObject(tempobjectfp, service);
580 objectfp << tempobjectfp.str();
584 for (const HostGroup::Ptr& hg : ConfigType::GetObjectsByType<HostGroup>()) {
585 std::ostringstream tempobjectfp;
586 tempobjectfp << std::fixed;
588 String display_name = hg->GetDisplayName();
589 String notes = hg->GetNotes();
590 String notes_url = hg->GetNotesUrl();
591 String action_url = hg->GetActionUrl();
593 tempobjectfp << "define hostgroup {" "\n"
594 "\t" "hostgroup_name" "\t" << hg->GetName() << "\n";
596 if (!display_name.IsEmpty())
597 tempobjectfp << "\t" "alias" "\t" << display_name << "\n";
598 if (!notes.IsEmpty())
599 tempobjectfp << "\t" "notes" "\t" << notes << "\n";
600 if (!notes_url.IsEmpty())
601 tempobjectfp << "\t" "notes_url" "\t" << notes_url << "\n";
602 if (!action_url.IsEmpty())
603 tempobjectfp << "\t" "action_url" "\t" << action_url << "\n";
605 DumpCustomAttributes(tempobjectfp, hg);
607 tempobjectfp << "\t" "members" "\t";
608 DumpNameList(tempobjectfp, hg->GetMembers());
609 tempobjectfp << "\n" "\t" "}" "\n";
611 objectfp << tempobjectfp.str();
614 for (const ServiceGroup::Ptr& sg : ConfigType::GetObjectsByType<ServiceGroup>()) {
615 std::ostringstream tempobjectfp;
616 tempobjectfp << std::fixed;
618 String display_name = sg->GetDisplayName();
619 String notes = sg->GetNotes();
620 String notes_url = sg->GetNotesUrl();
621 String action_url = sg->GetActionUrl();
623 tempobjectfp << "define servicegroup {" "\n"
624 "\t" "servicegroup_name" "\t" << sg->GetName() << "\n";
626 if (!display_name.IsEmpty())
627 tempobjectfp << "\t" "alias" "\t" << display_name << "\n";
628 if (!notes.IsEmpty())
629 tempobjectfp << "\t" "notes" "\t" << notes << "\n";
630 if (!notes_url.IsEmpty())
631 tempobjectfp << "\t" "notes_url" "\t" << notes_url << "\n";
632 if (!action_url.IsEmpty())
633 tempobjectfp << "\t" "action_url" "\t" << action_url << "\n";
635 DumpCustomAttributes(tempobjectfp, sg);
637 tempobjectfp << "\t" "members" "\t";
639 std::vector<String> sglist;
640 for (const Service::Ptr& service : sg->GetMembers()) {
641 Host::Ptr host = service->GetHost();
643 sglist.emplace_back(host->GetName());
644 sglist.emplace_back(service->GetShortName());
647 DumpStringList(tempobjectfp, sglist);
649 tempobjectfp << "\n" "}" "\n";
651 objectfp << tempobjectfp.str();
654 for (const User::Ptr& user : ConfigType::GetObjectsByType<User>()) {
655 std::ostringstream tempobjectfp;
656 tempobjectfp << std::fixed;
658 String email = user->GetEmail();
659 String pager = user->GetPager();
660 String alias = user->GetDisplayName();
662 tempobjectfp << "define contact {" "\n"
663 "\t" "contact_name" "\t" << user->GetName() << "\n";
665 if (!alias.IsEmpty())
666 tempobjectfp << "\t" "alias" "\t" << alias << "\n";
667 if (!email.IsEmpty())
668 tempobjectfp << "\t" "email" "\t" << email << "\n";
669 if (!pager.IsEmpty())
670 tempobjectfp << "\t" "pager" "\t" << pager << "\n";
672 tempobjectfp << "\t" "service_notification_options" "\t" "w,u,c,r,f,s" "\n"
673 "\t" "host_notification_options""\t" "d,u,r,f,s" "\n"
674 "\t" "host_notifications_enabled" "\t" "1" "\n"
675 "\t" "service_notifications_enabled" "\t" "1" "\n"
679 objectfp << tempobjectfp.str();
682 for (const UserGroup::Ptr& ug : ConfigType::GetObjectsByType<UserGroup>()) {
683 std::ostringstream tempobjectfp;
684 tempobjectfp << std::fixed;
686 tempobjectfp << "define contactgroup {" "\n"
687 "\t" "contactgroup_name" "\t" << ug->GetName() << "\n"
688 "\t" "alias" "\t" << ug->GetDisplayName() << "\n";
690 tempobjectfp << "\t" "members" "\t";
691 DumpNameList(tempobjectfp, ug->GetMembers());
695 objectfp << tempobjectfp.str();
698 for (const Command::Ptr& command : ConfigType::GetObjectsByType<CheckCommand>()) {
699 DumpCommand(objectfp, command);
702 for (const Command::Ptr& command : ConfigType::GetObjectsByType<NotificationCommand>()) {
703 DumpCommand(objectfp, command);
706 for (const Command::Ptr& command : ConfigType::GetObjectsByType<EventCommand>()) {
707 DumpCommand(objectfp, command);
710 for (const TimePeriod::Ptr& tp : ConfigType::GetObjectsByType<TimePeriod>()) {
711 DumpTimePeriod(objectfp, tp);
714 for (const Dependency::Ptr& dep : ConfigType::GetObjectsByType<Dependency>()) {
715 Checkable::Ptr parent = dep->GetParent();
718 Log(LogDebug, "StatusDataWriter")
719 << "Missing parent for dependency '" << dep->GetName() << "'.";
723 Host::Ptr parent_host;
724 Service::Ptr parent_service;
725 tie(parent_host, parent_service) = GetHostService(parent);
727 Checkable::Ptr child = dep->GetChild();
730 Log(LogDebug, "StatusDataWriter")
731 << "Missing child for dependency '" << dep->GetName() << "'.";
735 Host::Ptr child_host;
736 Service::Ptr child_service;
737 tie(child_host, child_service) = GetHostService(child);
739 int state_filter = dep->GetStateFilter();
740 std::vector<String> failure_criteria;
741 if (state_filter & StateFilterOK || state_filter & StateFilterUp)
742 failure_criteria.emplace_back("o");
743 if (state_filter & StateFilterWarning)
744 failure_criteria.emplace_back("w");
745 if (state_filter & StateFilterCritical)
746 failure_criteria.emplace_back("c");
747 if (state_filter & StateFilterUnknown)
748 failure_criteria.emplace_back("u");
749 if (state_filter & StateFilterDown)
750 failure_criteria.emplace_back("d");
752 String criteria = boost::algorithm::join(failure_criteria, ",");
754 /* Icinga 1.x only allows host->host, service->service dependencies */
755 if (!child_service && !parent_service) {
756 objectfp << "define hostdependency {" "\n"
757 "\t" "dependent_host_name" "\t" << child_host->GetName() << "\n"
758 "\t" "host_name" "\t" << parent_host->GetName() << "\n"
759 "\t" "execution_failure_criteria" "\t" << criteria << "\n"
760 "\t" "notification_failure_criteria" "\t" << criteria << "\n"
763 } else if (child_service && parent_service){
765 objectfp << "define servicedependency {" "\n"
766 "\t" "dependent_host_name" "\t" << child_service->GetHost()->GetName() << "\n"
767 "\t" "dependent_service_description" "\t" << child_service->GetShortName() << "\n"
768 "\t" "host_name" "\t" << parent_service->GetHost()->GetName() << "\n"
769 "\t" "service_description" "\t" << parent_service->GetShortName() << "\n"
770 "\t" "execution_failure_criteria" "\t" << criteria << "\n"
771 "\t" "notification_failure_criteria" "\t" << criteria << "\n"
780 _unlink(objectsPath.CStr());
783 if (rename(tempObjectsPath.CStr(), objectsPath.CStr()) < 0) {
784 BOOST_THROW_EXCEPTION(posix_error()
785 << boost::errinfo_api_function("rename")
786 << boost::errinfo_errno(errno)
787 << boost::errinfo_file_name(tempObjectsPath));
792 * Periodically writes the status.dat and objects.cache files.
794 void StatusDataWriter::StatusTimerHandler()
796 if (m_ObjectsCacheOutdated) {
797 UpdateObjectsCache();
798 m_ObjectsCacheOutdated = false;
801 double start = Utility::GetTime();
803 String statusPath = GetStatusPath();
805 std::fstream statusfp;
806 String tempStatusPath = Utility::CreateTempFile(statusPath + ".XXXXXX", 0644, statusfp);
808 statusfp << std::fixed;
810 statusfp << "# Icinga status file" "\n"
811 "# This file is auto-generated. Do not modify this file." "\n"
814 statusfp << "info {" "\n"
815 "\t" "created=" << Utility::GetTime() << "\n"
816 "\t" "version=" << Application::GetAppVersion() << "\n"
820 statusfp << "programstatus {" "\n"
821 "\t" "icinga_pid=" << Utility::GetPid() << "\n"
822 "\t" "daemon_mode=1" "\n"
823 "\t" "program_start=" << static_cast<long>(Application::GetStartTime()) << "\n"
824 "\t" "active_host_checks_enabled=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableHostChecks()) << "\n"
825 "\t" "passive_host_checks_enabled=1" "\n"
826 "\t" "active_service_checks_enabled=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableServiceChecks()) << "\n"
827 "\t" "passive_service_checks_enabled=1" "\n"
828 "\t" "check_service_freshness=1" "\n"
829 "\t" "check_host_freshness=1" "\n"
830 "\t" "enable_notifications=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableNotifications()) << "\n"
831 "\t" "enable_event_handlers=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableEventHandlers()) << "\n"
832 "\t" "enable_flap_detection=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnableFlapping()) << "\n"
833 "\t" "enable_failure_prediction=0" "\n"
834 "\t" "process_performance_data=" << Convert::ToLong(IcingaApplication::GetInstance()->GetEnablePerfdata()) << "\n"
835 "\t" "active_scheduled_host_check_stats=" << CIB::GetActiveHostChecksStatistics(60) << "," << CIB::GetActiveHostChecksStatistics(5 * 60) << "," << CIB::GetActiveHostChecksStatistics(15 * 60) << "\n"
836 "\t" "passive_host_check_stats=" << CIB::GetPassiveHostChecksStatistics(60) << "," << CIB::GetPassiveHostChecksStatistics(5 * 60) << "," << CIB::GetPassiveHostChecksStatistics(15 * 60) << "\n"
837 "\t" "active_scheduled_service_check_stats=" << CIB::GetActiveServiceChecksStatistics(60) << "," << CIB::GetActiveServiceChecksStatistics(5 * 60) << "," << CIB::GetActiveServiceChecksStatistics(15 * 60) << "\n"
838 "\t" "passive_service_check_stats=" << CIB::GetPassiveServiceChecksStatistics(60) << "," << CIB::GetPassiveServiceChecksStatistics(5 * 60) << "," << CIB::GetPassiveServiceChecksStatistics(15 * 60) << "\n"
839 "\t" "next_downtime_id=" << Downtime::GetNextDowntimeID() << "\n"
840 "\t" "next_comment_id=" << Comment::GetNextCommentID() << "\n";
842 statusfp << "\t" "}" "\n"
845 for (const Host::Ptr& host : ConfigType::GetObjectsByType<Host>()) {
846 std::ostringstream tempstatusfp;
847 tempstatusfp << std::fixed;
848 DumpHostStatus(tempstatusfp, host);
849 statusfp << tempstatusfp.str();
851 for (const Service::Ptr& service : host->GetServices()) {
852 std::ostringstream tempstatusfp;
853 tempstatusfp << std::fixed;
854 DumpServiceStatus(tempstatusfp, service);
855 statusfp << tempstatusfp.str();
862 _unlink(statusPath.CStr());
865 if (rename(tempStatusPath.CStr(), statusPath.CStr()) < 0) {
866 BOOST_THROW_EXCEPTION(posix_error()
867 << boost::errinfo_api_function("rename")
868 << boost::errinfo_errno(errno)
869 << boost::errinfo_file_name(tempStatusPath));
872 Log(LogNotice, "StatusDataWriter")
873 << "Writing status.dat file took " << Utility::FormatDuration(Utility::GetTime() - start);
876 void StatusDataWriter::ObjectHandler()
878 m_ObjectsCacheOutdated = true;
881 String StatusDataWriter::GetNotificationOptions(const Checkable::Ptr& checkable)
884 Service::Ptr service;
885 tie(host, service) = GetHostService(checkable);
887 unsigned long notification_type_filter = 0;
888 unsigned long notification_state_filter = 0;
890 for (const Notification::Ptr& notification : checkable->GetNotifications()) {
891 notification_type_filter |= notification->GetTypeFilter();
892 notification_state_filter |= notification->GetStateFilter();
895 std::vector<String> notification_options;
897 /* notification state filters */
899 if (notification_state_filter & ServiceWarning) {
900 notification_options.push_back("w");
902 if (notification_state_filter & ServiceUnknown) {
903 notification_options.push_back("u");
905 if (notification_state_filter & ServiceCritical) {
906 notification_options.push_back("c");
909 if (notification_state_filter & HostDown) {
910 notification_options.push_back("d");
914 /* notification type filters */
915 if (notification_type_filter & NotificationRecovery) {
916 notification_options.push_back("r");
918 if ((notification_type_filter & NotificationFlappingStart) ||
919 (notification_type_filter & NotificationFlappingEnd)) {
920 notification_options.push_back("f");
922 if ((notification_type_filter & NotificationDowntimeStart) ||
923 (notification_type_filter & NotificationDowntimeEnd) ||
924 (notification_type_filter & NotificationDowntimeRemoved)) {
925 notification_options.push_back("s");
928 return boost::algorithm::join(notification_options, ",");