]> granicus.if.org Git - icinga2/blob - lib/icinga/pluginutility.cpp
8358547030474188d261c120b778a8bf952172f7
[icinga2] / lib / icinga / pluginutility.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/)  *
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 "icinga/pluginutility.hpp"
21 #include "icinga/macroprocessor.hpp"
22 #include "icinga/perfdatavalue.hpp"
23 #include "base/logger.hpp"
24 #include "base/utility.hpp"
25 #include "base/convert.hpp"
26 #include "base/process.hpp"
27 #include "base/objectlock.hpp"
28 #include "base/exception.hpp"
29 #include <boost/algorithm/string/classification.hpp>
30 #include <boost/algorithm/string/split.hpp>
31 #include <boost/algorithm/string/trim.hpp>
32
33 using namespace icinga;
34
35 void PluginUtility::ExecuteCommand(const Command::Ptr& commandObj, const Checkable::Ptr& checkable,
36     const CheckResult::Ptr& cr, const MacroProcessor::ResolverList& macroResolvers,
37     const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros,
38     const boost::function<void(const Value& commandLine, const ProcessResult&)>& callback)
39 {
40         Value raw_command = commandObj->GetCommandLine();
41         Dictionary::Ptr raw_arguments = commandObj->GetArguments();
42
43         Value command;
44
45         try {
46                 command = MacroProcessor::ResolveArguments(raw_command, raw_arguments,
47                     macroResolvers, cr, resolvedMacros, useResolvedMacros);
48         } catch (const std::exception& ex) {
49                 String message = DiagnosticInformation(ex);
50
51                 Log(LogWarning, "PluginUtility", message);
52
53                 if (callback) {
54                         ProcessResult pr;
55                         pr.PID = -1;
56                         pr.ExecutionStart = Utility::GetTime();
57                         pr.ExecutionEnd = pr.ExecutionStart;
58                         pr.ExitStatus = 3; /* Unknown */
59                         pr.Output = message;
60                         callback(Empty, pr);
61                 }
62
63                 return;
64         }
65
66         Dictionary::Ptr envMacros = new Dictionary();
67
68         Dictionary::Ptr env = commandObj->GetEnv();
69
70         if (env) {
71                 ObjectLock olock(env);
72                 for (const Dictionary::Pair& kv : env) {
73                         String name = kv.second;
74
75                         Value value = MacroProcessor::ResolveMacros(name, macroResolvers, cr,
76                             NULL, MacroProcessor::EscapeCallback(), resolvedMacros,
77                             useResolvedMacros);
78
79                         if (value.IsObjectType<Array>())
80                                 value = Utility::Join(value, ';');
81
82                         envMacros->Set(kv.first, value);
83                 }
84         }
85
86         if (resolvedMacros && !useResolvedMacros)
87                 return;
88
89         Process::Ptr process = new Process(Process::PrepareCommand(command), envMacros);
90
91         if (checkable->GetCheckTimeout().IsEmpty())
92                 process->SetTimeout(commandObj->GetTimeout());
93         else
94                 process->SetTimeout(checkable->GetCheckTimeout());
95
96         process->SetAdjustPriority(true);
97
98         process->Run(boost::bind(callback, command, _1));
99 }
100
101 ServiceState PluginUtility::ExitStatusToState(int exitStatus)
102 {
103         switch (exitStatus) {
104                 case 0:
105                         return ServiceOK;
106                 case 1:
107                         return ServiceWarning;
108                 case 2:
109                         return ServiceCritical;
110                 default:
111                         return ServiceUnknown;
112         }
113 }
114
115 std::pair<String, String> PluginUtility::ParseCheckOutput(const String& output)
116 {
117         String text;
118         String perfdata;
119
120         std::vector<String> lines;
121         boost::algorithm::split(lines, output, boost::is_any_of("\r\n"));
122
123         for (const String& line : lines) {
124                 size_t delim = line.FindFirstOf("|");
125
126                 if (!text.IsEmpty())
127                         text += "\n";
128
129                 if (delim != String::NPos) {
130                         text += line.SubStr(0, delim);
131
132                         if (!perfdata.IsEmpty())
133                                 perfdata += " ";
134
135                         perfdata += line.SubStr(delim + 1, line.GetLength());
136                 } else {
137                         text += line;
138                 }
139         }
140
141         boost::algorithm::trim(perfdata);
142
143         return std::make_pair(text, perfdata);
144 }
145
146 Array::Ptr PluginUtility::SplitPerfdata(const String& perfdata)
147 {
148         Array::Ptr result = new Array();
149
150         size_t begin = 0;
151         String multi_prefix;
152
153         for (;;) {
154                 size_t eqp = perfdata.FindFirstOf('=', begin);
155
156                 if (eqp == String::NPos)
157                         break;
158
159                 String label = perfdata.SubStr(begin, eqp - begin);
160
161                 if (label.GetLength() > 2 && label[0] == '\'' && label[label.GetLength() - 1] == '\'')
162                         label = label.SubStr(1, label.GetLength() - 2);
163
164                 size_t multi_index = label.RFind("::");
165
166                 if (multi_index != String::NPos)
167                         multi_prefix = "";
168
169                 size_t spq = perfdata.FindFirstOf(' ', eqp);
170
171                 if (spq == String::NPos)
172                         spq = perfdata.GetLength();
173
174                 String value = perfdata.SubStr(eqp + 1, spq - eqp - 1);
175
176                 if (!multi_prefix.IsEmpty())
177                         label = multi_prefix + "::" + label;
178
179                 String pdv;
180                 if (label.FindFirstOf(" ") != String::NPos)
181                         pdv = "'" + label + "'=" + value;
182                 else
183                         pdv = label + "=" + value;
184
185                 result->Add(pdv);
186
187                 if (multi_index != String::NPos)
188                         multi_prefix = label.SubStr(0, multi_index);
189
190                 begin = spq + 1;
191         }
192
193         return result;
194 }
195
196 String PluginUtility::FormatPerfdata(const Array::Ptr& perfdata)
197 {
198         if (!perfdata)
199                 return "";
200
201         std::ostringstream result;
202
203         ObjectLock olock(perfdata);
204
205         bool first = true;
206         for (const Value& pdv : perfdata) {
207                 if (!first)
208                         result << " ";
209                 else
210                         first = false;
211
212                 if (pdv.IsObjectType<PerfdataValue>())
213                         result << static_cast<PerfdataValue::Ptr>(pdv)->Format();
214                 else
215                         result << pdv;
216         }
217
218         return result.str();
219 }