bundles/sshmon: import from work repository
This commit is contained in:
parent
eaf268aea9
commit
c7362df6c4
12 changed files with 773 additions and 0 deletions
153
bundles/sshmon/files/check_mounts
Normal file
153
bundles/sshmon/files/check_mounts
Normal file
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from subprocess import check_output
|
||||
from tempfile import TemporaryFile
|
||||
|
||||
|
||||
check_filesystem_types = {
|
||||
'ext2',
|
||||
'ext3',
|
||||
'ext4',
|
||||
'vfat',
|
||||
}
|
||||
|
||||
|
||||
def read_systemd():
|
||||
"""
|
||||
Read configured mount units from systemd.
|
||||
"""
|
||||
|
||||
lines = check_output(
|
||||
'systemctl list-unit-files -at mount --no-legend --no-pager',
|
||||
shell=True,
|
||||
).decode('UTF-8').splitlines()
|
||||
|
||||
for line in lines:
|
||||
frag_path = None
|
||||
fstype = None
|
||||
options = None
|
||||
source_path = None
|
||||
state = None
|
||||
where = None
|
||||
|
||||
mountunit = line.split()[0]
|
||||
props = check_output(
|
||||
'systemctl show -p FragmentPath,Options,SourcePath,Type,UnitFileState,Where -- ' + mountunit,
|
||||
shell=True,
|
||||
).decode('UTF-8')
|
||||
for pline in props.splitlines():
|
||||
if pline.startswith('FragmentPath='):
|
||||
frag_path = pline[len('FragmentPath='):]
|
||||
elif pline.startswith('Options='):
|
||||
options = pline[len('Options='):]
|
||||
elif pline.startswith('SourcePath='):
|
||||
source_path = pline[len('SourcePath='):]
|
||||
elif pline.startswith('Type='):
|
||||
fstype = pline[len('Type='):]
|
||||
elif pline.startswith('UnitFileState='):
|
||||
state = pline[len('UnitFileState='):]
|
||||
elif pline.startswith('Where='):
|
||||
where = pline[len('Where='):]
|
||||
|
||||
if state not in ('enabled', 'generated', 'static'):
|
||||
continue
|
||||
|
||||
# The properties of mount units change once they are mounted.
|
||||
# For example, "options" and "type" change from "bind"/"none" to
|
||||
# something like "ext4"/"rw,relatime" once a bind-mount is
|
||||
# mounted.
|
||||
#
|
||||
# fstype can be an empty string if an admin decides to simply
|
||||
# not specify the type in its mount unit. (Only good old fstab
|
||||
# forced setting fstype.)
|
||||
if (
|
||||
options != 'bind' and
|
||||
fstype != '' and
|
||||
fstype not in check_filesystem_types
|
||||
):
|
||||
continue
|
||||
|
||||
# Traditional mountpoints, those are represented by systemd
|
||||
# units which are auto-generated.
|
||||
if source_path == '/etc/fstab':
|
||||
yield where
|
||||
# Okay, this is a real systemd mount unit. Has it been
|
||||
# configured by an admin or is it noise?
|
||||
elif frag_path.startswith('/etc/systemd/system'):
|
||||
yield where
|
||||
|
||||
|
||||
def read_unix(path):
|
||||
"""
|
||||
Read /etc/fstab or /proc/self/mounts.
|
||||
"""
|
||||
|
||||
with open(path, 'r') as fp:
|
||||
lines = fp.read().splitlines()
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
|
||||
fields = line.split()
|
||||
if len(fields) < 3 or fields[2] not in check_filesystem_types:
|
||||
continue
|
||||
|
||||
# Only the mountpoint.
|
||||
yield fields[1]
|
||||
|
||||
|
||||
def rwtest(path):
|
||||
try:
|
||||
with TemporaryFile(dir=path) as fp:
|
||||
pass
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('--ignore', nargs='*')
|
||||
args = parser.parse_args()
|
||||
|
||||
# read_systemd() does not return everything on systems older than 18.04.
|
||||
configured = set(read_systemd()) | set(read_unix('/etc/fstab'))
|
||||
mounted = set(read_unix('/proc/self/mounts'))
|
||||
|
||||
configured -= set(args.ignore or [])
|
||||
mounted -= set(args.ignore or [])
|
||||
|
||||
missing_mounted = configured - mounted
|
||||
missing_configured = mounted - configured
|
||||
mounted_as_configured = mounted & configured
|
||||
|
||||
all_mounts = configured | mounted
|
||||
not_okay = {}
|
||||
|
||||
for i in missing_mounted:
|
||||
not_okay[i] = 'not mounted'
|
||||
|
||||
for i in missing_configured:
|
||||
not_okay[i] = 'not in fstab nor systemd unit'
|
||||
|
||||
for i in mounted_as_configured:
|
||||
if not rwtest(i):
|
||||
not_okay[i] = 'mounted read-only'
|
||||
|
||||
exitcode = 0
|
||||
|
||||
# Two loops to have CRITICAL printed before OK without having to create
|
||||
# a new data structure.
|
||||
for i in sorted(all_mounts):
|
||||
if i in not_okay:
|
||||
print('CRITICAL - {}: {}'.format(i, not_okay[i]))
|
||||
exitcode = 2
|
||||
|
||||
for i in sorted(all_mounts):
|
||||
if i not in not_okay:
|
||||
print('OK - {}'.format(i))
|
||||
|
||||
exit(exitcode)
|
Loading…
Add table
Add a link
Reference in a new issue