2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2018 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
28 # UNIT LOAD ACTIVE SUB DESCRIPTION
29 # ● check-mk-enterprise-2018.07.24.service loaded failed failed LSB: OMD sites
30 # ● systemd-cryptsetup@cryptswap1.service loaded failed failed Cryptography Setup for cryptswap1
31 # ● swapfile.swap loaded failed failed /swapfile
33 # LOAD = Reflects whether the unit definition was properly loaded.
34 # ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
35 # SUB = The low-level unit activation state, values depend on unit type.
37 # 3 loaded units listed. Pass --all to see loaded but inactive units, too.
38 # To show all installed unit files use 'systemctl list-unit-files'.
40 # .--Parse function------------------------------------------------------.
42 # | | _ \ __ _ _ __ ___ ___ / _|_ _ _ __ ___| |_(_) ___ _ __ |
43 # | | |_) / _` | '__/ __|/ _ \ | |_| | | | '_ \ / __| __| |/ _ \| '_ \ |
44 # | | __/ (_| | | \__ \ __/ | _| |_| | | | | (__| |_| | (_) | | | | |
45 # | |_| \__,_|_| |___/\___| |_| \__,_|_| |_|\___|\__|_|\___/|_| |_| |
47 # '----------------------------------------------------------------------'
50 '.service ', # A service unit describes how to manage a service or application on the server. This will include how to start or stop the service, under which circumstances it should be automatically started, and the dependency and ordering information for related software.
51 '.socket ', # A socket unit file describes a network or IPC socket, or a FIFO buffer that systemd uses for socket-based activation. These always have an associated .service file that will be started when activity is seen on the socket that this unit defines.
52 '.device ', # A unit that describes a device that has been designated as needing systemd management by udev or the sysfs filesystem. Not all devices will have .device files. Some scenarios where .device units may be necessary are for ordering, mounting, and accessing the devices.
53 '.mount ', # This unit defines a mountpoint on the system to be managed by systemd. These are named after the mount path, with slashes changed to dashes. Entries within /etc/fstab can have units created automatically.
54 '.automount ', # An .automount unit configures a mountpoint that will be automatically mounted. These must be named after the mount point they refer to and must have a matching .mount unit to define the specifics of the mount.
55 '.swap ', # This unit describes swap space on the system. The name of these units must reflect the device or file path of the space.
56 '.target ', # A target unit is used to provide synchronization points for other units when booting up or changing states. They also can be used to bring the system to a new state. Other units specify their relation to targets to become tied to the target's operations.
57 '.path ', # This unit defines a path that can be used for path-based activation. By default, a .service unit of the same base name will be started when the path reaches the specified state. This uses inotify to monitor the path for changes.
58 '.timer ', # A .timer unit defines a timer that will be managed by systemd, similar to a cron job for delayed or scheduled activation. A matching unit will be started when the timer is reached.
59 '.snapshot ', # A .snapshot unit is created automatically by the systemctl snapshot command. It allows you to reconstruct the current state of the system after making changes. Snapshots do not survive across sessions and are used to roll back temporary states.
60 '.slice ', # A .slice unit is associated with Linux Control Group nodes, allowing resources to be restricted or assigned to any processes associated with the slice. The name reflects its hierarchical position within the cgroup tree. Units are placed in certain slices by default depending on their type.
61 '.scope ', # Scope units are created automatically by systemd from information received from its bus interfaces. These are used to manage sets of system processes that are created externally.
65 def parse_systemd_units(info
):
71 # second to last line (see above): "X loaded units listed."
72 count
= int(info
[-2][0])
76 UnitEntry
= collections
.namedtuple("UnitEntry",
77 ['name', 'type', 'load', 'active', 'sub', 'description'])
78 for row
in info
[1:count
+ 1]:
79 if row
[0] == '*': # remove the '● ' (seems to get converted to '*')
82 for unit_marker
in _SYSTEMD_UNITS
:
83 if unit_marker
in line
:
84 utype
= unit_marker
.strip('. ')
85 name
, remains
= line
.split(unit_marker
, 1)
86 load
, active
, sub
, descr
= remains
.split(' ', 3)
87 unit
= UnitEntry(name
, utype
, load
, active
, sub
, descr
)
88 parsed
.setdefault(unit
.type, {})[unit
.name
] = unit
96 check_info
['systemd_units'] = {
97 'parse_function': parse_systemd_units
,
100 # .--services------------------------------------------------------------.
102 # | ___ ___ _ ____ _(_) ___ ___ ___ |
103 # | / __|/ _ \ '__\ \ / / |/ __/ _ \/ __| |
104 # | \__ \ __/ | \ V /| | (_| __/\__ \ |
105 # | |___/\___|_| \_/ |_|\___\___||___/ |
107 # '----------------------------------------------------------------------'
109 factory_settings
["systemd_services_default_levels"] = {
116 "else": 2, # missleading name, used if service vanishes
119 discovery_systemd_units_services_rules
= []
122 def discovery_systemd_units_services(parsed
):
123 services
= parsed
.get('service', {})
125 def regex_match(what
, name
):
129 if entry
.startswith("~"):
130 if regex(entry
[1:]).match(name
):
138 def state_match(rule_states
, state
):
139 return any(s
in (None, state
) for s
in rule_states
)
141 for rule
in discovery_systemd_units_services_rules
:
143 descriptions
= settings
.get("descriptions", [])
144 names
= settings
.get("names", [])
145 states
= settings
.get("states")
146 for service
in services
.values():
147 if (regex_match(descriptions
, service
.description
) and
148 regex_match(names
, service
.name
) and state_match(states
, service
.active
)):
149 yield service
.name
, {}
152 def check_systemd_units_services(item
, params
, parsed
):
153 services
= parsed
.get('service', {})
154 service
= services
.get(item
, None)
156 yield params
["else"], "Service not found"
159 state
= params
["states"].get(service
.active
, params
["states_default"])
160 yield state
, "Status: %s" % service
.active
161 yield 0, service
.description
164 check_info
['systemd_units.services'] = {
165 'inventory_function': discovery_systemd_units_services
,
166 'check_function': check_systemd_units_services
,
167 'service_description': 'Systemd Service %s',
168 'group': 'systemd_services',
169 'default_levels_variable': 'systemd_services_default_levels',
173 def discovery_systemd_units_services_summary(parsed
):
178 def check_systemd_units_services_summary(_no_item
, params
, parsed
):
179 services
= parsed
.get('service', {}).values()
181 yield 0, "%d services in total" % len(services
)
183 all_states
= sorted(set(s
.active
for s
in services
))
185 for active_state
in all_states
:
186 state
= params
["states"].get(active_state
, params
["states_default"])
190 service_names
= sorted(s
.name
for s
in services
if s
.active
== active_state
)
191 cnt
= len(service_names
)
192 service_names
= ", ".join(service_names
)
193 yield state
, "%d service%s %s (%s)" % (cnt
, '' if cnt
== 1 else 's', active_state
,
197 check_info
['systemd_units.services_summary'] = {
198 'inventory_function': discovery_systemd_units_services_summary
,
199 'check_function': check_systemd_units_services_summary
,
200 'service_description': 'Systemd Service %s',
201 'group': 'systemd_services',
202 'default_levels_variable': 'systemd_services_default_levels',