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.

321 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)