Skip to content

Commit

Permalink
Refactor to add subchecks
Browse files Browse the repository at this point in the history
  • Loading branch information
martialblog committed May 31, 2024
1 parent 84ee0fc commit 9c6ec9d
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 79 deletions.
1 change: 1 addition & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ disable=fixme,
too-many-locals,
too-many-statements,
too-many-branches,
too-many-return-statements,
bare-except,
missing-module-docstring,
missing-function-docstring,
Expand Down
238 changes: 172 additions & 66 deletions check_brevisone
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
# works based on those contributions, and sublicense and distribute
# those contributions and any derivatives thereof.

from argparse import ArgumentParser
from argparse import ArgumentParser, ArgumentTypeError
import urllib.request
from urllib.parse import urljoin
import ssl
Expand All @@ -55,53 +55,40 @@ import sys
# threshold or did not appear to be working properly
# 2 - CRITICAL - The plugin detected that either the service was not running or it was above some "critical" threshold
# 3 - UNKNOWN - Invalid command line arguments were supplied to the plugin or low-level failures
__version__ = '3.1.0'

OK = 0
WARNING = 1
CRITICAL = 2
UNKNOWN = 3

__version__ = '3.0.0'


def read_int(string):
"""
Get and sanitize integer data
"""
try:
return int(string.split(':')[1])
except ValueError:
return 0


def read_signal(string):
"""
Get and sanitize the signal data
"""
sig = ':'.join(string.split(':')[1:]).strip()
sig = sig.replace('db', '').replace('dBm', '').strip()

try:
return int(sig)
except ValueError:
return 0
STATES = {
OK: "OK",
WARNING: "WARNING",
CRITICAL: "CRITICAL",
UNKNOWN: "UNKNOWN",
}


def generate_output(status='UNKNOWN', lines=None, perfdata=None):
def generate_output(status=3, outputs=None, perfdata=None):
"""
Generate plugin data output with status and perfdata
"""

pluginoutput = str(status)
pluginoutput = '[' + STATES.get(status, 'UNKNOWN') + '] - Brevis.One SMS Gateway Status\n'

# All lines we received from the Endpoint
if lines:
pluginoutput += ' - ' + ' '.join(lines)
if outputs:
for line in outputs:
pluginoutput += line + '\n'

# Perfdata we explicitly extracted from the data
# The perfdata var should be a dict, we normalize the keys and
# transform everything into the expected output 'key 1': 3 > key_1=3
if perfdata:
pluginoutput += '|' + ' '.join([key.lower().replace(" ", "_").replace(",", "") + '=' + str(value) for key, value in perfdata.items()])
pluginoutput += '|'
for k,v in perfdata.items():
if (k and v) and isinstance(v, int):
pluginoutput += k.lower().replace(" ", "_").replace(",", "") + '=' + str(v) + ' '

print(pluginoutput)

Expand All @@ -118,10 +105,34 @@ def commandline(args):
parser.add_argument('-T', '--timeout', help='Seconds before connection times out (default 10)',
default=10,
type=int)
parser.add_argument('-Q', '--queue', help='The warning threshold for the amount of queued SMS (default 1)',
parser.add_argument('--ssl-insecure',
dest='insecure',
action='store_true',
default=False,
help='Allow insecure SSL connections (default False)')
parser.add_argument('--protocol',
choices=["http", "https"],
default='https',
help='HTTP protocol, use one of http or https (default https)')
parser.add_argument('-d', '--debug', action='store_true',
help='debug mode')

parser.add_argument('--queue-warning', help='The warning threshold for the amount of queued SMS (default 1)',
default=1,
type=int)
parser.add_argument('-F', '--fail', help='The critical threshold for failed SMS (default 1)', default=1, type=int)
parser.add_argument('--queue-critical', help='The critical threshold for the amount of queued SMS (default 5)',
default=5,
type=int)

parser.add_argument('--failed-warning',
help='The warning threshold for failed SMS (default 1)',
default=1,
type=int)
parser.add_argument('--failed-critical',
help='The critical threshold for failed SMS (default 5)',
default=5,
type=int)

parser.add_argument('--signal-warning',
help='The warning threshold for the minimum signal strength (in db, default -91)',
default=-91,
Expand All @@ -130,17 +141,27 @@ def commandline(args):
help='The critical threshold for the minimum signal strength (in db, default -107)',
default=-107,
type=int)
parser.add_argument('--ssl-insecure',
dest='insecure',
action='store_true',
default=False,
help='Allow insecure SSL connections (default False)')
parser.add_argument('--protocol',
choices=["http", "https"],
default='https',
help='HTTP protocol, use one of http or https (default https)')

return parser.parse_args(args)
parser.add_argument('--disk-warning',
help='The warning threshold for the disk space (in bytes)',
required=False,
type=int)
parser.add_argument('--disk-critical',
help='The critical threshold for the disk space (in bytes)',
required=False,
type=int)

args = parser.parse_args(args)

if args.disk_warning and not args.disk_critical:
parser.print_help()
raise ArgumentTypeError("%s: error: --disk-warning requires --disk-critical" % parser.prog)

if args.disk_critical and not args.disk_warning:
parser.print_help()
raise ArgumentTypeError("%s: error: --disk-critical requires --disk-warning" % parser.prog)

return args


def get_data(base_url, timeout, insecure):
Expand All @@ -152,7 +173,7 @@ def get_data(base_url, timeout, insecure):
HTTP/1.0 200 OK
que: foo
failed: 0
signal_strength: 15 db
signal: 15 db
total: 25
"""

Expand All @@ -177,21 +198,104 @@ def get_data(base_url, timeout, insecure):

return resp

def extract_perfdata(lines):
def parse_data(data):
"""
Safely extract perfdata
Safely extract data from the APIs reponse
"""
if len(lines) < 4:
return None
lines = [str(i).strip() for i in data.split("\n") if i]

parsed_data = {}

for l in lines:
d = l.split(":")
if len(d) == 2:
key = d[0].strip()
value = d[1].strip()

perfdata = {
'que': read_int(lines[0]),
'failed': read_int(lines[1]),
'signal': read_signal(lines[2]),
'total': read_int(lines[3])
}
# Remove the db string from the signal value
if key == "signal":
value = value.replace('db', '').replace('dBm', '').strip()

return perfdata
# Parse integer value to be actual integers
if value.lstrip('-').isdigit():
value = int(value)

parsed_data[key] = value

return parsed_data


def worst_state(*states):
overall = -1

for state in states:
if state == CRITICAL:
overall = CRITICAL
elif state == UNKNOWN:
if overall != CRITICAL:
overall = UNKNOWN
elif state > overall:
overall = state

if overall < 0 or overall > 3:
overall = UNKNOWN

return overall

def debug_print(debug_flag, message):
"""
Print debug messages if -d is set.
"""
if not debug_flag:
return

print(message)

def determine_status(args, perfdata):
states = []
outputs = []

if perfdata['failed'] >= args.failed_critical:
outputs.append(" \\_[CRITICAL] Failed sending: {}".format(perfdata['failed']))
states.append(CRITICAL)
elif perfdata['failed'] >= args.failed_warning:
outputs.append(" \\_[WARNING] Failed sending: {}".format(perfdata['failed']))
states.append(WARNING)
else:
outputs.append(" \\_[OK] Failed sending: {}".format(perfdata['failed']))
states.append(OK)

if perfdata['signal'] <= args.signal_critical:
outputs.append(" \\_[CRITICAL] Signal strength: {}".format(perfdata['signal']))
states.append(CRITICAL)
elif perfdata['signal'] <= args.signal_warning:
outputs.append(" \\_[WARNING] Signal strength: {}".format(perfdata['signal']))
states.append(WARNING)
else:
outputs.append(" \\_[OK] Signal strength: {}".format(perfdata['signal']))
states.append(OK)

if perfdata['que'] >= args.queue_critical:
outputs.append(" \\_[CRITICAL] Que length: {}".format(perfdata['que']))
states.append(CRITICAL)
elif perfdata['que'] >= args.queue_warning:
outputs.append(" \\_[WARNING] Que length: {}".format(perfdata['que']))
states.append(WARNING)
else:
outputs.append(" \\_[OK] Que length: {}".format(perfdata['que']))
states.append(OK)

if args.disk_critical and perfdata['disk'] >= args.disk_critical:
outputs.append(" \\_[CRITICAL] Disk usage: {}".format(perfdata['disk']))
states.append(CRITICAL)
elif args.disk_warning and perfdata['disk'] >= args.disk_warning:
outputs.append(" \\_[WARNING] Disk usage: {}".format(perfdata['disk']))
states.append(WARNING)
elif args.disk_warning or args.disk_critical:
outputs.append(" \\_[OK] Disk usage: {}".format(perfdata['disk']))
states.append(OK)

return states, outputs

def main(args):
try:
Expand All @@ -203,26 +307,28 @@ def main(args):
print('UNKNOWN - Could not connect to SMS Gateway', data_exc)
return UNKNOWN

# Split up lines and clean up items
lines = [str(i).strip() for i in data.split("\n") if i]
# Safely extract perfdata, which we'll also use to determine the final status
perfdata = extract_perfdata(lines)
perfdata = parse_data(data)

if not perfdata:
print('UNKNOWN - Could not determine status', perfdata)
return UNKNOWN

if 'failed' not in perfdata:
print('UNKNOWN - Could not determine failed status', perfdata)
return UNKNOWN

if 'que' not in perfdata:
print('UNKNOWN - Could not determine que status', perfdata)
return UNKNOWN

# Determine the final status
if perfdata['failed'] >= args.fail or perfdata['signal'] <= args.signal_critical:
generate_output(status='CRITICAL', lines=lines, perfdata=perfdata)
return CRITICAL
states, outputs = determine_status(args, perfdata)

if perfdata['que'] >= args.queue or perfdata['signal'] <= args.signal_warning:
generate_output(status='WARNING', lines=lines, perfdata=perfdata)
return WARNING
debug_print(args.debug, "API Response:\n{}".format(data))

generate_output(status='OK', lines=lines, perfdata=perfdata)
return OK
generate_output(worst_state(*states), outputs=outputs, perfdata=perfdata)
return worst_state(*states)


if __name__ == '__main__': # pragma: no cover
Expand Down
Loading

0 comments on commit 9c6ec9d

Please sign in to comment.