1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
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"
16 using namespace icinga;
18 REGISTER_FUNCTION_NONCONST(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
20 void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
21 const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
23 CheckCommand::Ptr commandObj = checkable->GetCheckCommand();
24 Value raw_command = commandObj->GetCommandLine();
28 tie(host, service) = GetHostService(checkable);
30 MacroProcessor::ResolverList resolvers;
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());
37 String idoType = MacroProcessor::ResolveMacros("$ido_type$", resolvers, checkable->GetLastCheckResult(),
38 nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
40 String idoName = MacroProcessor::ResolveMacros("$ido_name$", resolvers, checkable->GetLastCheckResult(),
41 nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
43 String missingQueriesWarning;
44 String missingQueriesCritical;
45 String missingPendingQueriesWarning;
46 String missingPendingQueriesCritical;
48 double queriesWarning = MacroProcessor::ResolveMacros("$ido_queries_warning$", resolvers, checkable->GetLastCheckResult(),
49 &missingQueriesWarning, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
51 double queriesCritical = MacroProcessor::ResolveMacros("$ido_queries_critical$", resolvers, checkable->GetLastCheckResult(),
52 &missingQueriesCritical, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
54 double pendingQueriesWarning = MacroProcessor::ResolveMacros("$ido_pending_queries_warning$", resolvers, checkable->GetLastCheckResult(),
55 &missingPendingQueriesWarning, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
57 double pendingQueriesCritical = MacroProcessor::ResolveMacros("$ido_pending_queries_critical$", resolvers, checkable->GetLastCheckResult(),
58 &missingPendingQueriesCritical, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
60 if (resolvedMacros && !useResolvedMacros)
63 if (idoType.IsEmpty()) {
64 cr->SetOutput("Attribute 'ido_type' must be set.");
65 cr->SetState(ServiceUnknown);
66 checkable->ProcessCheckResult(cr);
70 if (idoName.IsEmpty()) {
71 cr->SetOutput("Attribute 'ido_name' must be set.");
72 cr->SetState(ServiceUnknown);
73 checkable->ProcessCheckResult(cr);
77 Type::Ptr type = Type::GetByName(idoType);
79 if (!type || !DbConnection::TypeInstance->IsAssignableFrom(type)) {
80 cr->SetOutput("DB IDO type '" + idoType + "' is invalid.");
81 cr->SetState(ServiceUnknown);
82 checkable->ProcessCheckResult(cr);
86 auto *dtype = dynamic_cast<ConfigType *>(type.get());
89 DbConnection::Ptr conn = static_pointer_cast<DbConnection>(dtype->GetObject(idoName));
92 cr->SetOutput("DB IDO connection '" + idoName + "' does not exist.");
93 cr->SetState(ServiceUnknown);
94 checkable->ProcessCheckResult(cr);
98 double qps = conn->GetQueryCount(60) / 60.0;
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);
107 double pendingQueries = conn->GetPendingQueryCount();
109 if (!conn->GetConnected()) {
110 if (conn->GetShouldConnect()) {
111 cr->SetOutput("Could not connect to the database server.");
112 cr->SetState(ServiceCritical);
114 cr->SetOutput("Not currently enabled: Another cluster instance is responsible for the IDO database.");
115 cr->SetState(ServiceOK);
118 checkable->ProcessCheckResult(cr);
123 /* Schema versions. */
124 String schema_version = conn->GetSchemaVersion();
125 std::ostringstream msgbuf;
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 << ".";
133 cr->SetState(ServiceWarning);
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 << ".";
139 cr->SetState(ServiceOK);
142 if (conn->GetEnableHa()) {
143 double failoverTs = conn->GetLastFailover();
145 msgbuf << " Last failover: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", failoverTs) << ".";
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).";
152 cr->SetState(ServiceCritical);
153 } else if (missingQueriesWarning.IsEmpty() && qps < queriesWarning) {
154 msgbuf << " " << qps << " queries/s lower than warning threshold (" << queriesWarning << " queries/s).";
156 cr->SetState(ServiceWarning);
159 if (missingPendingQueriesCritical.IsEmpty() && pendingQueries > pendingQueriesCritical) {
160 msgbuf << " " << pendingQueries << " pending queries greater than critical threshold ("
161 << pendingQueriesCritical << " queries).";
163 cr->SetState(ServiceCritical);
164 } else if (missingPendingQueriesWarning.IsEmpty() && pendingQueries > pendingQueriesWarning) {
165 msgbuf << " " << pendingQueries << " pending queries greater than warning threshold ("
166 << pendingQueriesWarning << " queries).";
168 cr->SetState(ServiceWarning);
171 cr->SetOutput(msgbuf.str());
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) }
181 checkable->ProcessCheckResult(cr);