munin-plugins/systemd_status
2021-06-16 11:56:56 +02:00

111 lines
2.6 KiB
Python

#!/usr/bin/env python3
# pylint: disable=invalid-name
# pylint: enable=invalid-name
"""Munin plugin to monitor systemd service status.
=head1 NAME
systemd_status - monitor systemd service status, including normal services,
mounts, hotplugs and socket activations
=head1 APPLICABLE SYSTEMS
Linux systems with systemd installed.
=head1 CONFIGURATION
No configuration is required for this plugin.
Warning level for systemd "failed" state is set to 0:0. If any of the services
enters "failed" state, Munin will emit warning.
=head1 AUTHOR
Kim B. Heino <b@bbbs.net>
=head1 LICENSE
GPLv2
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf
=cut
"""
import os
import re
import subprocess
import sys
STATES = (
'failed',
'dead',
'running',
'exited',
'active',
'listening',
'waiting',
'plugged',
'mounted',
)
def config():
"""Autoconfig values."""
print('graph_title systemd services')
print('graph_vlabel Services')
print('graph_category processes')
print('graph_args --base 1000 --lower-limit 0')
print('graph_scale no')
print('graph_info Number of services in given activation state.')
for state in STATES:
print('{state}.label Services in {state} state'.format(state=state))
print('failed.warning 0:0')
if os.environ.get('MUNIN_CAP_DIRTYCONFIG') == '1':
fetch()
def fetch():
"""Print runtime values."""
# Get data
try:
# deb9/py3.5 doesn't have encoding parameter in subprocess
output = subprocess.check_output(['/bin/systemctl', 'list-units'])
except (OSError, subprocess.CalledProcessError):
return
output = output.decode('utf-8', 'ignore')
# Parse data
states = {state: 0 for state in STATES}
for line in output.splitlines():
token = line.split()
if len(token) < 4:
continue
if len(token[0]) < 3: # Skip failed-bullet
token = token[1:]
if token[0].endswith('.scope'):
continue # Ignore scopes
if re.match(r'user.*@\d+\.service', token[0]):
continue # These fail randomly in older systemd
if token[3] in states:
states[token[3]] = states[token[3]] + 1
# Output
for state in STATES:
print('{}.value {}'.format(state, states[state]))
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'autoconf':
print('yes' if os.path.exists('/run/systemd/system') else
'no (systemd is not running)')
elif len(sys.argv) > 1 and sys.argv[1] == 'config':
config()
else:
fetch()