A Lua script to check the health of Devuan Linux package mirrors. The master repo is at https://sledjhamr.org/cgit/apt-panopticon/ and the master issues tracker is at https://sledjhamr.org/mantisbt/project_page.php?project_id=13
https://sledjhamr.org/cgit/apt-panopticon/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
9.5 KiB
320 lines
9.5 KiB
#!/usr/bin/env lua
|
|
|
|
--[[
|
|
Writing Nagios plugins -
|
|
https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html
|
|
https://nagios-plugins.org/doc/guidelines.html
|
|
http://users.telenet.be/mydotcom/howto/nagios/pluginsudo.html
|
|
]]
|
|
|
|
local APT = require 'apt-panopticommon'
|
|
local D = APT.D
|
|
local I = APT.I
|
|
local T = APT.T
|
|
local W = APT.W
|
|
local E = APT.E
|
|
local C = APT.C
|
|
--local arg, sendArgs = APT.parseArgs({...})
|
|
|
|
|
|
APT.mirrors = loadfile("results/mirrors.lua")()
|
|
|
|
|
|
-- Nagios result codes
|
|
local OK = 0
|
|
local WARNING = 1
|
|
local CRITICAL = 2
|
|
local UNKNOWN = 3
|
|
|
|
-- Result variables.
|
|
local status = "UNKNOWN: something went horribly wrong with apt-panopticon-nagios.lua."
|
|
local extra = ""
|
|
local returnCode = UNKNOWN
|
|
local perfData = {}
|
|
local perfCount = 0
|
|
|
|
-- For collecting debugging text for verbosity level 3.
|
|
local debugText = "\nDebugging output -\n"
|
|
|
|
|
|
-- Misc functions.
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- Wrapper coz I'm a C coder.
|
|
local function printf(...) io.write(string.format(...)) end
|
|
|
|
|
|
-- Command line argument handling.
|
|
-------------------------------------------------------------------------------
|
|
|
|
-- A bunch of functions for parsing argument values.
|
|
local function parseVersion(arguments, token, value)
|
|
arguments[token].value = true
|
|
return false
|
|
end
|
|
|
|
local function parseHelp(arguments, token, value)
|
|
arguments["version"].value = true
|
|
arguments[token].value = 2
|
|
return false
|
|
end
|
|
|
|
local function parseVerbose(arguments, token, value)
|
|
if nil == arguments[token].value then arguments[token].value = 0 end
|
|
arguments[token].value = arguments[token].value + 1
|
|
if arguments[token].value > 3 then arguments[token].value = 3 end
|
|
return false
|
|
end
|
|
|
|
local function parseTimeout(arguments, token, value)
|
|
if nil == value then return true end
|
|
-- The "+ 0" part forces this to be converted to a number. Coz the comparison wont coerce it automaticaly, which Lua normally does.
|
|
arguments[token].value = value + 0
|
|
if arguments[token].value > 120 then arguments[token].value = 120 end
|
|
return true
|
|
end
|
|
|
|
local function parseString(arguments, token, value)
|
|
if nil == value then return true end
|
|
arguments[token].value = value
|
|
return true
|
|
end
|
|
|
|
local function parseRange(arguments, token, value)
|
|
if nil == value then return true end
|
|
-- TODO - actually parse this.
|
|
-- Threshhold and ranges, meaning that we can set what is classified as the various thresholds and ranges for the three result codes.
|
|
return true
|
|
end
|
|
|
|
|
|
-- Lua doesn't have any sort of C like structure, this is how to fake it.
|
|
local function addArgument(short, default, help, parser)
|
|
return { short = short, default = default, help = help, parser = parser }
|
|
end
|
|
local arguments =
|
|
{
|
|
-- Reserved arguments.
|
|
version = addArgument("V", false, "Print version string, then exit.", parseVersion),
|
|
help = addArgument("h", 0, "Print version string, verbose help, then exit.", parseHelp),
|
|
|
|
verbose = addArgument("v", 0, "Be verbose. Can be up to three of these to increase the verbosity.", parseVerbose),
|
|
timeout = addArgument("t", 50, "Timeout to wait for the actual results to arrive.", parseTimeout),
|
|
|
|
ok = addArgument("o", {}, "What range of thresholds counts as OK.", parseRange),
|
|
warning = addArgument("w", {}, "What range of thresholds counts as WARNING.", parseRange),
|
|
critical = addArgument("c", {}, "What range of thresholds counts as CRITICAL.", parseRange),
|
|
|
|
--Standard, but optional arguments.
|
|
-- community = addArgument("C", "", "SNMP community.", parseString),
|
|
-- logname = addArgument("l", "", "User name.", parseString),
|
|
-- username = addArgument("u", "", "User name.", parseString),
|
|
-- authentication = addArgument("a", "", "Password.", parseString),
|
|
-- password = addArgument("p", "", "Password.", parseString),
|
|
-- passwd = addArgument("p", "", "Password.", parseString),
|
|
|
|
-- We can combine hostname, port, and URL. Avoids duplicate short options.
|
|
hostname = addArgument("H", "", "Host name or complete URL, including port number.", parseString),
|
|
-- url = addArgument("u", "", "URL.", parseString),
|
|
-- port = addArgument("p", -1, "Port number.", parseString),
|
|
|
|
-- Our non standard arguments.
|
|
}
|
|
|
|
|
|
-- Parse the arguments.
|
|
if nil ~= arg[1] then
|
|
local lastArg = nil
|
|
local expectValue = false
|
|
for i, token in ipairs(arg) do
|
|
if 0 < i then
|
|
if not expectValue then
|
|
if "--" == token:sub(1, 2) then
|
|
token = token:sub(3)
|
|
if nil ~= arguments[token] then
|
|
lastArg = token
|
|
expectValue = arguments[token].parser(arguments, lastArg, nil)
|
|
else
|
|
arguments["version"].value = true
|
|
arguments["help"].value = 1
|
|
lastArg = nil
|
|
expectValue = false
|
|
end
|
|
elseif "-" == token:sub(1, 1) then
|
|
token = token:sub(2)
|
|
-- Scan through the arguments table looking for short token.
|
|
for k, v in pairs(arguments) do
|
|
if token == arguments[k].short then
|
|
lastArg = k
|
|
expectValue = arguments[k].parser(arguments, lastArg, nil)
|
|
end
|
|
end
|
|
end
|
|
elseif nil ~= lastArg then
|
|
arguments[lastArg].parser(arguments, lastArg, token)
|
|
lastArg = nil
|
|
expectValue = false
|
|
else
|
|
arguments["version"].value = true
|
|
arguments["help"].value = 1
|
|
lastArg = nil
|
|
expectValue = false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- Fill in default values if needed.
|
|
for k, v in pairs(arguments) do
|
|
if nil == arguments[k].value then arguments[k].value = arguments[k].default end
|
|
end
|
|
|
|
|
|
-- Deal with the various help and version variations.
|
|
-------------------------------------------------------------------------------
|
|
|
|
if arguments["version"].value then print("apt-panopticon-nagios.lua v0.1") end
|
|
if arguments["help"].value >= 1 then
|
|
printf("Usage:\n apt-panopticon-nagios.lua ")
|
|
for k, v in pairs(arguments) do
|
|
printf("[-%s] ", arguments[k].short, k)
|
|
end
|
|
print("")
|
|
end
|
|
if arguments["help"].value == 2 then
|
|
print("\nThis Nagios plugin is a generic wrapper around stdio based mini checker scripts that can be written in any language.\n")
|
|
print("Options:")
|
|
-- TODO - should sort this somehow, it's coming out in hash order.
|
|
for k, v in pairs(arguments) do
|
|
printf(" -%s, --%s\n", arguments[k].short, k)
|
|
printf(" %s\n", arguments[k].help)
|
|
end
|
|
end
|
|
|
|
-- All the help and version variations don't actually run the checker script, just output stuff and exit.
|
|
if arguments["version"].value or arguments["help"].value >= 1 then os.exit(OK) end
|
|
|
|
|
|
|
|
local function readFile(name)
|
|
local file = io.open(name, 'r')
|
|
local output = file:read('*a')
|
|
|
|
file:close()
|
|
return output
|
|
end
|
|
|
|
|
|
-- Actually calculate the results.
|
|
-------------------------------------------------------------------------------
|
|
|
|
if "" == arguments["hostname"].value then
|
|
status = "UNKNOWN: no host specified."
|
|
returnCode = UNKNOWN
|
|
else
|
|
local host = arguments["hostname"].value
|
|
if APT.checkFile('results/' .. host .. '.lua') then
|
|
local results = APT.collateAll(APT.mirrors, 'results', host)
|
|
local e = 0
|
|
local w = 0
|
|
local t = 0
|
|
|
|
for h, typ in pairs(APT.protocols) do
|
|
if nil ~= results[typ] then
|
|
e = e + results[typ].errors
|
|
w = w + results[typ].warnings
|
|
t = t + results[typ].timeouts
|
|
for k, v in pairs(results[typ]) do
|
|
if ("table" == type(v)) and ('redirects' ~= k) then
|
|
if 0 <= v.errors then e = e + v.errors end
|
|
if 0 <= v.warnings then w = w + v.warnings end
|
|
if 0 <= v.timeouts then t = t + v.timeouts end
|
|
end
|
|
end
|
|
else
|
|
for k, v in pairs(results) do
|
|
if "table" == type(v) then
|
|
for i, u in pairs(v) do
|
|
if "table" == type(u) then
|
|
if typ == i then
|
|
if 0 <= u.errors then e = e + u.errors end
|
|
if 0 <= u.warnings then w = w + u.warnings end
|
|
if 0 <= u.timeouts then t = t + u.timeouts end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
perfData['errors'] = e
|
|
perfData['warnings'] = w
|
|
perfData['timeouts'] = t
|
|
perfCount = perfCount + 3
|
|
if 0 < e then returnCode = CRITICAL; status = 'CRITICAL'
|
|
elseif 0 < w then returnCode = WARNING; status = 'WARNING'
|
|
-- elseif 0 < t then returnCode = UNKNOWN; status = 'UNKNOWN'
|
|
else returnCode = OK; status = 'OK'
|
|
end
|
|
|
|
if arguments["verbose"].value == 1 then
|
|
status = status .. ': ' .. APT.plurals(e, w, t)
|
|
else
|
|
extra = '\n' .. APT.plurals(e, w, t)
|
|
end
|
|
else
|
|
status = "UNKNOWN: no records for host " .. host
|
|
returnCode = UNKNOWN
|
|
end
|
|
end
|
|
|
|
|
|
-- Send the results to Nagios.
|
|
-------------------------------------------------------------------------------
|
|
|
|
--[[ Verbosity levels mean -
|
|
0 Single line, minimal output. Summary
|
|
1 Single line, additional information (eg list processes that fail)
|
|
2 Multi line, configuration debug output (eg ps command used)
|
|
3 Lots of detail for plugin problem diagnosis
|
|
]]
|
|
|
|
printf(status)
|
|
if arguments["verbose"].value > 0 then
|
|
printf(extra)
|
|
end
|
|
|
|
-- Performance data can be a complex format, or a simple format.
|
|
if perfCount > 0 then
|
|
printf(" | ")
|
|
for k, v in pairs(perfData) do
|
|
printf("'%s'=%s\n", k, v)
|
|
end
|
|
else
|
|
print()
|
|
end
|
|
|
|
if arguments["verbose"].value > 1 then
|
|
print("\nCheckGeneric.lua arguments -")
|
|
for k, v in pairs(arguments) do
|
|
if type(v.value) == "table" then
|
|
APT.dumpTable(v.value, " --" .. k)
|
|
elseif type(v.value) == "boolean" then
|
|
if (v.value) then
|
|
printf(" --%s: true\n", k)
|
|
else
|
|
printf(" --%s: false\n", k)
|
|
end
|
|
else
|
|
printf(" --%s: %s\n", k, v.value)
|
|
end
|
|
end
|
|
end
|
|
|
|
if arguments["verbose"].value == 3 then
|
|
print(debugText)
|
|
end
|
|
|
|
os.exit(returnCode)
|
|
|