diff options
| author | onefang | 2019-12-26 00:36:28 +1000 |
|---|---|---|
| committer | onefang | 2019-12-26 00:36:28 +1000 |
| commit | b81e5c82e5fc32246a2da0cf656baa7d1dc635da (patch) | |
| tree | fa070092460778ff81f476801c078734afb42172 | |
| parent | Proper Updated check. (diff) | |
| download | apt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.zip apt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.tar.gz apt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.tar.bz2 apt-panopticon-b81e5c82e5fc32246a2da0cf656baa7d1dc635da.tar.xz | |
Add a Icinga/Nagios script.
| -rwxr-xr-x | apt-panopticon-nagios.lua | 320 |
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 | --[[ | ||
| 4 | Writing 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 | |||
| 10 | local APT = require 'apt-panopticommon' | ||
| 11 | local D = APT.D | ||
| 12 | local I = APT.I | ||
| 13 | local T = APT.T | ||
| 14 | local W = APT.W | ||
| 15 | local E = APT.E | ||
| 16 | local C = APT.C | ||
| 17 | --local arg, sendArgs = APT.parseArgs({...}) | ||
| 18 | |||
| 19 | |||
| 20 | APT.mirrors = loadfile("results/mirrors.lua")() | ||
| 21 | |||
| 22 | |||
| 23 | -- Nagios result codes | ||
| 24 | local OK = 0 | ||
| 25 | local WARNING = 1 | ||
| 26 | local CRITICAL = 2 | ||
| 27 | local UNKNOWN = 3 | ||
| 28 | |||
| 29 | -- Result variables. | ||
| 30 | local status = "UNKNOWN: something went horribly wrong with apt-panopticon-nagios.lua." | ||
| 31 | local extra = "" | ||
| 32 | local returnCode = UNKNOWN | ||
| 33 | local perfData = {} | ||
| 34 | local perfCount = 0 | ||
| 35 | |||
| 36 | -- For collecting debugging text for verbosity level 3. | ||
| 37 | local debugText = "\nDebugging output -\n" | ||
| 38 | |||
| 39 | |||
| 40 | -- Misc functions. | ||
| 41 | ------------------------------------------------------------------------------- | ||
| 42 | |||
| 43 | -- Wrapper coz I'm a C coder. | ||
| 44 | local 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. | ||
| 51 | local function parseVersion(arguments, token, value) | ||
| 52 | arguments[token].value = true | ||
| 53 | return false | ||
| 54 | end | ||
| 55 | |||
| 56 | local function parseHelp(arguments, token, value) | ||
| 57 | arguments["version"].value = true | ||
| 58 | arguments[token].value = 2 | ||
| 59 | return false | ||
| 60 | end | ||
| 61 | |||
| 62 | local 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 | ||
| 67 | end | ||
| 68 | |||
| 69 | local 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 | ||
| 75 | end | ||
| 76 | |||
| 77 | local function parseString(arguments, token, value) | ||
| 78 | if nil == value then return true end | ||
| 79 | arguments[token].value = value | ||
| 80 | return true | ||
| 81 | end | ||
| 82 | |||
| 83 | local 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 | ||
| 88 | end | ||
| 89 | |||
| 90 | |||
| 91 | -- Lua doesn't have any sort of C like structure, this is how to fake it. | ||
| 92 | local function addArgument(short, default, help, parser) | ||
| 93 | return { short = short, default = default, help = help, parser = parser } | ||
| 94 | end | ||
| 95 | local 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. | ||
| 126 | if 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 | ||
| 165 | end | ||
| 166 | |||
| 167 | |||
| 168 | -- Fill in default values if needed. | ||
| 169 | for k, v in pairs(arguments) do | ||
| 170 | if nil == arguments[k].value then arguments[k].value = arguments[k].default end | ||
| 171 | end | ||
| 172 | |||
| 173 | |||
| 174 | -- Deal with the various help and version variations. | ||
| 175 | ------------------------------------------------------------------------------- | ||
| 176 | |||
| 177 | if arguments["version"].value then print("apt-panopticon-nagios.lua v0.1") end | ||
| 178 | if 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("") | ||
| 184 | end | ||
| 185 | if 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 | ||
| 193 | end | ||
| 194 | |||
| 195 | -- All the help and version variations don't actually run the checker script, just output stuff and exit. | ||
| 196 | if arguments["version"].value or arguments["help"].value >= 1 then os.exit(OK) end | ||
| 197 | |||
| 198 | |||
| 199 | |||
| 200 | local function readFile(name) | ||
| 201 | local file = io.open(name, 'r') | ||
| 202 | local output = file:read('*a') | ||
| 203 | |||
| 204 | file:close() | ||
| 205 | return output | ||
| 206 | end | ||
| 207 | |||
| 208 | |||
| 209 | -- Actually calculate the results. | ||
| 210 | ------------------------------------------------------------------------------- | ||
| 211 | |||
| 212 | if "" == arguments["hostname"].value then | ||
| 213 | status = "UNKNOWN: no host specified." | ||
| 214 | returnCode = UNKNOWN | ||
| 215 | else | ||
| 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 | ||
| 271 | end | ||
| 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 | |||
| 284 | printf(status) | ||
| 285 | if arguments["verbose"].value > 0 then | ||
| 286 | printf(extra) | ||
| 287 | end | ||
| 288 | |||
| 289 | -- Performance data can be a complex format, or a simple format. | ||
| 290 | if perfCount > 0 then | ||
| 291 | printf(" | ") | ||
| 292 | for k, v in pairs(perfData) do | ||
| 293 | printf("'%s'=%s\n", k, v) | ||
| 294 | end | ||
| 295 | else | ||
| 296 | print() | ||
| 297 | end | ||
| 298 | |||
| 299 | if 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 | ||
| 314 | end | ||
| 315 | |||
| 316 | if arguments["verbose"].value == 3 then | ||
| 317 | print(debugText) | ||
| 318 | end | ||
| 319 | |||
| 320 | os.exit(returnCode) | ||
