2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2014 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 # /dev/sda3 ext4 8123200 1207512 6496392 16% /
29 # /dev/sda6 ext3 117794932 192192 111522544 1% /data
30 # /dev/sda2 ext3 8123200 220388 7483516 3% /var
31 # /dev/sda1 reiserfs 256666 16052 227362 7% /boot
32 # /dev/mapper/mirrored-database ext3 20642428 1027112 19405604 6% /mirrored/database
34 # Another example from a Windows 7 system:
36 # SYSTEM NTFS 312569172 180648472 131920700 58% C:\
37 # Data NTFS 976506816 528665344 447841472 55% D:\
38 # PS3 PlayStation(R)3 File System 0 0 0 0% P:\
40 # An example with btrfs (SLES 12). Here the same device is mounted
41 # several times at different mount point. But must only be monitored
42 # once. We use the device instead of the mount point in this case.
44 # /dev/sda1 btrfs 20970496 4169036 16539348 21% /
45 # devtmpfs devtmpfs 497396 0 497396 0% /dev
46 # tmpfs tmpfs 506312 0 506312 0% /dev/shm
47 # tmpfs tmpfs 506312 6980 499332 2% /run
48 # tmpfs tmpfs 506312 0 506312 0% /sys/fs/cgroup
49 # /dev/sda1 btrfs 20970496 4169036 16539348 21% /.snapshots
50 # /dev/sda1 btrfs 20970496 4169036 16539348 21% /var/tmp
51 # /dev/sda1 btrfs 20970496 4169036 16539348 21% /var/spool
52 # /dev/sda1 btrfs 20970496 4169036 16539348 21% /var/opt
53 # /dev/sda1 btrfs 20970496 4169036 16539348 21% /var/log
56 # dev 795652 0 795652 0% /dev
57 # run 811756 11848 799908 1% /run
58 # /dev/sda2 1040280 716340 271512 73% /
59 # devtmpfs 795652 0 795652 0% /dev
60 # tmpfs 811756 0 811756 0% /dev/shm
61 # tmpfs 811756 11848 799908 1% /run
62 # tmpfs 811756 0 811756 0% /sys/fs/cgroup
63 # none 811756 12 811744 0% /var/tmp
64 # none 811756 0 811756 0% /var/lock
65 # none 409600 95460 314140 23% /var/log
66 # tmpfs 811756 11848 799908 1% /var/run
67 # none 811756 56 811700 0% /tmp
68 # /dev/sda1 126931 33759 86619 28% /boot
69 # /dev/sda5 12668904 360184 11670236 3% /persist
72 # dev 198913 365 198548 0% /dev
73 # run 202939 336 202603 0% /run
74 # /dev/sda2 65536 25533 40003 39% /
75 # devtmpfs 198913 365 198548 0% /dev
76 # tmpfs 202939 1 202938 0% /dev/shm
77 # tmpfs 202939 336 202603 0% /run
78 # tmpfs 202939 7 202932 0% /sys/fs/cgroup
79 # none 202939 4 202935 0% /var/tmp
80 # none 202939 1 202938 0% /var/lock
81 # none 202939 28 202911 0% /var/log
82 # tmpfs 202939 336 202603 0% /var/run
83 # none 202939 27 202912 0% /tmp
84 # /dev/sda1 32768 25 32743 0% /boot
85 # /dev/sda5 799680 118 799562 0% /persist
89 # C:\ NTFS 41838588 21776048 20062540 53% C:\
90 # C:\Program Files\Vision Solutions\Double-Take\Service\MountDir\usauhtest0010_c061b170-ad3f-473f-92ce-088c97fce98e_C\ NTFS 41835516 11895180 29940336 29% C:\Program Files\Vision Solutions\Double-Take\Service\MountDir\usauhtest0010_c061b170-ad3f-473f-92ce-088c97fce98e_C\
92 inventory_df_rules
= []
93 inventory_df_exclude_fs
= ['tmpfs', 'nfs', 'smbfs', 'cifs', 'iso9660']
97 def parse_blocks_subsection(blocks_subsection
):
100 btrfs_devices
= set()
101 for line
in blocks_subsection
:
107 line
= [line
[0], None] + line
[1:]
109 # Handle known cases, where the file system contains spaces
110 for index
, entry
in enumerate(line
):
112 line
= [" ".join(line
[:index
])] + [line
[index
]] + line
[index
+ 1:index
+ 5] + [
113 " ".join(line
[index
+ 5:])
117 if line
[2] == "File" and line
[3] == "System":
118 line
= [line
[0], " ".join(line
[1:4])] + line
[4:]
121 # This particular bit of magic originated in Werk #2671 and has the purpose of avoiding duplicate checks,
122 # as btrfs filesystems are often mounted at multiple mountpoints. We keep it for compatibility.
123 if fs_type
== "btrfs":
125 if device
not in btrfs_devices
:
126 btrfs_devices
.add(device
)
127 mountpoint
= "btrfs " + device
132 mountpoint
= " ".join(line
[6:]).replace('\\', '/') # Windows \ is replaced with /
134 # exclude filesystems without size
136 if int(line
[2]) == 0:
141 # Beware: the 6th column of df ("used perc") may includes 5% which are reserved
142 # for the superuser, whereas the 4th colum ("used MB") does *not* include that.
143 # Beware(2): the column used_mb does not account for the reserved space for
144 # superusers. So we rather use the column 'avail' and subtract that from total
145 # to compute the used space.
146 size_mb
= int(line
[2]) / 1024.0
147 avail_mb
= int(line
[4]) / 1024.0
148 used_mb
= int(line
[3]) / 1024.0
149 reserved_mb
= size_mb
- avail_mb
- used_mb
# reserved for root
150 df_blocks
.append((mountpoint
, size_mb
, avail_mb
, reserved_mb
))
152 volume_name
= line
[0]
153 volume_info
[mountpoint
] = {
154 "volume_name": volume_name
,
158 return df_blocks
, volume_info
160 def parse_inodes_subsection(inodes_subsection
):
162 for line
in inodes_subsection
:
168 line
= [line
[0], None] + line
[1:]
171 inodes_total
= int(line
[2])
172 inodes_avail
= int(line
[4])
176 mountpoint
= line
[-1]
177 df_inodes
.append((mountpoint
, inodes_total
, inodes_avail
))
180 blocks_subsection
= []
181 inodes_subsection
= []
185 if line
[-1] == '[df_inodes_start]':
188 elif line
[-1] == '[df_inodes_end]':
193 inodes_subsection
.append(line
)
195 blocks_subsection
.append(line
)
197 return parse_blocks_subsection(blocks_subsection
), parse_inodes_subsection(inodes_subsection
)
200 def inventory_df(parsed
):
201 def is_mountpoint(inventory_entry
):
202 return "patterns" not in inventory_entry
[1]
204 inventory_options
= host_extra_conf_merged(host_name(), inventory_df_rules
)
205 include_volume_name
= inventory_options
.get("include_volume_name", False)
206 ignore_fs_types
= inventory_options
.get("ignore_fs_types", inventory_df_exclude_fs
)
207 never_ignore_mountpoints
= inventory_options
.get("never_ignore_mountpoints", [])
209 (df_blocks
, volume_info
), _
= parsed
212 for line
in _filter_docker_filesystems(df_blocks
):
215 if mountpoint
in inventory_df_exclude_mountpoints
:
216 continue # exclude this mount point (/tmp, /proc, whatever user wants)
217 if volume_info
[mountpoint
][
218 "fs_type"] in ignore_fs_types
and mountpoint
not in never_ignore_mountpoints
:
219 continue # ignore this filesystem type
220 mplist
.append(mountpoint
)
222 if include_volume_name
:
224 for entry
in df_inventory(mplist
):
225 if is_mountpoint(entry
):
226 mountpoint
, params
= entry
227 item
= "%s %s" % (volume_info
[mountpoint
]["volume_name"], mountpoint
)
228 inventory
.append((item
, params
))
230 inventory
.append(entry
)
232 inventory
= df_inventory(mplist
)
236 def check_df(item
, params
, parsed
):
237 (df_blocks
, volume_info
), df_inodes
= parsed
239 df_blocks
= _filter_docker_filesystems(df_blocks
)
240 volume_and_mp_to_mp
= {
241 ("%s %s" % (volume_info
[mp
]["volume_name"], mp
)): mp
for mp
in volume_info
243 if "patterns" in params
or item
in volume_info
:
245 elif item
in volume_and_mp_to_mp
:
246 mountpoint
= volume_and_mp_to_mp
[item
]
249 return df_check_filesystem_list(mountpoint
, params
, df_blocks
, df_inodes
)
252 # Always exclude filesystems below dockers local storage area
253 # And also exclude docker mounts in containers which are reported
254 # by the agent when the agent is executed in the container context
255 def _filter_docker_filesystems(df_blocks
):
257 e
for e
in df_blocks
if not e
[0].startswith("/var/lib/docker/") and
258 e
[0] not in ["/etc/resolv.conf", "/etc/hostname", "/etc/hosts"]
263 "parse_function": parse_df
,
264 "inventory_function": inventory_df
,
265 "check_function": check_df
,
266 "service_description": "Filesystem %s",
267 "has_perfdata": True,
268 "group": "filesystem",
269 "default_levels_variable": "filesystem_default_levels",
270 "includes": ["size_trend.include", "df.include"],