aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/apt-panopticon-nagios.lua
diff options
context:
space:
mode:
authoronefang2019-12-26 00:36:28 +1000
committeronefang2019-12-26 00:36:28 +1000
commitb81e5c82e5fc32246a2da0cf656baa7d1dc635da (patch)
treefa070092460778ff81f476801c078734afb42172 /apt-panopticon-nagios.lua
parentProper Updated check. (diff)
downloadapt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.zip
apt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.tar.gz
apt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.tar.bz2
apt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.tar.xz
Add a Icinga/Nagios script.
Diffstat (limited to 'apt-panopticon-nagios.lua')
-rwxr-xr-xapt-panopticon-nagios.lua320
1 files changed, 320 insertions, 0 deletions
diff --git a/apt-panopticon-nagios.lua b/apt-panopticon-nagios.lua
new file mode 100755
index 0000000..1cc9bbc
--- /dev/null
+++ b/apt-panopticon-nagios.lua
@@ -0,0 +1,320 @@
1#!/usr/bin/env lua
2
3--[[
4Writing Nagios plugins -
5 https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html
6 https://nagios-plugins.org/doc/guidelines.html
7 http://users.telenet.be/mydotcom/howto/nagios/pluginsudo.html
8]]
9
10local APT = require 'apt-panopticommon'
11local D = APT.D
12local I = APT.I
13local T = APT.T
14local W = APT.W
15local E = APT.E
16local C = APT.C
17--local arg, sendArgs = APT.parseArgs({...})
18
19
20APT.mirrors = loadfile("results/mirrors.lua")()
21
22
23-- Nagios result codes
24local OK = 0
25local WARNING = 1
26local CRITICAL = 2
27local UNKNOWN = 3
28
29-- Result variables.
30local status = "UNKNOWN: something went horribly wrong with apt-panopticon-nagios.lua."
31local extra = ""
32local returnCode = UNKNOWN
33local perfData = {}
34local perfCount = 0
35
36-- For collecting debugging text for verbosity level 3.
37local debugText = "\nDebugging output -\n"
38
39
40-- Misc functions.
41-------------------------------------------------------------------------------
42
43-- Wrapper coz I'm a C coder.
44local function printf(...) io.write(string.format(...)) end
45
46
47-- Command line argument handling.
48-------------------------------------------------------------------------------
49
50-- A bunch of functions for parsing argument values.
51local function parseVersion(arguments, token, value)
52 arguments[token].value = true
53 return false
54end
55
56local function parseHelp(arguments, token, value)
57 arguments["version"].value = true
58 arguments[token].value = 2
59 return false
60end
61
62local function parseVerbose(arguments, token, value)
63 if nil == arguments[token].value then arguments[token].value = 0 end
64 arguments[token].value = arguments[token].value + 1
65 if arguments[token].value > 3 then arguments[token].value = 3 end
66 return false
67end
68
69local function parseTimeout(arguments, token, value)
70 if nil == value then return true end
71 -- The "+ 0" part forces this to be converted to a number. Coz the comparison wont coerce it automaticaly, which Lua normally does.
72 arguments[token].value = value + 0
73 if arguments[token].value > 120 then arguments[token].value = 120 end
74 return true
75end
76
77local function parseString(arguments, token, value)
78 if nil == value then return true end
79 arguments[token].value = value
80 return true
81end
82
83local function parseRange(arguments, token, value)
84 if nil == value then return true end
85-- TODO - actually parse this.
86-- Threshhold and ranges, meaning that we can set what is classified as the various thresholds and ranges for the three result codes.
87 return true
88end
89
90
91-- Lua doesn't have any sort of C like structure, this is how to fake it.
92local function addArgument(short, default, help, parser)
93 return { short = short, default = default, help = help, parser = parser }
94end
95local arguments =
96{
97 -- Reserved arguments.
98 version = addArgument("V", false, "Print version string, then exit.", parseVersion),
99 help = addArgument("h", 0, "Print version string, verbose help, then exit.", parseHelp),
100
101 verbose = addArgument("v", 0, "Be verbose. Can be up to three of these to increase the verbosity.", parseVerbose),
102 timeout = addArgument("t", 50, "Timeout to wait for the actual results to arrive.", parseTimeout),
103
104 ok = addArgument("o", {}, "What range of thresholds counts as OK.", parseRange),
105 warning = addArgument("w", {}, "What range of thresholds counts as WARNING.", parseRange),
106 critical = addArgument("c", {}, "What range of thresholds counts as CRITICAL.", parseRange),
107
108 --Standard, but optional arguments.
109-- community = addArgument("C", "", "SNMP community.", parseString),
110-- logname = addArgument("l", "", "User name.", parseString),
111-- username = addArgument("u", "", "User name.", parseString),
112-- authentication = addArgument("a", "", "Password.", parseString),
113-- password = addArgument("p", "", "Password.", parseString),
114-- passwd = addArgument("p", "", "Password.", parseString),
115
116 -- We can combine hostname, port, and URL. Avoids duplicate short options.
117 hostname = addArgument("H", "", "Host name or complete URL, including port number.", parseString),
118 -- url = addArgument("u", "", "URL.", parseString),
119 -- port = addArgument("p", -1, "Port number.", parseString),
120
121 -- Our non standard arguments.
122}
123
124
125-- Parse the arguments.
126if nil ~= arg[1] then
127 local lastArg = nil
128 local expectValue = false
129 for i, token in ipairs(arg) do
130 if 0 < i then
131 if not expectValue then
132 if "--" == token:sub(1, 2) then
133 token = token:sub(3)
134 if nil ~= arguments[token] then
135 lastArg = token
136 expectValue = arguments[token].parser(arguments, lastArg, nil)
137 else
138 arguments["version"].value = true
139 arguments["help"].value = 1
140 lastArg = nil
141 expectValue = false
142 end
143 elseif "-" == token:sub(1, 1) then
144 token = token:sub(2)
145 -- Scan through the arguments table looking for short token.
146 for k, v in pairs(arguments) do
147 if token == arguments[k].short then
148 lastArg = k
149 expectValue = arguments[k].parser(arguments, lastArg, nil)
150 end
151 end
152 end
153 elseif nil ~= lastArg then
154 arguments[lastArg].parser(arguments, lastArg, token)
155 lastArg = nil
156 expectValue = false
157 else
158 arguments["version"].value = true
159 arguments["help"].value = 1
160 lastArg = nil
161 expectValue = false
162 end
163 end
164 end
165end
166
167
168-- Fill in default values if needed.
169for k, v in pairs(arguments) do
170 if nil == arguments[k].value then arguments[k].value = arguments[k].default end
171end
172
173
174-- Deal with the various help and version variations.
175-------------------------------------------------------------------------------
176
177if arguments["version"].value then print("apt-panopticon-nagios.lua v0.1") end
178if arguments["help"].value >= 1 then
179 printf("Usage:\n apt-panopticon-nagios.lua ")
180 for k, v in pairs(arguments) do
181 printf("[-%s] ", arguments[k].short, k)
182 end
183 print("")
184end
185if arguments["help"].value == 2 then
186 print("\nThis Nagios plugin is a generic wrapper around stdio based mini checker scripts that can be written in any language.\n")
187 print("Options:")
188-- TODO - should sort this somehow, it's coming out in hash order.
189 for k, v in pairs(arguments) do
190 printf(" -%s, --%s\n", arguments[k].short, k)
191 printf(" %s\n", arguments[k].help)
192 end
193end
194
195-- All the help and version variations don't actually run the checker script, just output stuff and exit.
196if arguments["version"].value or arguments["help"].value >= 1 then os.exit(OK) end
197
198
199
200local function readFile(name)
201 local file = io.open(name, 'r')
202 local output = file:read('*a')
203
204 file:close()
205 return output
206end
207
208
209-- Actually calculate the results.
210-------------------------------------------------------------------------------
211
212if "" == arguments["hostname"].value then
213 status = "UNKNOWN: no host specified."
214 returnCode = UNKNOWN
215else
216 local host = arguments["hostname"].value
217 if APT.checkFile('results/' .. host .. '.lua') then
218 local results = APT.collateAll(APT.mirrors, 'results', host)
219 local e = 0
220 local w = 0
221 local t = 0
222
223 for h, typ in pairs(APT.protocols) do
224 if nil ~= results[typ] then
225 e = e + results[typ].errors
226 w = w + results[typ].warnings
227 t = t + results[typ].timeouts
228 for k, v in pairs(results[typ]) do
229 if ("table" == type(v)) and ('redirects' ~= k) then
230 if 0 <= v.errors then e = e + v.errors end
231 if 0 <= v.warnings then w = w + v.warnings end
232 if 0 <= v.timeouts then t = t + v.timeouts end
233 end
234 end
235 else
236 for k, v in pairs(results) do
237 if "table" == type(v) then
238 for i, u in pairs(v) do
239 if "table" == type(u) then
240 if typ == i then
241 if 0 <= u.errors then e = e + u.errors end
242 if 0 <= u.warnings then w = w + u.warnings end
243 if 0 <= u.timeouts then t = t + u.timeouts end
244 end
245 end
246 end
247 end
248 end
249 end
250 end
251
252 perfData['errors'] = e
253 perfData['warnings'] = w
254 perfData['timeouts'] = t
255 perfCount = perfCount + 3
256 if 0 < e then returnCode = CRITICAL; status = 'CRITICAL'
257 elseif 0 < w then returnCode = WARNING; status = 'WARNING'
258-- elseif 0 < t then returnCode = UNKNOWN; status = 'UNKNOWN'
259 else returnCode = OK; status = 'OK'
260 end
261
262 if arguments["verbose"].value == 1 then
263 status = status .. ': ' .. APT.plurals(e, w, t)
264 else
265 extra = '\n' .. APT.plurals(e, w, t)
266 end
267 else
268 status = "UNKNOWN: no records for host " .. host
269 returnCode = UNKNOWN
270 end
271end
272
273
274-- Send the results to Nagios.
275-------------------------------------------------------------------------------
276
277--[[ Verbosity levels mean -
278 0 Single line, minimal output. Summary
279 1 Single line, additional information (eg list processes that fail)
280 2 Multi line, configuration debug output (eg ps command used)
281 3 Lots of detail for plugin problem diagnosis
282]]
283
284printf(status)
285if arguments["verbose"].value > 0 then
286 printf(extra)
287end
288
289-- Performance data can be a complex format, or a simple format.
290if perfCount > 0 then
291 printf(" | ")
292 for k, v in pairs(perfData) do
293 printf("'%s'=%s\n", k, v)
294 end
295else
296 print()
297end
298
299if arguments["verbose"].value > 1 then
300 print("\nCheckGeneric.lua arguments -")
301 for k, v in pairs(arguments) do
302 if type(v.value) == "table" then
303 APT.dumpTable(v.value, "", " --" .. k)
304 elseif type(v.value) == "boolean" then
305 if (v.value) then
306 printf(" --%s: true\n", k)
307 else
308 printf(" --%s: false\n", k)
309 end
310 else
311 printf(" --%s: %s\n", k, v.value)
312 end
313 end
314end
315
316if arguments["verbose"].value == 3 then
317 print(debugText)
318end
319
320os.exit(returnCode)