]> granicus.if.org Git - icinga2/blob - components/livestatus/servicestable.cpp
CompatUtility: Use functionality in compat/ido/livestatus.
[icinga2] / components / livestatus / servicestable.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2013 Icinga Development Team (http://www.icinga.org/)   *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "livestatus/servicestable.h"
21 #include "livestatus/hoststable.h"
22 #include "icinga/service.h"
23 #include "icinga/checkcommand.h"
24 #include "icinga/eventcommand.h"
25 #include "icinga/timeperiod.h"
26 #include "icinga/macroprocessor.h"
27 #include "icinga/icingaapplication.h"
28 #include "icinga/compatutility.h"
29 #include "base/dynamictype.h"
30 #include "base/objectlock.h"
31 #include "base/convert.h"
32 #include "base/utility.h"
33 #include <boost/foreach.hpp>
34 #include <boost/tuple/tuple.hpp>
35 #include <boost/algorithm/string/replace.hpp>
36
37 using namespace icinga;
38 using namespace livestatus;
39
40 ServicesTable::ServicesTable(void)
41 {
42         AddColumns(this);
43 }
44
45 void ServicesTable::AddColumns(Table *table, const String& prefix,
46     const Column::ObjectAccessor& objectAccessor)
47 {
48         table->AddColumn(prefix + "description", Column(&ServicesTable::ShortNameAccessor, objectAccessor));
49         table->AddColumn(prefix + "display_name", Column(&ServicesTable::DisplayNameAccessor, objectAccessor));
50         table->AddColumn(prefix + "check_command", Column(&ServicesTable::CheckCommandAccessor, objectAccessor));
51         table->AddColumn(prefix + "check_command_expanded", Column(&ServicesTable::CheckCommandExpandedAccessor, objectAccessor));
52         table->AddColumn(prefix + "event_handler", Column(&ServicesTable::EventHandlerAccessor, objectAccessor));
53         table->AddColumn(prefix + "plugin_output", Column(&ServicesTable::PluginOutputAccessor, objectAccessor));
54         table->AddColumn(prefix + "long_plugin_output", Column(&ServicesTable::LongPluginOutputAccessor, objectAccessor));
55         table->AddColumn(prefix + "perf_data", Column(&ServicesTable::PerfDataAccessor, objectAccessor));
56         table->AddColumn(prefix + "notification_period", Column(&ServicesTable::NotificationPeriodAccessor, objectAccessor));
57         table->AddColumn(prefix + "check_period", Column(&ServicesTable::CheckPeriodAccessor, objectAccessor));
58         table->AddColumn(prefix + "notes", Column(&ServicesTable::NotesAccessor, objectAccessor));
59         table->AddColumn(prefix + "notes_expanded", Column(&ServicesTable::NotesExpandedAccessor, objectAccessor));
60         table->AddColumn(prefix + "notes_url", Column(&ServicesTable::NotesUrlAccessor, objectAccessor));
61         table->AddColumn(prefix + "notes_url_expanded", Column(&ServicesTable::NotesUrlExpandedAccessor, objectAccessor));
62         table->AddColumn(prefix + "action_url", Column(&ServicesTable::ActionUrlAccessor, objectAccessor));
63         table->AddColumn(prefix + "action_url_expanded", Column(&ServicesTable::ActionUrlExpandedAccessor, objectAccessor));
64         table->AddColumn(prefix + "icon_image", Column(&ServicesTable::IconImageAccessor, objectAccessor));
65         table->AddColumn(prefix + "icon_image_expanded", Column(&ServicesTable::IconImageExpandedAccessor, objectAccessor));
66         table->AddColumn(prefix + "icon_image_alt", Column(&ServicesTable::IconImageAltAccessor, objectAccessor));
67         table->AddColumn(prefix + "initial_state", Column(&Table::EmptyStringAccessor, objectAccessor));
68         table->AddColumn(prefix + "max_check_attempts", Column(&ServicesTable::MaxCheckAttemptsAccessor, objectAccessor));
69         table->AddColumn(prefix + "current_attempt", Column(&ServicesTable::CurrentAttemptAccessor, objectAccessor));
70         table->AddColumn(prefix + "state", Column(&ServicesTable::StateAccessor, objectAccessor));
71         table->AddColumn(prefix + "has_been_checked", Column(&ServicesTable::HasBeenCheckedAccessor, objectAccessor));
72         table->AddColumn(prefix + "last_state", Column(&ServicesTable::LastStateAccessor, objectAccessor));
73         table->AddColumn(prefix + "last_hard_state", Column(&ServicesTable::LastHardStateAccessor, objectAccessor));
74         table->AddColumn(prefix + "state_type", Column(&ServicesTable::StateTypeAccessor, objectAccessor));
75         table->AddColumn(prefix + "check_type", Column(&ServicesTable::CheckTypeAccessor, objectAccessor));
76         table->AddColumn(prefix + "acknowledged", Column(&ServicesTable::AcknowledgedAccessor, objectAccessor));
77         table->AddColumn(prefix + "acknowledgement_type", Column(&ServicesTable::AcknowledgementTypeAccessor, objectAccessor));
78         table->AddColumn(prefix + "no_more_notifications", Column(&ServicesTable::NoMoreNotificationsAccessor, objectAccessor));
79         table->AddColumn(prefix + "last_time_ok", Column(&ServicesTable::LastTimeOkAccessor, objectAccessor));
80         table->AddColumn(prefix + "last_time_warning", Column(&ServicesTable::LastTimeWarningAccessor, objectAccessor));
81         table->AddColumn(prefix + "last_time_critical", Column(&ServicesTable::LastTimeCriticalAccessor, objectAccessor));
82         table->AddColumn(prefix + "last_time_unknown", Column(&ServicesTable::LastTimeUnknownAccessor, objectAccessor));
83         table->AddColumn(prefix + "last_check", Column(&ServicesTable::LastCheckAccessor, objectAccessor));
84         table->AddColumn(prefix + "next_check", Column(&ServicesTable::NextCheckAccessor, objectAccessor));
85         table->AddColumn(prefix + "last_notification", Column(&ServicesTable::LastNotificationAccessor, objectAccessor));
86         table->AddColumn(prefix + "next_notification", Column(&ServicesTable::NextNotificationAccessor, objectAccessor));
87         table->AddColumn(prefix + "current_notification_number", Column(&ServicesTable::CurrentNotificationNumberAccessor, objectAccessor));
88         table->AddColumn(prefix + "last_state_change", Column(&ServicesTable::LastStateChangeAccessor, objectAccessor));
89         table->AddColumn(prefix + "last_hard_state_change", Column(&ServicesTable::LastHardStateChangeAccessor, objectAccessor));
90         table->AddColumn(prefix + "scheduled_downtime_depth", Column(&ServicesTable::ScheduledDowntimeDepthAccessor, objectAccessor));
91         table->AddColumn(prefix + "is_flapping", Column(&ServicesTable::IsFlappingAccessor, objectAccessor));
92         table->AddColumn(prefix + "checks_enabled", Column(&ServicesTable::ChecksEnabledAccessor, objectAccessor));
93         table->AddColumn(prefix + "accept_passive_checks", Column(&ServicesTable::AcceptPassiveChecksAccessor, objectAccessor));
94         table->AddColumn(prefix + "event_handler_enabled", Column(&ServicesTable::EventHandlerEnabledAccessor, objectAccessor));
95         table->AddColumn(prefix + "notifications_enabled", Column(&ServicesTable::NotificationsEnabledAccessor, objectAccessor));
96         table->AddColumn(prefix + "process_performance_data", Column(&Table::OneAccessor, objectAccessor));
97         table->AddColumn(prefix + "is_executing", Column(&Table::ZeroAccessor, objectAccessor));
98         table->AddColumn(prefix + "active_checks_enabled", Column(&ServicesTable::ActiveChecksEnabledAccessor, objectAccessor));
99         table->AddColumn(prefix + "check_options", Column(&ServicesTable::CheckOptionsAccessor, objectAccessor));
100         table->AddColumn(prefix + "flap_detection_enabled", Column(&ServicesTable::FlapDetectionEnabledAccessor, objectAccessor));
101         table->AddColumn(prefix + "check_freshness", Column(&ServicesTable::CheckFreshnessAccessor, objectAccessor));
102         table->AddColumn(prefix + "obsess_over_service", Column(&Table::ZeroAccessor, objectAccessor));
103         table->AddColumn(prefix + "modified_attributes", Column(&ServicesTable::ModifiedAttributesAccessor, objectAccessor));
104         table->AddColumn(prefix + "modified_attributes_list", Column(&ServicesTable::ModifiedAttributesListAccessor, objectAccessor));
105         table->AddColumn(prefix + "pnpgraph_present", Column(&Table::ZeroAccessor, objectAccessor));
106         table->AddColumn(prefix + "staleness", Column(&ServicesTable::StalenessAccessor, objectAccessor));
107         table->AddColumn(prefix + "check_interval", Column(&ServicesTable::CheckIntervalAccessor, objectAccessor));
108         table->AddColumn(prefix + "retry_interval", Column(&ServicesTable::RetryIntervalAccessor, objectAccessor));
109         table->AddColumn(prefix + "notification_interval", Column(&ServicesTable::NotificationIntervalAccessor, objectAccessor));
110         table->AddColumn(prefix + "first_notification_delay", Column(&Table::EmptyStringAccessor, objectAccessor));
111         table->AddColumn(prefix + "low_flap_threshold", Column(&ServicesTable::LowFlapThresholdAccessor, objectAccessor));
112         table->AddColumn(prefix + "high_flap_threshold", Column(&ServicesTable::HighFlapThresholdAccessor, objectAccessor));
113         table->AddColumn(prefix + "latency", Column(&ServicesTable::LatencyAccessor, objectAccessor));
114         table->AddColumn(prefix + "execution_time", Column(&ServicesTable::ExecutionTimeAccessor, objectAccessor));
115         table->AddColumn(prefix + "percent_state_change", Column(&ServicesTable::PercentStateChangeAccessor, objectAccessor));
116         table->AddColumn(prefix + "in_check_period", Column(&ServicesTable::InCheckPeriodAccessor, objectAccessor));
117         table->AddColumn(prefix + "in_notification_period", Column(&ServicesTable::InNotificationPeriodAccessor, objectAccessor));
118         table->AddColumn(prefix + "contacts", Column(&ServicesTable::ContactsAccessor, objectAccessor));
119         table->AddColumn(prefix + "downtimes", Column(&ServicesTable::DowntimesAccessor, objectAccessor));
120         table->AddColumn(prefix + "downtimes_with_info", Column(&ServicesTable::DowntimesWithInfoAccessor, objectAccessor));
121         table->AddColumn(prefix + "comments", Column(&ServicesTable::CommentsAccessor, objectAccessor));
122         table->AddColumn(prefix + "comments_with_info", Column(&ServicesTable::CommentsWithInfoAccessor, objectAccessor));
123         table->AddColumn(prefix + "comments_with_extra_info", Column(&ServicesTable::CommentsWithExtraInfoAccessor, objectAccessor));
124         table->AddColumn(prefix + "custom_variable_names", Column(&ServicesTable::CustomVariableNamesAccessor, objectAccessor));
125         table->AddColumn(prefix + "custom_variable_values", Column(&ServicesTable::CustomVariableValuesAccessor, objectAccessor));
126         table->AddColumn(prefix + "custom_variables", Column(&ServicesTable::CustomVariablesAccessor, objectAccessor));
127         table->AddColumn(prefix + "groups", Column(&ServicesTable::GroupsAccessor, objectAccessor));
128         table->AddColumn(prefix + "contact_groups", Column(&ServicesTable::ContactGroupsAccessor, objectAccessor));
129
130         HostsTable::AddColumns(table, "host_", boost::bind(&ServicesTable::HostAccessor, _1, objectAccessor));
131 }
132
133 String ServicesTable::GetName(void) const
134 {
135         return "services";
136 }
137
138 void ServicesTable::FetchRows(const AddRowFunction& addRowFn)
139 {
140         BOOST_FOREACH(const Service::Ptr& service, DynamicType::GetObjects<Service>()) {
141                 addRowFn(service);
142         }
143 }
144
145 Object::Ptr ServicesTable::HostAccessor(const Value& row, const Column::ObjectAccessor& parentObjectAccessor)
146 {
147         Value service;
148
149         if (parentObjectAccessor)
150                 service = parentObjectAccessor(row);
151         else
152                 service = row;
153
154         Service::Ptr svc = static_cast<Service::Ptr>(service);
155
156         if (!svc)
157                 return Object::Ptr();
158
159         return svc->GetHost();
160 }
161
162 Value ServicesTable::ShortNameAccessor(const Value& row)
163 {
164         Service::Ptr service = static_cast<Service::Ptr>(row);
165
166         if (!service)
167                 return Empty;
168
169         return service->GetShortName();
170 }
171
172 Value ServicesTable::DisplayNameAccessor(const Value& row)
173 {
174         Service::Ptr service = static_cast<Service::Ptr>(row);
175
176         if (!service)
177                 return Empty;
178
179         return service->GetDisplayName();
180 }
181
182 Value ServicesTable::CheckCommandAccessor(const Value& row)
183 {
184         Service::Ptr service = static_cast<Service::Ptr>(row);
185
186         if (!service)
187                 return Empty;
188
189         CheckCommand::Ptr checkcommand = service->GetCheckCommand();
190
191         if (checkcommand)
192                 return checkcommand->GetName(); /* this is the name without '!' args */
193
194         return Empty;
195 }
196
197 Value ServicesTable::CheckCommandExpandedAccessor(const Value& row)
198 {
199         Service::Ptr service = static_cast<Service::Ptr>(row);
200
201         if (!service)
202                 return Empty;
203
204         CheckCommand::Ptr commandObj = service->GetCheckCommand();
205
206         if (!commandObj)
207                 return Empty;
208
209         Value raw_command = commandObj->GetCommandLine();
210
211         std::vector<MacroResolver::Ptr> resolvers;
212         resolvers.push_back(service);
213         resolvers.push_back(service->GetHost());
214         resolvers.push_back(commandObj);
215         resolvers.push_back(IcingaApplication::GetInstance());
216
217         Value commandLine = MacroProcessor::ResolveMacros(raw_command, resolvers, Dictionary::Ptr(), Utility::EscapeShellCmd);
218
219         String buf;
220         if (commandLine.IsObjectType<Array>()) {
221                 Array::Ptr args = commandLine;
222
223                 ObjectLock olock(args);
224                 String arg;
225                 BOOST_FOREACH(arg, args) {
226                         // This is obviously incorrect for non-trivial cases.
227                         String argitem = " \"" + arg + "\"";
228                         boost::algorithm::replace_all(argitem, "\n", "\\n");
229                         buf += argitem;
230                 }
231         } else if (!commandLine.IsEmpty()) {
232                 String args = Convert::ToString(commandLine);
233                 boost::algorithm::replace_all(args, "\n", "\\n");
234                 buf += args;
235         } else {
236                 buf += "<internal>";
237         }
238
239         return buf;
240 }
241
242 Value ServicesTable::EventHandlerAccessor(const Value& row)
243 {
244         Service::Ptr service = static_cast<Service::Ptr>(row);
245
246         if (!service)
247                 return Empty;
248
249         EventCommand::Ptr eventcommand = service->GetEventCommand();
250
251         if (eventcommand)
252                 return eventcommand->GetName();
253
254         return Empty;
255 }
256
257 Value ServicesTable::PluginOutputAccessor(const Value& row)
258 {
259         Service::Ptr service = static_cast<Service::Ptr>(row);
260
261         if (!service)
262                 return Empty;
263
264         String output;
265         Dictionary::Ptr cr = service->GetLastCheckResult();
266
267         if (cr) {
268                 Dictionary::Ptr output_bag = CompatUtility::GetCheckResultOutput(cr);
269                 output = output_bag->Get("output");
270         }
271
272         return output;
273 }
274
275 Value ServicesTable::LongPluginOutputAccessor(const Value& row)
276 {
277         Service::Ptr service = static_cast<Service::Ptr>(row);
278
279         if (!service)
280                 return Empty;
281
282         String long_output;
283         Dictionary::Ptr cr = service->GetLastCheckResult();
284
285         if (cr) {
286                 Dictionary::Ptr output_bag = CompatUtility::GetCheckResultOutput(cr);
287                 long_output = output_bag->Get("long_output");
288         }
289
290         return long_output;
291 }
292
293 Value ServicesTable::PerfDataAccessor(const Value& row)
294 {
295         Service::Ptr service = static_cast<Service::Ptr>(row);
296
297         if (!service)
298                 return Empty;
299
300         String perfdata;
301         Dictionary::Ptr cr = service->GetLastCheckResult();
302
303         if (cr)
304                 perfdata = CompatUtility::GetCheckResultPerfdata(cr);
305
306         return perfdata;
307 }
308
309 Value ServicesTable::NotificationPeriodAccessor(const Value& row)
310 {
311         Service::Ptr service = static_cast<Service::Ptr>(row);
312
313         if (!service)
314                 return Empty;
315
316         BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
317                 ObjectLock olock(notification);
318
319                 TimePeriod::Ptr timeperiod = notification->GetNotificationPeriod();
320
321                 /* XXX first notification wins */
322                 if (timeperiod)
323                         return timeperiod->GetName();
324         }
325
326         return Empty;
327 }
328
329 Value ServicesTable::CheckPeriodAccessor(const Value& row)
330 {
331         Service::Ptr service = static_cast<Service::Ptr>(row);
332
333         if (!service)
334                 return Empty;
335
336         TimePeriod::Ptr timeperiod = service->GetCheckPeriod();
337
338         if (!timeperiod)
339                 return Empty;
340
341         return timeperiod->GetName();
342 }
343
344 Value ServicesTable::NotesAccessor(const Value& row)
345 {
346         Service::Ptr service = static_cast<Service::Ptr>(row);
347
348         if (!service)
349                 return Empty;
350
351         Dictionary::Ptr custom = service->GetCustom();
352
353         if (!custom)
354                 return Empty;
355
356         return custom->Get("notes");
357 }
358
359 Value ServicesTable::NotesExpandedAccessor(const Value& row)
360 {
361         Service::Ptr service = static_cast<Service::Ptr>(row);
362
363         if (!service)
364                 return Empty;
365
366         Dictionary::Ptr custom = service->GetCustom();
367
368         if (!custom)
369                 return Empty;
370
371         std::vector<MacroResolver::Ptr> resolvers;
372         resolvers.push_back(service);
373         resolvers.push_back(service->GetHost());
374         resolvers.push_back(IcingaApplication::GetInstance());
375
376         Value value = custom->Get("notes");
377
378         Dictionary::Ptr cr;
379         Value value_expanded = MacroProcessor::ResolveMacros(value, resolvers, cr, Utility::EscapeShellCmd);
380
381         return value_expanded;
382 }
383
384 Value ServicesTable::NotesUrlAccessor(const Value& row)
385 {
386         Service::Ptr service = static_cast<Service::Ptr>(row);
387
388         if (!service)
389                 return Empty;
390
391         Dictionary::Ptr custom = service->GetCustom();
392
393         if (!custom)
394                 return Empty;
395
396         return custom->Get("notes_url");
397 }
398
399 Value ServicesTable::NotesUrlExpandedAccessor(const Value& row)
400 {
401         Service::Ptr service = static_cast<Service::Ptr>(row);
402
403         if (!service)
404                 return Empty;
405
406         Dictionary::Ptr custom = service->GetCustom();
407
408         if (!custom)
409                 return Empty;
410
411         std::vector<MacroResolver::Ptr> resolvers;
412         resolvers.push_back(service);
413         resolvers.push_back(service->GetHost());
414         resolvers.push_back(IcingaApplication::GetInstance());
415
416         Value value = custom->Get("notes_url");
417
418         Dictionary::Ptr cr;
419         Value value_expanded = MacroProcessor::ResolveMacros(value, resolvers, cr, Utility::EscapeShellCmd);
420
421         return value_expanded;
422 }
423
424 Value ServicesTable::ActionUrlAccessor(const Value& row)
425 {
426         Service::Ptr service = static_cast<Service::Ptr>(row);
427
428         if (!service)
429                 return Empty;
430
431         Dictionary::Ptr custom = service->GetCustom();
432
433         if (!custom)
434                 return Empty;
435
436         return custom->Get("action_url");
437 }
438
439 Value ServicesTable::ActionUrlExpandedAccessor(const Value& row)
440 {
441         Service::Ptr service = static_cast<Service::Ptr>(row);
442
443         if (!service)
444                 return Empty;
445
446         Dictionary::Ptr custom = service->GetCustom();
447
448         if (!custom)
449                 return Empty;
450
451         std::vector<MacroResolver::Ptr> resolvers;
452         resolvers.push_back(service);
453         resolvers.push_back(service->GetHost());
454         resolvers.push_back(IcingaApplication::GetInstance());
455
456         Value value = custom->Get("action_url");
457
458         Dictionary::Ptr cr;
459         Value value_expanded = MacroProcessor::ResolveMacros(value, resolvers, cr, Utility::EscapeShellCmd);
460
461         return value_expanded;
462 }
463
464 Value ServicesTable::IconImageAccessor(const Value& row)
465 {
466         Service::Ptr service = static_cast<Service::Ptr>(row);
467
468         if (!service)
469                 return Empty;
470
471         Dictionary::Ptr custom = service->GetCustom();
472
473         if (!custom)
474                 return Empty;
475
476         return custom->Get("icon_image");
477 }
478
479 Value ServicesTable::IconImageExpandedAccessor(const Value& row)
480 {
481         Service::Ptr service = static_cast<Service::Ptr>(row);
482
483         if (!service)
484                 return Empty;
485
486         Dictionary::Ptr custom = service->GetCustom();
487
488         if (!custom)
489                 return Empty;
490
491         std::vector<MacroResolver::Ptr> resolvers;
492         resolvers.push_back(service);
493         resolvers.push_back(service->GetHost());
494         resolvers.push_back(IcingaApplication::GetInstance());
495
496         Value value = custom->Get("icon_image");
497
498         Dictionary::Ptr cr;
499         Value value_expanded = MacroProcessor::ResolveMacros(value, resolvers, cr, Utility::EscapeShellCmd);
500
501         return value_expanded;
502 }
503
504 Value ServicesTable::IconImageAltAccessor(const Value& row)
505 {
506         Service::Ptr service = static_cast<Service::Ptr>(row);
507
508         if (!service)
509                 return Empty;
510
511         Dictionary::Ptr custom = service->GetCustom();
512
513         if (!custom)
514                 return Empty;
515
516         return custom->Get("icon_image_alt");
517 }
518
519 Value ServicesTable::MaxCheckAttemptsAccessor(const Value& row)
520 {
521         Service::Ptr service = static_cast<Service::Ptr>(row);
522
523         if (!service)
524                 return Empty;
525
526         return service->GetMaxCheckAttempts();
527 }
528
529 Value ServicesTable::CurrentAttemptAccessor(const Value& row)
530 {
531         Service::Ptr service = static_cast<Service::Ptr>(row);
532
533         if (!service)
534                 return Empty;
535
536         return service->GetCheckAttempt();
537 }
538
539 Value ServicesTable::StateAccessor(const Value& row)
540 {
541         Service::Ptr service = static_cast<Service::Ptr>(row);
542
543         if (!service)
544                 return Empty;
545
546         return service->GetState();
547 }
548
549 Value ServicesTable::HasBeenCheckedAccessor(const Value& row)
550 {
551         Service::Ptr service = static_cast<Service::Ptr>(row);
552
553         if (!service)
554                 return Empty;
555
556         return (service->HasBeenChecked() ? 1 : 0);
557 }
558
559 Value ServicesTable::LastStateAccessor(const Value& row)
560 {
561         Service::Ptr service = static_cast<Service::Ptr>(row);
562
563         if (!service)
564                 return Empty;
565
566         return service->GetLastState();
567 }
568
569 Value ServicesTable::LastHardStateAccessor(const Value& row)
570 {
571         Service::Ptr service = static_cast<Service::Ptr>(row);
572
573         if (!service)
574                 return Empty;
575
576         return service->GetLastHardState();
577 }
578
579 Value ServicesTable::StateTypeAccessor(const Value& row)
580 {
581         Service::Ptr service = static_cast<Service::Ptr>(row);
582
583         if (!service)
584                 return Empty;
585
586         return service->GetStateType();
587 }
588
589 Value ServicesTable::CheckTypeAccessor(const Value& row)
590 {
591         Service::Ptr service = static_cast<Service::Ptr>(row);
592
593         if (!service)
594                 return Empty;
595
596         return (service->GetEnableActiveChecks() ? 0 : 1);
597 }
598
599 Value ServicesTable::AcknowledgedAccessor(const Value& row)
600 {
601         Service::Ptr service = static_cast<Service::Ptr>(row);
602
603         if (!service)
604                 return Empty;
605
606         /* important: lock acknowledgements */
607         ObjectLock olock(service);
608
609         return (service->IsAcknowledged() ? 1 : 0);
610 }
611
612 Value ServicesTable::AcknowledgementTypeAccessor(const Value& row)
613 {
614         Service::Ptr service = static_cast<Service::Ptr>(row);
615
616         if (!service)
617                 return Empty;
618
619         /* important: lock acknowledgements */
620         ObjectLock olock(service);
621
622         return static_cast<int>(service->GetAcknowledgement());
623 }
624
625 Value ServicesTable::NoMoreNotificationsAccessor(const Value& row)
626 {
627         Service::Ptr service = static_cast<Service::Ptr>(row);
628
629         if (!service)
630                 return Empty;
631
632         /* XXX take the smallest notification_interval */
633         double notification_interval = -1;
634         BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
635                 if (notification_interval == -1 || notification->GetNotificationInterval() < notification_interval)
636                         notification_interval = notification->GetNotificationInterval();
637         }
638
639         if (notification_interval == 0 && !service->GetVolatile())
640                 return 1;
641
642         return 0;
643 }
644
645 Value ServicesTable::LastTimeOkAccessor(const Value& row)
646 {
647         Service::Ptr service = static_cast<Service::Ptr>(row);
648
649         if (!service)
650                 return Empty;
651
652         return static_cast<int>(service->GetLastStateOK());
653 }
654
655 Value ServicesTable::LastTimeWarningAccessor(const Value& row)
656 {
657         Service::Ptr service = static_cast<Service::Ptr>(row);
658
659         if (!service)
660                 return Empty;
661
662         return static_cast<int>(service->GetLastStateWarning());
663 }
664
665 Value ServicesTable::LastTimeCriticalAccessor(const Value& row)
666 {
667         Service::Ptr service = static_cast<Service::Ptr>(row);
668
669         if (!service)
670                 return Empty;
671
672         return static_cast<int>(service->GetLastStateCritical());
673 }
674
675 Value ServicesTable::LastTimeUnknownAccessor(const Value& row)
676 {
677         Service::Ptr service = static_cast<Service::Ptr>(row);
678
679         if (!service)
680                 return Empty;
681
682         return static_cast<int>(service->GetLastStateUnknown());
683 }
684
685 Value ServicesTable::LastCheckAccessor(const Value& row)
686 {
687         Service::Ptr service = static_cast<Service::Ptr>(row);
688
689         if (!service)
690                 return Empty;
691
692         return static_cast<int>(service->GetLastCheck());
693 }
694
695 Value ServicesTable::NextCheckAccessor(const Value& row)
696 {
697         Service::Ptr service = static_cast<Service::Ptr>(row);
698
699         if (!service)
700                 return Empty;
701
702         return static_cast<int>(service->GetNextCheck());
703 }
704
705 Value ServicesTable::LastNotificationAccessor(const Value& row)
706 {
707         Service::Ptr service = static_cast<Service::Ptr>(row);
708
709         if (!service)
710                 return Empty;
711
712         /* XXX Service -> Notifications, latest wins */
713         double last_notification = 0;
714         BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
715                 if (notification->GetLastNotification() > last_notification)
716                         last_notification = notification->GetLastNotification();
717         }
718
719         return static_cast<int>(last_notification);
720 }
721
722 Value ServicesTable::NextNotificationAccessor(const Value& row)
723 {
724         Service::Ptr service = static_cast<Service::Ptr>(row);
725
726         if (!service)
727                 return Empty;
728
729         /* XXX Service -> Notifications, latest wins */
730         double next_notification = 0;
731         BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
732                 if (notification->GetNextNotification() < next_notification)
733                         next_notification = notification->GetNextNotification();
734         }
735
736         return static_cast<int>(next_notification);
737 }
738
739 Value ServicesTable::CurrentNotificationNumberAccessor(const Value& row)
740 {
741         Service::Ptr service = static_cast<Service::Ptr>(row);
742
743         if (!service)
744                 return Empty;
745
746         /* XXX Service -> Notifications, biggest wins */
747         int notification_number = 0;
748         BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
749                 if (notification->GetNotificationNumber() > notification_number)
750                         notification_number = notification->GetNotificationNumber();
751         }
752
753         return notification_number;
754 }
755
756 Value ServicesTable::LastStateChangeAccessor(const Value& row)
757 {
758         Service::Ptr service = static_cast<Service::Ptr>(row);
759
760         if (!service)
761                 return Empty;
762
763         return static_cast<int>(service->GetLastStateChange());
764 }
765
766 Value ServicesTable::LastHardStateChangeAccessor(const Value& row)
767 {
768         Service::Ptr service = static_cast<Service::Ptr>(row);
769
770         if (!service)
771                 return Empty;
772
773         return static_cast<int>(service->GetLastHardStateChange());
774 }
775
776 Value ServicesTable::ScheduledDowntimeDepthAccessor(const Value& row)
777 {
778         Service::Ptr service = static_cast<Service::Ptr>(row);
779
780         if (!service)
781                 return Empty;
782
783         return service->GetDowntimeDepth();
784 }
785
786 Value ServicesTable::IsFlappingAccessor(const Value& row)
787 {
788         Service::Ptr service = static_cast<Service::Ptr>(row);
789
790         if (!service)
791                 return Empty;
792
793         return service->IsFlapping();
794 }
795
796 Value ServicesTable::ChecksEnabledAccessor(const Value& row)
797 {
798         Service::Ptr service = static_cast<Service::Ptr>(row);
799
800         if (!service)
801                 return Empty;
802
803         return (service->GetEnableActiveChecks() ? 1 : 0);
804 }
805
806 Value ServicesTable::AcceptPassiveChecksAccessor(const Value& row)
807 {
808         Service::Ptr service = static_cast<Service::Ptr>(row);
809
810         if (!service)
811                 return Empty;
812
813         return (service->GetEnablePassiveChecks() ? 1 : 0);
814 }
815
816 Value ServicesTable::EventHandlerEnabledAccessor(const Value& row)
817 {
818         Service::Ptr service = static_cast<Service::Ptr>(row);
819
820         if (!service)
821                 return Empty;
822
823         EventCommand::Ptr eventcommand = service->GetEventCommand();
824
825         if (eventcommand)
826                 return 1;
827
828         return 0;
829 }
830
831 Value ServicesTable::NotificationsEnabledAccessor(const Value& row)
832 {
833         Service::Ptr service = static_cast<Service::Ptr>(row);
834
835         if (!service)
836                 return Empty;
837
838         return (service->GetEnableNotifications() ? 1 : 0);
839 }
840
841 Value ServicesTable::ActiveChecksEnabledAccessor(const Value& row)
842 {
843         Service::Ptr service = static_cast<Service::Ptr>(row);
844
845         if (!service)
846                 return Empty;
847
848         return (service->GetEnableActiveChecks() ? 1 : 0);
849 }
850
851 Value ServicesTable::CheckOptionsAccessor(const Value& row)
852 {
853         /* TODO - forcexec, freshness, orphan, none */
854         return Empty;
855 }
856
857 Value ServicesTable::FlapDetectionEnabledAccessor(const Value& row)
858 {
859         Service::Ptr service = static_cast<Service::Ptr>(row);
860
861         if (!service)
862                 return Empty;
863
864         return (service->GetEnableFlapping() ? 1 : 0);
865 }
866
867 Value ServicesTable::CheckFreshnessAccessor(const Value& row)
868 {
869         /* always enabled */
870         return 1;
871 }
872
873 Value ServicesTable::ModifiedAttributesAccessor(const Value& row)
874 {
875         Service::Ptr service = static_cast<Service::Ptr>(row);
876
877         if (!service)
878                 return Empty;
879
880         return service->GetModifiedAttributes();
881 }
882
883 Value ServicesTable::ModifiedAttributesListAccessor(const Value& row)
884 {
885         /* not supported */
886         return Empty;
887 }
888
889 Value ServicesTable::StalenessAccessor(const Value& row)
890 {
891         Service::Ptr service = static_cast<Service::Ptr>(row);
892
893         if (!service)
894                 return Empty;
895
896         if (service->HasBeenChecked() && service->GetLastCheck() > 0)
897                 return (Utility::GetTime() - service->GetLastCheck()) / (service->GetCheckInterval() * 3600);
898
899         return Empty;
900 }
901
902 Value ServicesTable::CheckIntervalAccessor(const Value& row)
903 {
904         Service::Ptr service = static_cast<Service::Ptr>(row);
905
906         if (!service)
907                 return Empty;
908
909         return (service->GetCheckInterval() / 60.0);
910 }
911
912 Value ServicesTable::RetryIntervalAccessor(const Value& row)
913 {
914         Service::Ptr service = static_cast<Service::Ptr>(row);
915
916         if (!service)
917                 return Empty;
918
919         return (service->GetRetryInterval() / 60.0);
920 }
921
922 Value ServicesTable::NotificationIntervalAccessor(const Value& row)
923 {
924         Service::Ptr service = static_cast<Service::Ptr>(row);
925
926         if (!service)
927                 return Empty;
928
929         /* XXX take the smallest notification_interval */
930         double notification_interval = -1;
931         BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
932                 if (notification_interval == -1 || notification->GetNotificationInterval() < notification_interval)
933                         notification_interval = notification->GetNotificationInterval();
934         }
935
936         if (notification_interval == -1)
937                 notification_interval = 60;
938
939         return (notification_interval / 60.0);
940 }
941
942 Value ServicesTable::LowFlapThresholdAccessor(const Value& row)
943 {
944         Service::Ptr service = static_cast<Service::Ptr>(row);
945
946         if (!service)
947                 return Empty;
948
949         return service->GetFlappingThreshold();
950 }
951
952 Value ServicesTable::HighFlapThresholdAccessor(const Value& row)
953 {
954         Service::Ptr service = static_cast<Service::Ptr>(row);
955
956         if (!service)
957                 return Empty;
958
959         return service->GetFlappingThreshold();
960 }
961
962 Value ServicesTable::LatencyAccessor(const Value& row)
963 {
964         Service::Ptr service = static_cast<Service::Ptr>(row);
965
966         if (!service)
967                 return Empty;
968
969         return (Service::CalculateLatency(service->GetLastCheckResult()));
970 }
971
972 Value ServicesTable::ExecutionTimeAccessor(const Value& row)
973 {
974         Service::Ptr service = static_cast<Service::Ptr>(row);
975
976         if (!service)
977                 return Empty;
978
979         return (Service::CalculateExecutionTime(service->GetLastCheckResult()));
980 }
981
982 Value ServicesTable::PercentStateChangeAccessor(const Value& row)
983 {
984         Service::Ptr service = static_cast<Service::Ptr>(row);
985
986         if (!service)
987                 return Empty;
988
989         return service->GetFlappingCurrent();
990 }
991
992 Value ServicesTable::InCheckPeriodAccessor(const Value& row)
993 {
994         Service::Ptr service = static_cast<Service::Ptr>(row);
995
996         if (!service)
997                 return Empty;
998
999         TimePeriod::Ptr timeperiod = service->GetCheckPeriod();
1000
1001         /* none set means always checked */
1002         if (!timeperiod)
1003                 return 1;
1004
1005         return (timeperiod->IsInside(Utility::GetTime()) ? 1 : 0);
1006 }
1007
1008 Value ServicesTable::InNotificationPeriodAccessor(const Value& row)
1009 {
1010         Service::Ptr service = static_cast<Service::Ptr>(row);
1011
1012         if (!service)
1013                 return Empty;
1014
1015         BOOST_FOREACH(const Notification::Ptr& notification, service->GetNotifications()) {
1016                 ObjectLock olock(notification);
1017
1018                 TimePeriod::Ptr timeperiod = notification->GetNotificationPeriod();
1019
1020                 /* XXX first notification wins */
1021                 if (timeperiod)
1022                         return (timeperiod->IsInside(Utility::GetTime()) ? 1 : 0);
1023         }
1024
1025         /* none set means always notified */
1026         return 1;
1027 }
1028
1029 Value ServicesTable::ContactsAccessor(const Value& row)
1030 {
1031         Service::Ptr service = static_cast<Service::Ptr>(row);
1032
1033         if (!service)
1034                 return Empty;
1035
1036         Array::Ptr contact_names = boost::make_shared<Array>();
1037
1038         BOOST_FOREACH(const User::Ptr& user, CompatUtility::GetServiceNotificationUsers(service)) {
1039                 contact_names->Add(user->GetName());
1040         }
1041
1042         return contact_names;
1043 }
1044
1045 Value ServicesTable::DowntimesAccessor(const Value& row)
1046 {
1047         Service::Ptr service = static_cast<Service::Ptr>(row);
1048
1049         if (!service)
1050                 return Empty;
1051
1052         Dictionary::Ptr downtimes = service->GetDowntimes();
1053
1054         Array::Ptr ids = boost::make_shared<Array>();
1055
1056         ObjectLock olock(downtimes);
1057
1058         String id;
1059         Dictionary::Ptr downtime;
1060         BOOST_FOREACH(boost::tie(id, downtime), downtimes) {
1061
1062                 if (!downtime)
1063                         continue;
1064
1065                 if (Service::IsDowntimeExpired(downtime))
1066                         continue;
1067
1068                 ids->Add(downtime->Get("legacy_id"));
1069         }
1070
1071         return ids;
1072 }
1073
1074 Value ServicesTable::DowntimesWithInfoAccessor(const Value& row)
1075 {
1076         Service::Ptr service = static_cast<Service::Ptr>(row);
1077
1078         if (!service)
1079                 return Empty;
1080
1081         Dictionary::Ptr downtimes = service->GetDowntimes();
1082
1083         Array::Ptr ids = boost::make_shared<Array>();
1084
1085         ObjectLock olock(downtimes);
1086
1087         String id;
1088         Dictionary::Ptr downtime;
1089         BOOST_FOREACH(boost::tie(id, downtime), downtimes) {
1090
1091                 if (!downtime)
1092                         continue;
1093
1094                 if (Service::IsDowntimeExpired(downtime))
1095                         continue;
1096
1097                 Array::Ptr downtime_info = boost::make_shared<Array>();
1098                 downtime_info->Add(downtime->Get("legacy_id"));
1099                 downtime_info->Add(downtime->Get("author"));
1100                 downtime_info->Add(downtime->Get("comment"));
1101                 ids->Add(downtime_info);
1102         }
1103
1104         return ids;
1105 }
1106
1107 Value ServicesTable::CommentsAccessor(const Value& row)
1108 {
1109         Service::Ptr service = static_cast<Service::Ptr>(row);
1110
1111         if (!service)
1112                 return Empty;
1113
1114         Dictionary::Ptr comments = service->GetComments();
1115
1116         Array::Ptr ids = boost::make_shared<Array>();
1117
1118         ObjectLock olock(comments);
1119
1120         String id;
1121         Dictionary::Ptr comment;
1122         BOOST_FOREACH(boost::tie(id, comment), comments) {
1123
1124                 if (!comment)
1125                         continue;
1126
1127                 if (Service::IsCommentExpired(comment))
1128                         continue;
1129
1130                 ids->Add(comment->Get("legacy_id"));
1131         }
1132
1133         return ids;
1134 }
1135
1136 Value ServicesTable::CommentsWithInfoAccessor(const Value& row)
1137 {
1138         Service::Ptr service = static_cast<Service::Ptr>(row);
1139
1140         if (!service)
1141                 return Empty;
1142
1143         Dictionary::Ptr comments = service->GetComments();
1144
1145         Array::Ptr ids = boost::make_shared<Array>();
1146
1147         ObjectLock olock(comments);
1148
1149         String id;
1150         Dictionary::Ptr comment;
1151         BOOST_FOREACH(boost::tie(id, comment), comments) {
1152
1153                 if (!comment)
1154                         continue;
1155
1156                 if (Service::IsCommentExpired(comment))
1157                         continue;
1158
1159                 Array::Ptr comment_info = boost::make_shared<Array>();
1160                 comment_info->Add(comment->Get("legacy_id"));
1161                 comment_info->Add(comment->Get("author"));
1162                 comment_info->Add(comment->Get("text"));
1163                 ids->Add(comment_info);
1164         }
1165
1166         return ids;
1167 }
1168
1169 Value ServicesTable::CommentsWithExtraInfoAccessor(const Value& row)
1170 {
1171         Service::Ptr service = static_cast<Service::Ptr>(row);
1172
1173         if (!service)
1174                 return Empty;
1175
1176         Dictionary::Ptr comments = service->GetComments();
1177
1178         Array::Ptr ids = boost::make_shared<Array>();
1179
1180         ObjectLock olock(comments);
1181
1182         String id;
1183         Dictionary::Ptr comment;
1184         BOOST_FOREACH(boost::tie(id, comment), comments) {
1185
1186                 if (!comment)
1187                         continue;
1188
1189                 if (Service::IsCommentExpired(comment))
1190                         continue;
1191
1192                 Array::Ptr comment_info = boost::make_shared<Array>();
1193                 comment_info->Add(comment->Get("legacy_id"));
1194                 comment_info->Add(comment->Get("author"));
1195                 comment_info->Add(comment->Get("text"));
1196                 comment_info->Add(comment->Get("entry_type"));
1197                 comment_info->Add(static_cast<int>(comment->Get("entry_time")));
1198                 ids->Add(comment_info);
1199         }
1200
1201         return ids;
1202 }
1203
1204 Value ServicesTable::CustomVariableNamesAccessor(const Value& row)
1205 {
1206         Service::Ptr service = static_cast<Service::Ptr>(row);
1207
1208         if (!service)
1209                 return Empty;
1210
1211         Dictionary::Ptr customvars;
1212
1213         {
1214                 ObjectLock olock(service);
1215                 customvars = CompatUtility::GetCustomVariableConfig(service);
1216         }
1217
1218         if (!customvars)
1219                 return Empty;
1220
1221         Array::Ptr cv = boost::make_shared<Array>();
1222
1223         String key;
1224         Value value;
1225         BOOST_FOREACH(boost::tie(key, value), customvars) {
1226                 cv->Add(key);
1227         }
1228
1229         return cv;
1230 }
1231
1232 Value ServicesTable::CustomVariableValuesAccessor(const Value& row)
1233 {
1234         Service::Ptr service = static_cast<Service::Ptr>(row);
1235
1236         if (!service)
1237                 return Empty;
1238
1239         Dictionary::Ptr customvars;
1240
1241         {
1242                 ObjectLock olock(service);
1243                 customvars = CompatUtility::GetCustomVariableConfig(service);
1244         }
1245
1246         if (!customvars)
1247                 return Empty;
1248
1249         Array::Ptr cv = boost::make_shared<Array>();
1250
1251         String key;
1252         Value value;
1253         BOOST_FOREACH(boost::tie(key, value), customvars) {
1254                 cv->Add(value);
1255         }
1256
1257         return cv;
1258 }
1259
1260 Value ServicesTable::CustomVariablesAccessor(const Value& row)
1261 {
1262         Service::Ptr service = static_cast<Service::Ptr>(row);
1263
1264         if (!service)
1265                 return Empty;
1266
1267         Dictionary::Ptr customvars;
1268
1269         {
1270                 ObjectLock olock(service);
1271                 customvars = CompatUtility::GetCustomVariableConfig(service);
1272         }
1273
1274         if (!customvars)
1275                 return Empty;
1276
1277         Array::Ptr cv = boost::make_shared<Array>();
1278
1279         String key;
1280         Value value;
1281         BOOST_FOREACH(boost::tie(key, value), customvars) {
1282                 Array::Ptr key_val = boost::make_shared<Array>();
1283                 key_val->Add(key);
1284                 key_val->Add(value);
1285                 cv->Add(key_val);
1286         }
1287
1288         return cv;
1289 }
1290
1291 Value ServicesTable::GroupsAccessor(const Value& row)
1292 {
1293         Service::Ptr service = static_cast<Service::Ptr>(row);
1294
1295         if (!service)
1296                 return Empty;
1297
1298         Array::Ptr groups = service->GetGroups();
1299
1300         if (!groups)
1301                 return Empty;
1302
1303         return groups;
1304 }
1305
1306 Value ServicesTable::ContactGroupsAccessor(const Value& row)
1307 {
1308         Service::Ptr service = static_cast<Service::Ptr>(row);
1309
1310         if (!service)
1311                 return Empty;
1312
1313         Array::Ptr contactgroup_names = boost::make_shared<Array>();
1314
1315         BOOST_FOREACH(const UserGroup::Ptr& usergroup, CompatUtility::GetServiceNotificationUserGroups(service)) {
1316                 contactgroup_names->Add(usergroup->GetName());
1317         }
1318
1319         return contactgroup_names;
1320 }
1321
1322