]> granicus.if.org Git - icinga2/blob - lib/db_ido/servicedbobject.cpp
Merge pull request #7185 from Icinga/bugfix/gelfwriter-wrong-log-facility
[icinga2] / lib / db_ido / servicedbobject.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "db_ido/servicedbobject.hpp"
4 #include "db_ido/servicegroupdbobject.hpp"
5 #include "db_ido/dbtype.hpp"
6 #include "db_ido/dbvalue.hpp"
7 #include "db_ido/dbevents.hpp"
8 #include "icinga/notification.hpp"
9 #include "icinga/dependency.hpp"
10 #include "icinga/checkcommand.hpp"
11 #include "icinga/eventcommand.hpp"
12 #include "icinga/externalcommandprocessor.hpp"
13 #include "icinga/compatutility.hpp"
14 #include "icinga/pluginutility.hpp"
15 #include "icinga/icingaapplication.hpp"
16 #include "remote/endpoint.hpp"
17 #include "base/convert.hpp"
18 #include "base/objectlock.hpp"
19 #include "base/initialize.hpp"
20 #include "base/configtype.hpp"
21 #include "base/utility.hpp"
22 #include "base/logger.hpp"
23 #include "base/json.hpp"
24 #include <boost/algorithm/string/join.hpp>
25
26 using namespace icinga;
27
28 REGISTER_DBTYPE(Service, "service", DbObjectTypeService, "service_object_id", ServiceDbObject);
29
30 ServiceDbObject::ServiceDbObject(const DbType::Ptr& type, const String& name1, const String& name2)
31         : DbObject(type, name1, name2)
32 { }
33
34 Dictionary::Ptr ServiceDbObject::GetConfigFields() const
35 {
36         Service::Ptr service = static_pointer_cast<Service>(GetObject());
37         Host::Ptr host = service->GetHost();
38
39         unsigned long notificationStateFilter = CompatUtility::GetCheckableNotificationTypeFilter(service);
40         unsigned long notificationTypeFilter = CompatUtility::GetCheckableNotificationTypeFilter(service);
41
42         return new Dictionary({
43                 { "host_object_id", host },
44                 { "display_name", service->GetDisplayName() },
45                 { "check_command_object_id", service->GetCheckCommand() },
46                 { "eventhandler_command_object_id", service->GetEventCommand() },
47                 { "check_timeperiod_object_id", service->GetCheckPeriod() },
48                 { "check_interval", service->GetCheckInterval() / 60.0 },
49                 { "retry_interval", service->GetRetryInterval() / 60.0 },
50                 { "max_check_attempts", service->GetMaxCheckAttempts() },
51                 { "is_volatile", service->GetVolatile() },
52                 { "flap_detection_enabled", service->GetEnableFlapping() },
53                 { "low_flap_threshold", service->GetFlappingThresholdLow() },
54                 { "high_flap_threshold", service->GetFlappingThresholdLow() },
55                 { "process_performance_data", service->GetEnablePerfdata() },
56                 { "freshness_checks_enabled", 1 },
57                 { "freshness_threshold", Convert::ToLong(service->GetCheckInterval()) },
58                 { "event_handler_enabled", service->GetEnableEventHandler() },
59                 { "passive_checks_enabled", service->GetEnablePassiveChecks() },
60                 { "active_checks_enabled", service->GetEnableActiveChecks() },
61                 { "notifications_enabled", service->GetEnableNotifications() },
62                 { "notes", service->GetNotes() },
63                 { "notes_url", service->GetNotesUrl() },
64                 { "action_url", service->GetActionUrl() },
65                 { "icon_image", service->GetIconImage() },
66                 { "icon_image_alt", service->GetIconImageAlt() },
67                 { "notification_interval", CompatUtility::GetCheckableNotificationNotificationInterval(service) },
68                 { "notify_on_warning", (notificationStateFilter & ServiceWarning) ? 1 : 0 },
69                 { "notify_on_unknown", (notificationStateFilter & ServiceUnknown) ? 1 : 0 },
70                 { "notify_on_critical", (notificationStateFilter & ServiceCritical) ? 1 : 0 },
71                 { "notify_on_recovery", (notificationTypeFilter & NotificationRecovery) ? 1 : 0 },
72                 { "notify_on_flapping", (notificationTypeFilter & (NotificationFlappingStart | NotificationFlappingEnd)) ? 1 : 0 },
73                 { "notify_on_downtime", (notificationTypeFilter & (NotificationDowntimeStart | NotificationDowntimeEnd | NotificationDowntimeRemoved)) ? 1 : 0 }
74         });
75 }
76
77 Dictionary::Ptr ServiceDbObject::GetStatusFields() const
78 {
79         Dictionary::Ptr fields = new Dictionary();
80         Service::Ptr service = static_pointer_cast<Service>(GetObject());
81         CheckResult::Ptr cr = service->GetLastCheckResult();
82
83         if (cr) {
84                 fields->Set("output", CompatUtility::GetCheckResultOutput(cr));
85                 fields->Set("long_output", CompatUtility::GetCheckResultLongOutput(cr));
86                 fields->Set("perfdata", PluginUtility::FormatPerfdata(cr->GetPerformanceData()));
87                 fields->Set("check_source", cr->GetCheckSource());
88                 fields->Set("latency", cr->CalculateLatency());
89                 fields->Set("execution_time", cr->CalculateExecutionTime());
90         }
91
92         fields->Set("current_state", service->GetState());
93         fields->Set("has_been_checked", service->HasBeenChecked());
94         fields->Set("should_be_scheduled", service->GetEnableActiveChecks());
95         fields->Set("current_check_attempt", service->GetCheckAttempt());
96         fields->Set("max_check_attempts", service->GetMaxCheckAttempts());
97         fields->Set("last_check", DbValue::FromTimestamp(service->GetLastCheck()));
98         fields->Set("next_check", DbValue::FromTimestamp(service->GetNextCheck()));
99         fields->Set("check_type", !service->GetEnableActiveChecks()); /* 0 .. active, 1 .. passive */
100         fields->Set("last_state_change", DbValue::FromTimestamp(service->GetLastStateChange()));
101         fields->Set("last_hard_state_change", DbValue::FromTimestamp(service->GetLastHardStateChange()));
102         fields->Set("last_hard_state", service->GetLastHardState());
103         fields->Set("last_time_ok", DbValue::FromTimestamp(service->GetLastStateOK()));
104         fields->Set("last_time_warning", DbValue::FromTimestamp(service->GetLastStateWarning()));
105         fields->Set("last_time_critical", DbValue::FromTimestamp(service->GetLastStateCritical()));
106         fields->Set("last_time_unknown", DbValue::FromTimestamp(service->GetLastStateUnknown()));
107         fields->Set("state_type", service->GetStateType());
108         fields->Set("notifications_enabled", service->GetEnableNotifications());
109         fields->Set("problem_has_been_acknowledged", service->GetAcknowledgement() != AcknowledgementNone);
110         fields->Set("acknowledgement_type", service->GetAcknowledgement());
111         fields->Set("passive_checks_enabled", service->GetEnablePassiveChecks());
112         fields->Set("active_checks_enabled", service->GetEnableActiveChecks());
113         fields->Set("event_handler_enabled", service->GetEnableEventHandler());
114         fields->Set("flap_detection_enabled", service->GetEnableFlapping());
115         fields->Set("is_flapping", service->IsFlapping());
116         fields->Set("percent_state_change", service->GetFlappingCurrent());
117         fields->Set("scheduled_downtime_depth", service->GetDowntimeDepth());
118         fields->Set("process_performance_data", service->GetEnablePerfdata());
119         fields->Set("normal_check_interval", service->GetCheckInterval() / 60.0);
120         fields->Set("retry_check_interval", service->GetRetryInterval() / 60.0);
121         fields->Set("check_timeperiod_object_id", service->GetCheckPeriod());
122         fields->Set("is_reachable", service->GetLastReachable());
123         fields->Set("original_attributes", JsonEncode(service->GetOriginalAttributes()));
124
125         fields->Set("current_notification_number", CompatUtility::GetCheckableNotificationNotificationNumber(service));
126         fields->Set("last_notification", DbValue::FromTimestamp(CompatUtility::GetCheckableNotificationLastNotification(service)));
127         fields->Set("next_notification", DbValue::FromTimestamp(CompatUtility::GetCheckableNotificationNextNotification(service)));
128
129         EventCommand::Ptr eventCommand = service->GetEventCommand();
130
131         if (eventCommand)
132                 fields->Set("event_handler", eventCommand->GetName());
133
134         CheckCommand::Ptr checkCommand = service->GetCheckCommand();
135
136         if (checkCommand)
137                 fields->Set("check_command", checkCommand->GetName());
138
139         return fields;
140 }
141
142 void ServiceDbObject::OnConfigUpdateHeavy()
143 {
144         Service::Ptr service = static_pointer_cast<Service>(GetObject());
145
146         /* groups */
147         Array::Ptr groups = service->GetGroups();
148
149         std::vector<DbQuery> queries;
150
151         DbQuery query1;
152         query1.Table = DbType::GetByName("ServiceGroup")->GetTable() + "_members";
153         query1.Type = DbQueryDelete;
154         query1.Category = DbCatConfig;
155         query1.WhereCriteria = new Dictionary({
156                 { "service_object_id", service }
157         });
158         queries.emplace_back(std::move(query1));
159
160         if (groups) {
161                 ObjectLock olock(groups);
162                 for (const String& groupName : groups) {
163                         ServiceGroup::Ptr group = ServiceGroup::GetByName(groupName);
164
165                         DbQuery query2;
166                         query2.Table = DbType::GetByName("ServiceGroup")->GetTable() + "_members";
167                         query2.Type = DbQueryInsert;
168                         query2.Category = DbCatConfig;
169                         query2.Fields = new Dictionary({
170                                 { "instance_id", 0 }, /* DbConnection class fills in real ID */
171                                 { "servicegroup_id", DbValue::FromObjectInsertID(group) },
172                                 { "service_object_id", service }
173                         });
174                         query2.WhereCriteria = new Dictionary({
175                                 { "instance_id", 0 }, /* DbConnection class fills in real ID */
176                                 { "servicegroup_id", DbValue::FromObjectInsertID(group) },
177                                 { "service_object_id", service }
178                         });
179                         queries.emplace_back(std::move(query2));
180                 }
181         }
182
183         DbObject::OnMultipleQueries(queries);
184
185         /* service dependencies */
186         queries.clear();
187
188         DbQuery query2;
189         query2.Table = GetType()->GetTable() + "dependencies";
190         query2.Type = DbQueryDelete;
191         query2.Category = DbCatConfig;
192         query2.WhereCriteria = new Dictionary({
193                 { "dependent_service_object_id", service }
194         });
195         queries.emplace_back(std::move(query2));
196
197         for (const Dependency::Ptr& dep : service->GetDependencies()) {
198                 Checkable::Ptr parent = dep->GetParent();
199
200                 if (!parent) {
201                         Log(LogDebug, "ServiceDbObject")
202                                 << "Missing parent for dependency '" << dep->GetName() << "'.";
203                         continue;
204                 }
205
206                 Log(LogDebug, "ServiceDbObject")
207                         << "service parents: " << parent->GetName();
208
209                 int stateFilter = dep->GetStateFilter();
210
211                 /* service dependencies */
212                 DbQuery query1;
213                 query1.Table = GetType()->GetTable() + "dependencies";
214                 query1.Type = DbQueryInsert;
215                 query1.Category = DbCatConfig;
216                 query1.Fields = new Dictionary({
217                         { "service_object_id", parent },
218                         { "dependent_service_object_id", service },
219                         { "inherits_parent", 1 },
220                         { "timeperiod_object_id", dep->GetPeriod() },
221                         { "fail_on_ok", (stateFilter & StateFilterOK) ? 1 : 0 },
222                         { "fail_on_warning", (stateFilter & StateFilterWarning) ? 1 : 0 },
223                         { "fail_on_critical", (stateFilter & StateFilterCritical) ? 1 : 0 },
224                         { "fail_on_unknown", (stateFilter & StateFilterUnknown) ? 1 : 0 },
225                         { "instance_id", 0 } /* DbConnection class fills in real ID */
226                 });
227                 queries.emplace_back(std::move(query1));
228         }
229
230         DbObject::OnMultipleQueries(queries);
231
232         /* service contacts, contactgroups */
233         queries.clear();
234
235         DbQuery query3;
236         query3.Table = GetType()->GetTable() + "_contacts";
237         query3.Type = DbQueryDelete;
238         query3.Category = DbCatConfig;
239         query3.WhereCriteria = new Dictionary({
240                 { "service_id", DbValue::FromObjectInsertID(service) }
241         });
242         queries.emplace_back(std::move(query3));
243
244         for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(service)) {
245                 DbQuery query_contact;
246                 query_contact.Table = GetType()->GetTable() + "_contacts";
247                 query_contact.Type = DbQueryInsert;
248                 query_contact.Category = DbCatConfig;
249                 query_contact.Fields = new Dictionary({
250                         { "service_id", DbValue::FromObjectInsertID(service) },
251                         { "contact_object_id", user },
252                         { "instance_id", 0 } /* DbConnection class fills in real ID */
253
254                 });
255                 queries.emplace_back(std::move(query_contact));
256         }
257
258         DbObject::OnMultipleQueries(queries);
259
260         queries.clear();
261
262         DbQuery query4;
263         query4.Table = GetType()->GetTable() + "_contactgroups";
264         query4.Type = DbQueryDelete;
265         query4.Category = DbCatConfig;
266         query4.WhereCriteria = new Dictionary({
267                 { "service_id", DbValue::FromObjectInsertID(service) }
268         });
269         queries.emplace_back(std::move(query4));
270
271         for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(service)) {
272                 DbQuery query_contact;
273                 query_contact.Table = GetType()->GetTable() + "_contactgroups";
274                 query_contact.Type = DbQueryInsert;
275                 query_contact.Category = DbCatConfig;
276                 query_contact.Fields = new Dictionary({
277                         { "service_id", DbValue::FromObjectInsertID(service) },
278                         { "contactgroup_object_id", usergroup },
279                         { "instance_id", 0 } /* DbConnection class fills in real ID */
280                 });
281                 queries.emplace_back(std::move(query_contact));
282         }
283
284         DbObject::OnMultipleQueries(queries);
285
286         DoCommonConfigUpdate();
287 }
288
289 void ServiceDbObject::OnConfigUpdateLight()
290 {
291         DoCommonConfigUpdate();
292 }
293
294 void ServiceDbObject::DoCommonConfigUpdate()
295 {
296         Service::Ptr service = static_pointer_cast<Service>(GetObject());
297
298         /* update comments and downtimes on config change */
299         DbEvents::AddComments(service);
300         DbEvents::AddDowntimes(service);
301 }
302
303 String ServiceDbObject::CalculateConfigHash(const Dictionary::Ptr& configFields) const
304 {
305         String hashData = DbObject::CalculateConfigHash(configFields);
306
307         Service::Ptr service = static_pointer_cast<Service>(GetObject());
308
309         Array::Ptr groups = service->GetGroups();
310
311         if (groups)
312                 hashData += DbObject::HashValue(groups);
313
314         ArrayData dependencies;
315
316         /* dependencies */
317         for (const Dependency::Ptr& dep : service->GetDependencies()) {
318                 Checkable::Ptr parent = dep->GetParent();
319
320                 if (!parent)
321                         continue;
322
323                 dependencies.push_back(new Array({
324                         parent->GetName(),
325                         dep->GetStateFilter(),
326                         dep->GetPeriodRaw()
327                 }));
328         }
329
330         std::sort(dependencies.begin(), dependencies.end());
331
332         hashData += DbObject::HashValue(new Array(std::move(dependencies)));
333
334         ArrayData users;
335
336         for (const User::Ptr& user : CompatUtility::GetCheckableNotificationUsers(service)) {
337                 users.push_back(user->GetName());
338         }
339
340         std::sort(users.begin(), users.end());
341
342         hashData += DbObject::HashValue(new Array(std::move(users)));
343
344         ArrayData userGroups;
345
346         for (const UserGroup::Ptr& usergroup : CompatUtility::GetCheckableNotificationUserGroups(service)) {
347                 userGroups.push_back(usergroup->GetName());
348         }
349
350         std::sort(userGroups.begin(), userGroups.end());
351
352         hashData += DbObject::HashValue(new Array(std::move(userGroups)));
353
354         return SHA256(hashData);
355 }