1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "methods/clusterzonechecktask.hpp"
4 #include "icinga/checkcommand.hpp"
5 #include "icinga/macroprocessor.hpp"
6 #include "remote/apilistener.hpp"
7 #include "remote/endpoint.hpp"
8 #include "remote/zone.hpp"
9 #include "base/function.hpp"
10 #include "base/utility.hpp"
11 #include "base/perfdatavalue.hpp"
12
13 using namespace icinga;
14
15 REGISTER_FUNCTION_NONCONST(Internal, ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
16
ScriptFunc(const Checkable::Ptr & checkable,const CheckResult::Ptr & cr,const Dictionary::Ptr & resolvedMacros,bool useResolvedMacros)17 void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
18 const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
19 {
20 REQUIRE_NOT_NULL(checkable);
21 REQUIRE_NOT_NULL(cr);
22
23 ApiListener::Ptr listener = ApiListener::GetInstance();
24 CheckCommand::Ptr command = CheckCommand::ExecuteOverride ? CheckCommand::ExecuteOverride : checkable->GetCheckCommand();
25 String commandName = command->GetName();
26
27 if (!listener) {
28 String output = "No API listener is configured for this instance.";
29 ServiceState state = ServiceUnknown;
30
31 if (Checkable::ExecuteCommandProcessFinishedHandler) {
32 double now = Utility::GetTime();
33 ProcessResult pr;
34 pr.PID = -1;
35 pr.Output = output;
36 pr.ExecutionStart = now;
37 pr.ExecutionEnd = now;
38 pr.ExitStatus = state;
39
40 Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr);
41 } else {
42 cr->SetCommand(commandName);
43 cr->SetOutput(output);
44 cr->SetState(state);
45 checkable->ProcessCheckResult(cr);
46 }
47
48 return;
49 }
50
51 Value raw_command = command->GetCommandLine();
52
53 Host::Ptr host;
54 Service::Ptr service;
55 tie(host, service) = GetHostService(checkable);
56
57 MacroProcessor::ResolverList resolvers;
58
59 if (MacroResolver::OverrideMacros)
60 resolvers.emplace_back("override", MacroResolver::OverrideMacros);
61
62 if (service)
63 resolvers.emplace_back("service", service);
64 resolvers.emplace_back("host", host);
65 resolvers.emplace_back("command", command);
66 resolvers.emplace_back("icinga", IcingaApplication::GetInstance());
67
68 String zoneName = MacroProcessor::ResolveMacros("$cluster_zone$", resolvers, checkable->GetLastCheckResult(),
69 nullptr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
70
71 String missingLagWarning;
72 String missingLagCritical;
73
74 double lagWarning = MacroProcessor::ResolveMacros("$cluster_lag_warning$", resolvers, checkable->GetLastCheckResult(),
75 &missingLagWarning, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
76
77 double lagCritical = MacroProcessor::ResolveMacros("$cluster_lag_critical$", resolvers, checkable->GetLastCheckResult(),
78 &missingLagCritical, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros);
79
80 if (resolvedMacros && !useResolvedMacros)
81 return;
82
83 if (zoneName.IsEmpty()) {
84 String output = "Macro 'cluster_zone' must be set.";
85 ServiceState state = ServiceUnknown;
86
87 if (Checkable::ExecuteCommandProcessFinishedHandler) {
88 double now = Utility::GetTime();
89 ProcessResult pr;
90 pr.PID = -1;
91 pr.Output = output;
92 pr.ExecutionStart = now;
93 pr.ExecutionEnd = now;
94 pr.ExitStatus = state;
95
96 Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr);
97 } else {
98 cr->SetCommand(commandName);
99 cr->SetOutput(output);
100 cr->SetState(state);
101 checkable->ProcessCheckResult(cr);
102 }
103
104 return;
105 }
106
107 Zone::Ptr zone = Zone::GetByName(zoneName);
108
109 if (!zone) {
110 String output = "Zone '" + zoneName + "' does not exist.";
111 ServiceState state = ServiceUnknown;
112
113 if (Checkable::ExecuteCommandProcessFinishedHandler) {
114 double now = Utility::GetTime();
115 ProcessResult pr;
116 pr.PID = -1;
117 pr.Output = output;
118 pr.ExecutionStart = now;
119 pr.ExecutionEnd = now;
120 pr.ExitStatus = state;
121
122 Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr);
123 } else {
124 cr->SetCommand(commandName);
125 cr->SetOutput(output);
126 cr->SetState(state);
127 checkable->ProcessCheckResult(cr);
128 }
129 return;
130 }
131
132 bool connected = false;
133 double zoneLag = 0;
134
135 double lastMessageSent = 0;
136 double lastMessageReceived = 0;
137 double messagesSentPerSecond = 0;
138 double messagesReceivedPerSecond = 0;
139 double bytesSentPerSecond = 0;
140 double bytesReceivedPerSecond = 0;
141
142 for (const Endpoint::Ptr& endpoint : zone->GetEndpoints()) {
143 if (endpoint->GetConnected())
144 connected = true;
145
146 double eplag = ApiListener::CalculateZoneLag(endpoint);
147
148 if (eplag > 0 && eplag > zoneLag)
149 zoneLag = eplag;
150
151 if (endpoint->GetLastMessageSent() > lastMessageSent)
152 lastMessageSent = endpoint->GetLastMessageSent();
153
154 if (endpoint->GetLastMessageReceived() > lastMessageReceived)
155 lastMessageReceived = endpoint->GetLastMessageReceived();
156
157 messagesSentPerSecond += endpoint->GetMessagesSentPerSecond();
158 messagesReceivedPerSecond += endpoint->GetMessagesReceivedPerSecond();
159 bytesSentPerSecond += endpoint->GetBytesSentPerSecond();
160 bytesReceivedPerSecond += endpoint->GetBytesReceivedPerSecond();
161 }
162
163 ServiceState state;
164 String output;
165
166 if (connected) {
167 state = ServiceOK;
168 output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag);
169
170 /* Check whether the thresholds have been resolved and compare them */
171 if (missingLagCritical.IsEmpty() && zoneLag > lagCritical) {
172 state = ServiceCritical;
173 output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag)
174 + " greater than critical threshold: " + Utility::FormatDuration(lagCritical);
175 } else if (missingLagWarning.IsEmpty() && zoneLag > lagWarning) {
176 state = ServiceWarning;
177 output = "Zone '" + zoneName + "' is connected. Log lag: " + Utility::FormatDuration(zoneLag)
178 + " greater than warning threshold: " + Utility::FormatDuration(lagWarning);
179 }
180 } else {
181 state = ServiceCritical;
182 output = "Zone '" + zoneName + "' is not connected. Log lag: " + Utility::FormatDuration(zoneLag);
183 }
184
185 if (Checkable::ExecuteCommandProcessFinishedHandler) {
186 double now = Utility::GetTime();
187 ProcessResult pr;
188 pr.PID = -1;
189 pr.Output = output;
190 pr.ExecutionStart = now;
191 pr.ExecutionEnd = now;
192 pr.ExitStatus = state;
193
194 Checkable::ExecuteCommandProcessFinishedHandler(commandName, pr);
195 } else {
196 cr->SetCommand(commandName);
197 cr->SetState(state);
198 cr->SetOutput(output);
199 cr->SetPerformanceData(new Array({
200 new PerfdataValue("slave_lag", zoneLag, false, "s", lagWarning, lagCritical),
201 new PerfdataValue("last_messages_sent", lastMessageSent),
202 new PerfdataValue("last_messages_received", lastMessageReceived),
203 new PerfdataValue("sum_messages_sent_per_second", messagesSentPerSecond),
204 new PerfdataValue("sum_messages_received_per_second", messagesReceivedPerSecond),
205 new PerfdataValue("sum_bytes_sent_per_second", bytesSentPerSecond),
206 new PerfdataValue("sum_bytes_received_per_second", bytesReceivedPerSecond)
207 }));
208
209 checkable->ProcessCheckResult(cr);
210 }
211 }
212