mirror of
https://github.com/munin-monitoring/contrib.git
synced 2025-07-22 14:16:00 +00:00
Merge pull request #1392 from kimheino/master
systemd_status: add support to monitor user services
This commit is contained in:
commit
4c1a92ec28
1 changed files with 61 additions and 10 deletions
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
# pylint: enable=invalid-name
|
# pylint: enable=invalid-name
|
||||||
|
# pylint: disable=consider-using-f-string
|
||||||
|
|
||||||
"""Munin plugin to monitor systemd service status.
|
"""Munin plugin to monitor systemd service status.
|
||||||
|
|
||||||
|
@ -20,6 +21,21 @@ No configuration is required for this plugin.
|
||||||
Warning level for systemd "failed" state is set to 0:0. If any of the services
|
Warning level for systemd "failed" state is set to 0:0. If any of the services
|
||||||
enters "failed" state, Munin will emit warning.
|
enters "failed" state, Munin will emit warning.
|
||||||
|
|
||||||
|
Single service can be ignored by configuring it's value to "0":
|
||||||
|
|
||||||
|
[systemd_status]
|
||||||
|
env.fwupd_refresh_service 0
|
||||||
|
|
||||||
|
Normally this plugin monitors global system services. User services can be
|
||||||
|
monitored by manually adding softlink and config:
|
||||||
|
|
||||||
|
ln -s /usr/share/munin/plugins/systemd_status \
|
||||||
|
/etc/munin/plugins/systemd_status_b
|
||||||
|
|
||||||
|
[systemd_status_b]
|
||||||
|
user b
|
||||||
|
env.monitor_user yes
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
|
||||||
Kim B. Heino <b@bbbs.net>
|
Kim B. Heino <b@bbbs.net>
|
||||||
|
@ -38,9 +54,11 @@ GPLv2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import pwd
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
|
|
||||||
STATES = (
|
STATES = (
|
||||||
|
@ -55,9 +73,25 @@ STATES = (
|
||||||
'mounted',
|
'mounted',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
USER = os.environ.get('monitor_user') in ('yes', '1')
|
||||||
|
|
||||||
|
|
||||||
|
def safename(name):
|
||||||
|
"""Return safe variable name."""
|
||||||
|
# Convert ä->a as isalpha('ä') is true
|
||||||
|
value = unicodedata.normalize('NFKD', name)
|
||||||
|
value = value.encode('ASCII', 'ignore').decode('utf-8')
|
||||||
|
|
||||||
|
# Remove non-alphanumeric chars
|
||||||
|
return ''.join(char.lower() if char.isalnum() else '_' for char in value)
|
||||||
|
|
||||||
|
|
||||||
def config():
|
def config():
|
||||||
"""Autoconfig values."""
|
"""Autoconfig values."""
|
||||||
|
if USER:
|
||||||
|
print('graph_title systemd services for {}'.format(
|
||||||
|
pwd.getpwuid(os.geteuid())[0]))
|
||||||
|
else:
|
||||||
print('graph_title systemd services')
|
print('graph_title systemd services')
|
||||||
print('graph_vlabel Services')
|
print('graph_vlabel Services')
|
||||||
print('graph_category processes')
|
print('graph_category processes')
|
||||||
|
@ -75,33 +109,50 @@ def fetch():
|
||||||
"""Print runtime values."""
|
"""Print runtime values."""
|
||||||
# Get data
|
# Get data
|
||||||
try:
|
try:
|
||||||
# deb9/py3.5 doesn't have encoding parameter in subprocess
|
output = subprocess.check_output(['systemctl', 'list-units'] +
|
||||||
output = subprocess.check_output(['/bin/systemctl', 'list-units'])
|
(['--user'] if USER else []),
|
||||||
|
encoding='utf-8')
|
||||||
except (OSError, subprocess.CalledProcessError):
|
except (OSError, subprocess.CalledProcessError):
|
||||||
return
|
return
|
||||||
output = output.decode('utf-8', 'ignore')
|
|
||||||
|
|
||||||
# Parse data
|
# Parse data
|
||||||
states = {state: 0 for state in STATES}
|
states = {state: 0 for state in STATES}
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
token = line.split()
|
token = line.split()
|
||||||
|
if token and len(token[0]) < 3: # Skip failed-bullet
|
||||||
|
token = token[1:]
|
||||||
if len(token) < 4:
|
if len(token) < 4:
|
||||||
continue
|
continue
|
||||||
if len(token[0]) < 3: # Skip failed-bullet
|
service = token[0]
|
||||||
token = token[1:]
|
state = token[3]
|
||||||
if token[0].endswith('.scope'):
|
if service.endswith('.scope'):
|
||||||
continue # Ignore scopes
|
continue # Ignore scopes
|
||||||
if re.match(r'user.*@\d+\.service', token[0]):
|
if re.match(r'user.*@\d+\.service', service):
|
||||||
continue # These fail randomly in older systemd
|
continue # These fail randomly in older systemd
|
||||||
if token[3] in states:
|
if state in states:
|
||||||
states[token[3]] = states[token[3]] + 1
|
value = 1
|
||||||
|
if state == 'failed':
|
||||||
|
value = int(os.environ.get(safename(service), 1))
|
||||||
|
states[state] += value
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
for state in STATES:
|
for state in STATES:
|
||||||
print('{}.value {}'.format(state, states[state]))
|
print('{}.value {}'.format(state, states[state]))
|
||||||
|
|
||||||
|
|
||||||
|
def fix_dbus():
|
||||||
|
"""Fix DBus address for user service."""
|
||||||
|
if not USER:
|
||||||
|
return
|
||||||
|
euid = '/{}/'.format(os.geteuid())
|
||||||
|
if euid in os.environ.get('DBUS_SESSION_BUS_ADDRESS', ''):
|
||||||
|
return
|
||||||
|
os.putenv('DBUS_SESSION_BUS_ADDRESS',
|
||||||
|
'unix:path=/run/user{}bus'.format(euid))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
fix_dbus()
|
||||||
if len(sys.argv) > 1 and sys.argv[1] == 'autoconf':
|
if len(sys.argv) > 1 and sys.argv[1] == 'autoconf':
|
||||||
print('yes' if os.path.exists('/run/systemd/system') else
|
print('yes' if os.path.exists('/run/systemd/system') else
|
||||||
'no (systemd is not running)')
|
'no (systemd is not running)')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue