]> granicus.if.org Git - icinga2/blob - lib/db_ido/idochecktask.cpp
Merge pull request #7591 from Icinga/feature/docs-api-joins
[icinga2] / lib / db_ido / idochecktask.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "db_ido/idochecktask.hpp"
4 #include "icinga/host.hpp"
5 #include "icinga/checkcommand.hpp"
6 #include "icinga/macroprocessor.hpp"
7 #include "remote/apilistener.hpp"
8 #include "remote/endpoint.hpp"
9 #include "remote/zone.hpp"
10 #include "base/function.hpp"
11 #include "base/utility.hpp"
12 #include "base/perfdatavalue.hpp"
13 #include "base/configtype.hpp"
14 #include "base/convert.hpp"
15
16 using namespace icinga;
17
18 REGISTER_FUNCTION_NONCONST(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
19
20 void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
21         const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
22 {
23         CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
24         Value raw_command = commandObj->GetCommandLine();
25
26         Host::Ptr host;
27         Service::Ptr service;
28         tie(host, service) = GetHostService(checkable);
29
30         MacroProcessor::ResolverList resolvers;
31         if (service)
32                 resolvers.emplace_back("service", service);
33         resolvers.emplace_back("host", host);
34         resolvers.emplace_back("command", commandObj);
35         resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
36
37         String idoType = MacroProcessor::ResolveMacros("$ido_type$", resolvers, checkable->GetLastCheckResult(),
38                 nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
39
40         String idoName = MacroProcessor::ResolveMacros("$ido_name$", resolvers, checkable->GetLastCheckResult(),
41                 nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
42
43         String missingQueriesWarning;
44         String missingQueriesCritical;
45         String missingPendingQueriesWarning;
46         String missingPendingQueriesCritical;
47
48         double queriesWarning = MacroProcessor::ResolveMacros("$ido_queries_warning$", resolvers, checkable->GetLastCheckResult(),
49             &missingQueriesWarning, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
50
51         double queriesCritical = MacroProcessor::ResolveMacros("$ido_queries_critical$", resolvers, checkable->GetLastCheckResult(),
52             &missingQueriesCritical, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
53
54         double pendingQueriesWarning = MacroProcessor::ResolveMacros("$ido_pending_queries_warning$", resolvers, checkable->GetLastCheckResult(),
55             &missingPendingQueriesWarning, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
56
57         double pendingQueriesCritical = MacroProcessor::ResolveMacros("$ido_pending_queries_critical$", resolvers, checkable->GetLastCheckResult(),
58             &missingPendingQueriesCritical, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
59
60         if (resolvedMacros && !useResolvedMacros)
61                 return;
62
63         if (idoType.IsEmpty()) {
64                 cr->SetOutput("Attribute 'ido_type' must be set.");
65                 cr->SetState(ServiceUnknown);
66                 checkable->ProcessCheckResult(cr);
67                 return;
68         }
69
70         if (idoName.IsEmpty()) {
71                 cr->SetOutput("Attribute 'ido_name' must be set.");
72                 cr->SetState(ServiceUnknown);
73                 checkable->ProcessCheckResult(cr);
74                 return;
75         }
76
77         Type::Ptr type = Type::GetByName(idoType);
78
79         if (!type || !DbConnection::TypeInstance->IsAssignableFrom(type)) {
80                 cr->SetOutput("DB IDO type '" + idoType + "' is invalid.");
81                 cr->SetState(ServiceUnknown);
82                 checkable->ProcessCheckResult(cr);
83                 return;
84         }
85
86         auto *dtype = dynamic_cast<ConfigType *>(type.get());
87         VERIFY(dtype);
88
89         DbConnection::Ptr conn = static_pointer_cast<DbConnection>(dtype->GetObject(idoName));
90
91         if (!conn) {
92                 cr->SetOutput("DB IDO connection '" + idoName + "' does not exist.");
93                 cr->SetState(ServiceUnknown);
94                 checkable->ProcessCheckResult(cr);
95                 return;
96         }
97
98         double qps = conn->GetQueryCount(60) / 60.0;
99
100         if (conn->IsPaused()) {
101                 cr->SetOutput("DB IDO connection is temporarily disabled on this cluster instance.");
102                 cr->SetState(ServiceOK);
103                 checkable->ProcessCheckResult(cr);
104                 return;
105         }
106
107         double pendingQueries = conn->GetPendingQueryCount();
108
109         if (!conn->GetConnected()) {
110                 if (conn->GetShouldConnect()) {
111                         cr->SetOutput("Could not connect to the database server.");
112                         cr->SetState(ServiceCritical);
113                 } else {
114                         cr->SetOutput("Not currently enabled: Another cluster instance is responsible for the IDO database.");
115                         cr->SetState(ServiceOK);
116                 }
117
118                 checkable->ProcessCheckResult(cr);
119
120                 return;
121         }
122
123         /* Schema versions. */
124         String schema_version = conn->GetSchemaVersion();
125         std::ostringstream msgbuf;
126
127         if (Utility::CompareVersion(IDO_CURRENT_SCHEMA_VERSION, schema_version) < 0) {
128                 msgbuf << "Outdated schema version: '" << schema_version << "'. Latest version: '"
129                     << IDO_CURRENT_SCHEMA_VERSION << "'."
130                     << " Queries per second: " << std::fixed << std::setprecision(3) << qps
131                     << " Pending queries: " << std::fixed << std::setprecision(3) << pendingQueries << ".";
132
133                 cr->SetState(ServiceWarning);
134         } else {
135                 msgbuf << "Connected to the database server (Schema version: '" << schema_version << "')."
136                     << " Queries per second: " << std::fixed << std::setprecision(3) << qps
137                     << " Pending queries: " << std::fixed << std::setprecision(3) << pendingQueries << ".";
138
139                 cr->SetState(ServiceOK);
140         }
141
142         if (conn->GetEnableHa()) {
143                 double failoverTs = conn->GetLastFailover();
144
145                 msgbuf << " Last failover: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", failoverTs) << ".";
146         }
147
148         /* Check whether the thresholds have been defined and match. */
149         if (missingQueriesCritical.IsEmpty() && qps < queriesCritical) {
150                 msgbuf << " " << qps << " queries/s lower than critical threshold (" << queriesCritical << " queries/s).";
151
152                 cr->SetState(ServiceCritical);
153         } else if (missingQueriesWarning.IsEmpty() && qps < queriesWarning) {
154                 msgbuf << " " << qps << " queries/s lower than warning threshold (" << queriesWarning << " queries/s).";
155
156                 cr->SetState(ServiceWarning);
157         }
158
159         if (missingPendingQueriesCritical.IsEmpty() && pendingQueries > pendingQueriesCritical) {
160                 msgbuf << " " << pendingQueries << " pending queries greater than critical threshold ("
161                     << pendingQueriesCritical << " queries).";
162
163                 cr->SetState(ServiceCritical);
164         } else if (missingPendingQueriesWarning.IsEmpty() && pendingQueries > pendingQueriesWarning) {
165                 msgbuf << " " << pendingQueries << " pending queries greater than warning threshold ("
166                     << pendingQueriesWarning << " queries).";
167
168                 cr->SetState(ServiceWarning);
169         }
170
171         cr->SetOutput(msgbuf.str());
172
173         cr->SetPerformanceData(new Array({
174                 { new PerfdataValue("queries", qps, false, "", queriesWarning, queriesCritical) },
175                 { new PerfdataValue("queries_1min", conn->GetQueryCount(60)) },
176                 { new PerfdataValue("queries_5mins", conn->GetQueryCount(5 * 60)) },
177                 { new PerfdataValue("queries_15mins", conn->GetQueryCount(15 * 60)) },
178                 { new PerfdataValue("pending_queries", pendingQueries, false, "", pendingQueriesWarning, pendingQueriesCritical) }
179         }));
180
181         checkable->ProcessCheckResult(cr);
182 }