Cleanup config.nodes_of
[check_mk.git] / checks / zfsget
blob9c2f0efcc9fca18c8b9cbdefcdffcd8af33de499
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
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.
27 # Example output from agent (sizes are in bytes). Note: the part
28 # [df] in this check is duplicated. We need this information because
29 # zfsget does not show pass-through filesystems like '/'. :-(
31 # <<<zfsget>>>
32 # bpool name bpool -
33 # bpool quota 0 default
34 # bpool used 21947036798826 -
35 # bpool available 11329512075414 -
36 # bpool mountpoint /bpool default
37 # bpool type filesystem -
38 # bpool/acs_fs name bpool/acs_fs -
39 # bpool/acs_fs quota 0 default
40 # bpool/acs_fs used 4829131610 -
41 # bpool/acs_fs available 11329512075414 -
42 # bpool/acs_fs mountpoint /backup/acs local
43 # bpool/acs_fs type filesystem -
44 # [df]
45 # / 10255636 1836517 8419119 18% /
46 # /dev 10255636 1836517 8419119 18% /dev
47 # proc 0 0 0 0% /proc
48 # ctfs 0 0 0 0% /system/contract
49 # mnttab 0 0 0 0% /etc/mnttab
50 # objfs 0 0 0 0% /system/object
51 # swap 153480592 232 153480360 1% /etc/svc/volatile
52 # /usr/lib/libc/libc_hwcap1.so.1 10255636 1836517 8419119 18% /lib/libc.so.1
53 # fd 0 0 0 0% /dev/fd
54 # swap 2097152 11064 2086088 1% /tmp
55 # swap 153480384 24 153480360 1% /var/run
56 # tsrdb10exp/export 5128704 21 4982717 1% /export
57 # tsrdb10exp/export/home 5128704 55 4982717 1% /home
58 # tsrdb10exp/export/opt 5128704 145743 4982717 3% /opt
59 # tsrdb10exp 5128704 21 4982717 1% /tsrdb10exp
60 # tsrdb10dat 30707712 19914358 10789464 65% /u01
63 def parse_zfs_entry(info):
64 def mb(x):
65 return saveint(x) / (1024.0 * 1024)
67 entry = {}
68 for _name, what, value in info:
69 if what in ["used", "available"]:
70 entry[what] = mb(value)
71 elif what == "quota":
72 if value not in ['0', '-']:
73 entry[what] = mb(value)
74 elif what in ['mountpoint', 'type', 'name']:
75 entry[what] = value
77 return entry
80 def parse_zfsget(info):
81 run_zfs = True
82 run_df = False
83 last_name = None
84 zfs_agent_data = []
85 zfs_converted = []
86 df_parsed = {}
87 for line in info:
88 if line == ['[zfs]']:
89 run_zfs = True
90 run_df = False
91 continue
92 if line == ['[df]']:
93 run_df = True
94 run_zfs = False
95 continue
97 if run_zfs:
98 name = line[0]
99 # New block so parse everthing and go on collecting more blocks
100 if last_name != name:
101 last_name = name
102 if zfs_agent_data:
103 new_entry = parse_zfs_entry(zfs_agent_data)
104 if new_entry:
105 zfs_converted.append(new_entry)
106 zfs_agent_data = []
107 zfs_agent_data.append(line[:3])
109 if run_df:
110 if len(line) == 6:
111 device, kbytes, used, avail, _percent, mountpoint = line
112 else:
113 device, _fs_type, kbytes, used, avail, _percent, mountpoint = line
114 if mountpoint.startswith("/"):
115 entry = {}
116 entry["name"] = device
117 entry["mountpoint"] = mountpoint
118 # With some versions of solaris systems such as
119 # solaris 10 10/08 s10s_u6wos_07b SPARC and solaris 10 10/09 s10x_u8wos_08a X86
120 # there migth be a bug in the 'df -h' command which we use for filesystem infos.
121 # Then the received data from the agent looks like "/ 0 12445007 19012273 5% /".
122 # In this case we compute the total size as the sum of used and available.
123 total = int(kbytes)
124 used = int(used)
125 avail = int(avail)
126 if used and avail and not total:
127 total = used + avail
128 else:
129 avail = total - used
130 entry["total"] = total / 1024.0
131 entry["used"] = used / 1024.0
132 entry["available"] = avail / 1024.0
133 df_parsed[mountpoint] = entry
135 # Now remove duplicate entries for the root filesystem, such
136 # as /dev/ or /lib/libc.so.1. We do this if size, used and
137 # avail is equal. I hope that it will not happen too often
138 # that this is per chance the case for different passed-through
139 # filesystems
140 root_entry = df_parsed.get("/")
141 if root_entry:
142 t_u_a = (root_entry["total"], root_entry["used"], root_entry["available"])
143 drop = []
144 for mountpoint, entry in df_parsed.items():
145 if mountpoint != "/" and \
146 t_u_a == (entry["total"], entry["used"], entry["available"]):
147 drop.append(mountpoint)
148 for mp in drop:
149 del df_parsed[mp]
151 # parsed has the device name as key, because there may exist
152 # several device names per mount point, and we know only
153 # later which one to take
154 zfs_parsed = {}
155 for entry in zfs_converted:
156 if entry["mountpoint"].startswith("/"):
157 entry["is_pool"] = '/' not in entry["name"]
158 if entry['available'] != 0 and entry['type'] == 'filesystem':
159 zfs_parsed[entry["name"]] = entry
161 # parsed_df and parsed_final have the mount point as key
162 parsed_final = {}
163 for mountpoint, entry_df in df_parsed.items():
164 found = False
165 # for every mount point in the df section, if the device name
166 # is also present in the "parsed" variable, we take those data
167 for name, entry in zfs_parsed.items():
168 if entry_df["name"] == name:
169 parsed_final[mountpoint] = entry
170 found = True
171 # if a mount point in the df section is not present in the
172 # parsed variable, we take the data from the df section
173 if not found:
174 parsed_final[mountpoint] = entry_df
176 return parsed_final
179 def inventory_zfsget(info):
180 mplist = []
181 parsed = parse_zfsget(info)
182 for mountpoint in parsed.iterkeys():
183 if mountpoint not in inventory_df_exclude_mountpoints:
184 mplist.append(mountpoint)
185 return df_inventory(mplist)
188 # def convert_zfssize(txt):
189 # units_to_mb = {
190 # 'K' : 1/1024.0,
191 # 'M' : 1.0,
192 # 'G' : 1024.0,
193 # 'T' : 1024 * 1024.0,
194 # 'P' : 1024 * 1024 * 1024.0,
196 # return float(txt[:-1]) * units_to_mb[txt[-1]]
199 def check_zfsget(item, params, info):
200 entries = parse_zfsget(info)
201 # ist item drin -> OK, ansonsten gleich hier
202 fslist = []
203 for mountpoint, entry in entries.items():
204 if "patterns" in params or item == mountpoint:
205 # 1. Filesystems with a quota
206 if "quota" in entry:
207 used_mb = entry["used"]
208 total_mb = entry["quota"]
209 avail_mb = total_mb - used_mb
210 # 2. Normal filesystems.
211 else:
212 used_mb = entry["used"]
213 avail_mb = entry["available"]
214 total_mb = used_mb + avail_mb
215 fslist.append((mountpoint, total_mb, avail_mb, 0))
217 return df_check_filesystem_list(item, params, fslist)
220 check_info['zfsget'] = {
221 "check_function": check_zfsget,
222 "inventory_function": inventory_zfsget,
223 "service_description": "Filesystem %s",
224 "has_perfdata": True,
225 "group": "filesystem",
226 "default_levels_variable": "filesystem_default_levels",
227 "includes": ["size_trend.include", "df.include"],