Verified Commit 52e28672 authored by Dan Thomson's avatar Dan Thomson
Browse files

Initial commit

parent f13f3c65
---
stages:
- test
include:
- project: 'gitlab/ci/templates'
ref: 'master'
file: 'python/Pylint.gitlab-ci.yml'
pylint:
extends: .python_pylint
tags:
- docker-runner
[BASIC]
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,f,ex,Run,_
[DESIGN]
# Maximum number of branch for function / method body
max-branches=14
# nagios-vsftpd
Nagios tests to notify on issues reported by vsftpd
\ No newline at end of file
This repository contains a small collection of scripts used to check the health
of an FTP server running vsftpd. THe are scripts available for use by nagios
under the bin/ path and are documented below.
## Checks
* nagios\_check\_vsftpd\_log - Checks recent log entries for transfer errors
and reports the error condition if the number of errors exceeds the WARN
or CRIT limit.
You can check the pydoc for the script and/or the usage details by calling
the script with the `-h` argument for more information.
# Author(s)
Dan Thomson <dthomson@triumf.ca>
#!/usr/bin/env python3
"""
nagios_check_vsftpd_log - Nagios script for checking recent vsftpd log entries
for errors.
"""
import argparse
import logging
import os
import os.path
import re
import sys
import pygtail
def error_condition(line, regex=r'i$'):
"""
Returns true when a line is considered to have an error. You may
optionally pass the regex argument to alter the default condition for
what consists as an error. For now, this function is simply a wrapper
around a regex check.
"""
matches = re.search(regex, line)
logger = logging.getLogger(__name__)
logger.debug("MATCH: %s", matches)
return matches
def cache_result_value(exit_value, filename):
"""
Stores the result value so that it can be used on the next invocation if
required.
"""
with open(filename, 'w') as f:
f.write(str(exit_value))
def restore_result_value(filename):
"""
Loads the previously cached result value in the case where we want to
repeat the previous check status.
"""
val = -1
with open(filename, 'r') as f:
val = int(f.read())
return val
def main():
"""
Main function.
"""
parser = argparse.ArgumentParser(
description='Check the latest vsftp log entries and report errors.'
)
parser.add_argument(
'-q',
'--quiet',
action='store_true',
help='Disable printing any output on WARN or CRIT status',
)
parser.add_argument(
'-x',
'--debug',
action='store_true',
help='Enable debugging output',
)
parser.add_argument(
'-o',
'--offset-file-path',
default='/var/cache/nagios_check_vsftpd/',
help='Storage location for offset cache files used by pygtail',
)
parser.add_argument(
'-w',
'--warn-count',
default=1,
type=int,
help='Number of issues to trigger a WARN result',
)
parser.add_argument(
'-c',
'--crit-count',
type=int,
default=2,
help='Number of issues to trigger a CRIT result',
)
parser.add_argument(
'log_filenames',
nargs="+",
help='Log filenames to check'
)
parsed_args = parser.parse_args()
if parsed_args.debug:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)
warn_count = parsed_args.warn_count
crit_count = parsed_args.crit_count
log_filename_list = parsed_args.log_filenames
# Create the directory and don't care if there's a complaint about the
# path existing already
try:
os.mkdir(parsed_args.offset_file_path, mode=0o700)
except FileExistsError:
pass
# Not clear on the return value for os.mkdir or what happens when permission
# is denied, so if we didn't create a directory, lets just die
if not os.path.exists(parsed_args.offset_file_path):
raise FileNotFoundError(
"No offset destination path {dest} exists".format(
dest=parsed_args.offset_file_path
)
)
sorted(
log_filename_list,
key=lambda filename: os.stat(filename).st_mtime
)
error_count = 0
line_count = 0
for log_filename in log_filename_list:
logger.debug("LOG FILENAME: %s", log_filename)
pyg = pygtail.Pygtail(
log_filename,
offset_file="{destination_dir}/{log_filename}.offset".format(
destination_dir=parsed_args.offset_file_path,
log_filename=os.path.basename(log_filename),
)
)
for line in pyg:
line_count = line_count + 1
if error_condition(line.rstrip()):
error_count = error_count + 1
logger.debug("LOG FILANE LINE: [%s]", line.rstrip())
exit_value = 0
if error_count > crit_count:
logger.debug("CRITICAL (count: %d/%d)", error_count, crit_count)
exit_value = 2
if not parsed_args.quiet:
print("CRITICAL: {error_count} issues found in vsftpd log(s) "
"[MAX: {crit_count}]".format(
error_count=error_count,
crit_count=crit_count
)
)
elif error_count > warn_count:
logger.debug("WARNING (count: %d/%d)", error_count, warn_count)
exit_value = 1
if not parsed_args.quiet:
print("WARNING: {error_count} issues found in vsftpd log(s) "
"[MAX: {warn_count}]".format(
error_count=error_count,
warn_count=warn_count
)
)
# If no new results were found, we want to return the previous check's status
# and not a 0 in case the previous situation was an error and we don't want
# imply that the error is gone just because we haven't seen any new entries
# in the log
if line_count == 0:
exit_value = restore_result_value(
"{destination_dir}/exit_value".format(
destination_dir=parsed_args.offset_file_path
)
)
else:
cache_result_value(
exit_value,
"{destination_dir}/exit_value".format(
destination_dir=parsed_args.offset_file_path,
)
)
sys.exit(exit_value)
if __name__ == '__main__':
main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment