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 # TODO: name the next new subcheck "esx_vsphere_vm" and introduce a parse function
29 def esx_vsphere_vm_convert(info
):
32 # Do not monitor VM templates
33 if line
[0] == "config.template" and line
[1] == "true":
35 data
[line
[0]] = line
[1:]
39 # .--Memory--------------------------------------------------------------.
41 # | | \/ | ___ _ __ ___ ___ _ __ _ _ |
42 # | | |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | | |
43 # | | | | | __/ | | | | | (_) | | | |_| | |
44 # | |_| |_|\___|_| |_| |_|\___/|_| \__, | |
46 # '----------------------------------------------------------------------'
49 def inventory_esx_vsphere_vm_mem(info
):
50 data
= esx_vsphere_vm_convert(info
)
51 if 'summary.quickStats.guestMemoryUsage' in data
:
55 def check_esx_vsphere_vm_mem(_no_item
, _no_params
, info
):
56 data
= esx_vsphere_vm_convert(info
)
58 # If the machine is powered of, we do not get data
59 powerstate
= data
["runtime.powerState"][0]
60 if powerstate
!= "poweredOn":
61 raise MKCounterWrapped("VM is %s, skipping this check" % powerstate
)
65 host_memory_usage
= savefloat(data
["summary.quickStats.hostMemoryUsage"][0]) * 1024 * 1024
67 guest_memory_usage
= savefloat(data
["summary.quickStats.guestMemoryUsage"][0]) * 1024 * 1024
68 #size of the balloon driver in the VM
69 ballooned_memory
= savefloat(data
["summary.quickStats.balloonedMemory"][0]) * 1024 * 1024
70 #The portion of memory, in MB, that is granted to this VM from non-shared host memor(musst not be set)
71 shared_memory
= savefloat(data
["summary.quickStats.sharedMemory"][0]) * 1024 * 1024
72 #The portion of memory, in MB, that is granted to this VM from host memory that is shared between VMs.
73 private_memory
= savefloat(data
.get("summary.quickStats.privateMemory",
74 [0])[0]) * 1024 * 1024
76 raise MKCounterWrapped(
77 "Hostsystem did not provide memory information (reason may be high load)")
80 ("host", host_memory_usage
),
81 ("guest", guest_memory_usage
),
82 ("ballooned", ballooned_memory
),
83 ("shared", shared_memory
),
84 ("private", private_memory
),
87 message
= "Host: %s, Guest: %s, " \
88 "Ballooned: %s, Private: %s, Shared: %s" % \
89 (get_bytes_human_readable(host_memory_usage
), \
90 get_bytes_human_readable(guest_memory_usage
), get_bytes_human_readable(ballooned_memory
), \
91 get_bytes_human_readable(private_memory
), get_bytes_human_readable(shared_memory
) )
92 return (0, message
, perf
)
95 check_info
['esx_vsphere_vm.mem_usage'] = {
96 "inventory_function": inventory_esx_vsphere_vm_mem
,
97 "check_function": check_esx_vsphere_vm_mem
,
98 "service_description": "ESX Memory",
103 # .--Name----------------------------------------------------------------.
105 # | | \ | | __ _ _ __ ___ ___ |
106 # | | \| |/ _` | '_ ` _ \ / _ \ |
107 # | | |\ | (_| | | | | | | __/ |
108 # | |_| \_|\__,_|_| |_| |_|\___| |
110 # '----------------------------------------------------------------------'
113 def inventory_esx_vsphere_vm_name(info
):
114 data
= esx_vsphere_vm_convert(info
)
116 return [(None, None)]
119 def check_esx_vsphere_vm_name(_no_item
, _no_params
, info
):
120 data
= esx_vsphere_vm_convert(info
)
121 return (0, " ".join(data
['name']))
124 check_info
['esx_vsphere_vm.name'] = {
125 "inventory_function": inventory_esx_vsphere_vm_name
,
126 "check_function": check_esx_vsphere_vm_name
,
127 "service_description": "ESX Name",
131 # .--Runtime Host--------------------------------------------------------.
133 # | | _ \ _ _ _ __ | |_(_)_ __ ___ ___ | | | | ___ ___| |_ |
134 # | | |_) | | | | '_ \| __| | '_ ` _ \ / _ \ | |_| |/ _ \/ __| __| |
135 # | | _ <| |_| | | | | |_| | | | | | | __/ | _ | (_) \__ \ |_ |
136 # | |_| \_\\__,_|_| |_|\__|_|_| |_| |_|\___| |_| |_|\___/|___/\__| |
138 # +----------------------------------------------------------------------+
140 # '----------------------------------------------------------------------'
143 def inventory_esx_vsphere_vm_running_on(info
):
144 data
= esx_vsphere_vm_convert(info
)
145 if 'runtime.host' in data
:
146 return [(None, None)]
149 def check_esx_vsphere_vm_running_on(no_item
, no_params
, info
):
150 data
= esx_vsphere_vm_convert(info
)
152 running_on
= data
.get("runtime.host")
154 return 3, "Runtime host information is missing"
156 return 0, "Running on %s" % running_on
[0]
159 check_info
['esx_vsphere_vm.running_on'] = {
160 "inventory_function": inventory_esx_vsphere_vm_running_on
,
161 "check_function": check_esx_vsphere_vm_running_on
,
162 "service_description": "ESX Hostsystem",
166 # .--VM Datastores--------------------------------------------------------.
167 # | __ ____ __ ____ _ _ |
168 # | \ \ / / \/ | | _ \ __ _| |_ __ _ ___| |_ ___ _ __ ___ |
169 # | \ \ / /| |\/| | | | | |/ _` | __/ _` / __| __/ _ \| '__/ _ \ |
170 # | \ V / | | | | | |_| | (_| | || (_| \__ \ || (_) | | | __/ |
171 # | \_/ |_| |_| |____/ \__,_|\__\__,_|___/\__\___/|_| \___| |
173 # +----------------------------------------------------------------------+
175 # '----------------------------------------------------------------------'
178 def inventory_esx_vsphere_vm_datastores(info
):
179 data
= esx_vsphere_vm_convert(info
)
180 # Right now we only handle one datastore per vm
181 if 'config.datastoreUrl' in data
:
182 return [(None, None)]
185 def check_esx_vsphere_vm_datastores(no_item
, no_params
, info
):
186 data
= esx_vsphere_vm_convert(info
)
188 datastore_urls
= data
.get("config.datastoreUrl")
189 if not datastore_urls
:
190 return 3, "Datastore information is missing"
193 for datastore_url
in " ".join(datastore_urls
).split("@@"):
194 datastore_url
= datastore_url
.split("|")
197 # datastore_url looks like
198 #['url /vmfs/volumes/513df1e9-12fd7366-ac5a-e41f13e69eaa',
199 # 'uncommitted 51973812224',
200 # 'name zmucvm99-lds',
203 # 'capacity 578478407680',
204 # 'freeSpace 68779245568']
206 # Convert datastore_url to dict
207 datastore_dict
= dict(x
.split(" ", 1) for x
in datastore_url
)
209 capacity
= saveint(datastore_dict
.get("capacity", 0)) * 1.0
211 free_perc
= int(datastore_dict
.get("freeSpace", 0)) / capacity
* 100
215 output_store
= "Stored on %s (%s/%0.1f%% free)" %\
216 (datastore_dict
.get("name"),
217 get_bytes_human_readable(capacity
),
219 output
.append(output_store
)
220 return 0, ", ".join(output
)
223 check_info
['esx_vsphere_vm.datastores'] = {
224 "inventory_function": inventory_esx_vsphere_vm_datastores
,
225 "check_function": check_esx_vsphere_vm_datastores
,
226 "service_description": "ESX Datastores",
230 # .--GuestTools----------------------------------------------------------.
232 # | / ___|_ _ ___ ___| ||_ _|__ ___ | |___ |
233 # | | | _| | | |/ _ \/ __| __|| |/ _ \ / _ \| / __| |
234 # | | |_| | |_| | __/\__ \ |_ | | (_) | (_) | \__ \ |
235 # | \____|\__,_|\___||___/\__||_|\___/ \___/|_|___/ |
237 # +----------------------------------------------------------------------+
239 # '----------------------------------------------------------------------'
242 def inventory_esx_vsphere_vm_guest_tools(info
):
243 data
= esx_vsphere_vm_convert(info
)
244 if 'guest.toolsVersionStatus' in data
:
248 def check_esx_vsphere_vm_guest_tools(_no_item
, params
, info
):
249 data
= esx_vsphere_vm_convert(info
)
252 vm_status
= data
['guest.toolsVersionStatus'][0]
257 "guestToolsCurrent": (0, "VMware Tools are installed and the version is current"),
258 "guestToolsNeedUpgrade": (1, "VMware Tools are installed, but the version is not current"),
259 "guestToolsNotInstalled": (2, "VMware Tools are not installed"),
260 "guestToolsUnmanaged": (1, "VMware Tools are installed, but are not managed by VMWare")
262 state
, info
= guest_tools_map
.get(vm_status
, (3, "Unknown status for VMware Tools"))
265 state
= params
.get(vm_status
, state
)
270 check_info
['esx_vsphere_vm.guest_tools'] = {
271 "inventory_function": inventory_esx_vsphere_vm_guest_tools
,
272 "check_function": check_esx_vsphere_vm_guest_tools
,
273 "service_description": "ESX Guest Tools",
274 "group": "vm_guest_tools"
278 # .--Heartbeat-----------------------------------------------------------.
280 # | | | | | ___ __ _ _ __| |_| |__ ___ __ _| |_ |
281 # | | |_| |/ _ \/ _` | '__| __| '_ \ / _ \/ _` | __| |
282 # | | _ | __/ (_| | | | |_| |_) | __/ (_| | |_ |
283 # | |_| |_|\___|\__,_|_| \__|_.__/ \___|\__,_|\__| |
285 # '----------------------------------------------------------------------'
288 # Possible values (this list is taken from the official documentation)
289 # gray - VMware Tools are not installed or not running.
290 # red - No heartbeat. Guest operating system may have stopped responding.
291 # yellow - Intermittent heartbeat. May be due to guest load.
292 # green - Guest operating system is responding normally.
294 def inventory_esx_vsphere_vm_hb_status(info
):
295 data
= esx_vsphere_vm_convert(info
)
296 if 'guestHeartbeatStatus' in data
:
300 def check_esx_vsphere_vm_hb_status(_no_item
, params
, info
):
301 data
= esx_vsphere_vm_convert(info
)
303 if data
.get('guestHeartbeatStatus') is None:
306 vm_status
= data
['guestHeartbeatStatus'][0]
310 "gray": (1, "heartbeat_no_tools"),
311 "green": (0, "heartbeat_ok"),
312 "red": (2, "heartbeat_missing"),
313 "yellow": (1, "heartbeat_intermittend")
315 if vm_status
in vm_heartbeat_map
:
317 state
= params
.get(vm_heartbeat_map
.get(vm_status
)[1], 3)
319 state
= vm_heartbeat_map
.get(vm_status
)[0]
320 if vm_status
== 'gray':
321 return state
, "No VMWare Tools installed, outdated or not running"
322 return state
, "Heartbeat status is %s" % vm_status
324 return 3, "Unknown heartbeat status %s" % vm_status
327 check_info
['esx_vsphere_vm.heartbeat'] = {
328 "inventory_function": inventory_esx_vsphere_vm_hb_status
,
329 "check_function": check_esx_vsphere_vm_hb_status
,
330 "service_description": "ESX Heartbeat",
331 "group": "vm_heartbeat"
335 # .--CPU-----------------------------------------------------------------.
337 # | / ___| _ \| | | | |
338 # | | | | |_) | | | | |
339 # | | |___| __/| |_| | |
342 # +----------------------------------------------------------------------+
344 # '----------------------------------------------------------------------'
346 # <<<esx_vsphere_vm>>>
347 # config.hardware.numCPU 8
348 # config.hardware.numCoresPerSocket 2
349 # summary.quickStats.overallCpuUsage 8
352 def inventory_esx_vsphere_vm_cpu(info
):
353 data
= esx_vsphere_vm_convert(info
)
354 if 'summary.quickStats.overallCpuUsage' in data
:
355 return [(None, None)]
358 def check_esx_vsphere_vm_cpu(_no_item
, _no_params
, info
):
359 data
= esx_vsphere_vm_convert(info
)
360 # VMs that are currently down do not have this entry
361 if 'summary.quickStats.overallCpuUsage' not in data
:
362 raise MKCounterWrapped("No information about CPU usage. VM is probably powered off.")
364 usage_mhz
= int(data
['summary.quickStats.overallCpuUsage'][0])
365 cpus
= int(data
['config.hardware.numCPU'][0])
366 return 0, "demand is %.3f Ghz, %d virtual CPUs" % (usage_mhz
/ 1000.0, cpus
), [("demand",
370 check_info
['esx_vsphere_vm.cpu'] = {
371 "inventory_function": inventory_esx_vsphere_vm_cpu
,
372 "check_function": check_esx_vsphere_vm_cpu
,
373 "service_description": "ESX CPU",
374 "has_perfdata": True,
378 # .--Snapshots-----------------------------------------------------------.
380 # | / ___| _ __ __ _ _ __ ___| |__ ___ | |_ ___ |
381 # | \___ \| '_ \ / _` | '_ \/ __| '_ \ / _ \| __/ __| |
382 # | ___) | | | | (_| | |_) \__ \ | | | (_) | |_\__ \ |
383 # | |____/|_| |_|\__,_| .__/|___/_| |_|\___/ \__|___/ |
385 # +----------------------------------------------------------------------+
387 # <<<esx_vsphere_vm>>>
388 # snapshot.rootSnapshotList 1 1363596734 poweredOff 20130318_105600_snapshot_LinuxI|2 1413977827 poweredOn LinuxI Testsnapshot
391 def inventory_esx_vsphere_vm_snapshots(info
):
392 data
= esx_vsphere_vm_convert(info
)
397 def check_esx_vsphere_vm_snapshots(_no_item
, params
, info
):
398 def _check_levels(age
, warn
, crit
):
400 return (2, "snapshot is older than %s" % get_age_human_readable(age
))
402 return (1, "snapshot is older than %s" % get_age_human_readable(age
))
405 data
= esx_vsphere_vm_convert(info
)
407 if 'snapshot.rootSnapshotList' not in data
:
408 yield 0, "No snapshots found"
411 Snapshot
= collections
.namedtuple("Snapshot", ["time", "state", "name"])
413 snapshots
= (x
.split(" ", 3) for x
in " ".join(data
["snapshot.rootSnapshotList"]).split("|"))
414 snapshots
= [Snapshot(int(x
[1]), x
[2], x
[3]) for x
in snapshots
]
415 yield 0, "Number of Snapshots %d" % len(snapshots
)
420 powerd_on_list
= [s
for s
in snapshots
if s
.state
== "poweredOn"]
421 yield 0, "Powered On: %s" % (', '.join(s
.name
for s
in powerd_on_list
) or "None")
423 latest_snapshot
= max(snapshots
, key
=lambda s
: s
.time
)
424 latest_snapshot_age
= time
.time() - latest_snapshot
.time
426 if params
.get("age"):
427 warn
, crit
= params
["age"]
428 state
, message
= _check_levels(latest_snapshot_age
, warn
, crit
)
430 yield state
, "Latest %s" % message
,
431 perfdata
= [("age", latest_snapshot_age
, warn
, crit
)]
433 perfdata
= [("age", latest_snapshot_age
)]
435 timestamp
= get_timestamp_human_readable(latest_snapshot
.time
)
436 yield 0, "Latest Snapshot: %s %s" % (latest_snapshot
.name
, timestamp
), perfdata
438 oldest_snapshot
= min(snapshots
, key
=lambda s
: s
.time
)
439 # Display oldest snapshot only, if it is not identical with the last snapshot
440 if oldest_snapshot
!= latest_snapshot
:
442 oldest_snapshot_age
= time
.time() - oldest_snapshot
.time
443 if params
.get("age_oldest"):
444 warn
, crit
= params
["age_oldest"]
445 state
, message
= _check_levels(oldest_snapshot_age
, warn
, crit
)
447 yield state
, "Oldest %s" % message
,
448 perfdata
= [("age_oldest", oldest_snapshot_age
, warn
, crit
)]
450 perfdata
= [("age_oldest", oldest_snapshot_age
)]
452 timestamp
= get_timestamp_human_readable(oldest_snapshot
.time
)
453 yield 0, "Oldest Snapshot: %s %s" % (oldest_snapshot
.name
, timestamp
), perfdata
456 check_info
['esx_vsphere_vm.snapshots'] = {
457 "inventory_function": inventory_esx_vsphere_vm_snapshots
,
458 "check_function": check_esx_vsphere_vm_snapshots
,
459 "service_description": "ESX Snapshots",
460 "group": "vm_snapshots",
461 "has_perfdata": True,
465 # .--VM devices----------------------------------------------------------.
467 # | \ \ / / \/ | __| | _____ _(_) ___ ___ ___ |
468 # | \ \ / /| |\/| | / _` |/ _ \ \ / / |/ __/ _ \/ __| |
469 # | \ V / | | | | | (_| | __/\ V /| | (_| __/\__ \ |
470 # | \_/ |_| |_| \__,_|\___| \_/ |_|\___\___||___/ |
472 # '----------------------------------------------------------------------'
475 def parse_esx_vsphere_vm_mounted_devices(info
):
476 data
= esx_vsphere_vm_convert(info
).get("config.hardware.device", [])
478 for device_data
in " ".join(data
).split("@@"):
479 if "|" not in device_data
:
482 for entry
in device_data
.split("|"):
483 k
, v
= entry
.split(" ", 1)
484 device_attrs
.setdefault(k
, v
)
485 device_name
= device_attrs
["label"]
486 del device_attrs
["label"]
487 parsed
.setdefault(device_name
, device_attrs
)
491 def inventory_esx_vsphere_vm_mounted_devices(info
):
492 if parse_esx_vsphere_vm_mounted_devices(info
):
493 return [(None, None)]
496 def check_esx_vsphere_vm_mounted_devices(item
, params
, info
):
497 device_types
= ['VirtualCdrom', 'VirtualFloppy']
499 for device_name
, attrs
in parse_esx_vsphere_vm_mounted_devices(info
).iteritems():
500 if attrs
['virtualDeviceType'] in device_types
and \
501 attrs
['connected'] == 'true':
502 mounted_devices
.append(device_name
)
505 return 1, "HA functionality not guaranteed, Mounted devices: %s" % \
506 ", ".join(mounted_devices
)
507 return 0, "HA functionality guaranteed"
510 check_info
['esx_vsphere_vm.mounted_devices'] = {
511 "inventory_function": inventory_esx_vsphere_vm_mounted_devices
,
512 "check_function": check_esx_vsphere_vm_mounted_devices
,
513 "service_description": "ESX Mounted Devices",