check_vcenter_multipath
This commit is contained in:
parent
ed17eca658
commit
3945f50999
176
check_vcenter_multipath
Executable file
176
check_vcenter_multipath
Executable file
@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
from pyVmomi import vim
|
||||
import pyVim.connect
|
||||
import sys
|
||||
import atexit
|
||||
import argparse
|
||||
import re
|
||||
import siteconf
|
||||
|
||||
class Main:
|
||||
def __init__(self):
|
||||
self.ok = []
|
||||
self.warning = []
|
||||
self.critical = []
|
||||
self.site_conf = siteconf.read()
|
||||
self.get_args()
|
||||
|
||||
def get_args(self):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='check multipath redundancy')
|
||||
|
||||
parser.add_argument('-s', '--site',
|
||||
required=True,
|
||||
action='store',
|
||||
help='name of the site to connect to')
|
||||
|
||||
parser.add_argument('-H', '--host',
|
||||
required=True,
|
||||
action='store',
|
||||
help='host to check')
|
||||
|
||||
self.args = parser.parse_args()
|
||||
|
||||
def run(self):
|
||||
self.connect()
|
||||
host = self.get_obj([vim.HostSystem], self.args.host)
|
||||
if not host:
|
||||
print("host not found")
|
||||
exit(1)
|
||||
self.pathcheck(host)
|
||||
self.status_exit()
|
||||
|
||||
def map_uuid_to_datastore(self, host):
|
||||
canonical_datastore = {}
|
||||
for ds in host.datastore:
|
||||
try:
|
||||
vmfs = ds.info.vmfs
|
||||
except:
|
||||
continue # not vmfs
|
||||
for ext in vmfs.extent:
|
||||
canonical_datastore[ext.diskName] = {
|
||||
'name': vmfs.name,
|
||||
'local': vmfs.local
|
||||
}
|
||||
|
||||
self.uuid_datastore = {}
|
||||
for lun in host.config.storageDevice.scsiLun:
|
||||
ds = canonical_datastore.get(lun.canonicalName)
|
||||
if not ds:
|
||||
continue # not a datastore
|
||||
#print(f"uuid {lun.uuid} name {ds['name']} local {ds['local']}")
|
||||
self.uuid_datastore[lun.uuid] = ds
|
||||
|
||||
def pathcheck(self, host):
|
||||
self.map_uuid_to_datastore(host)
|
||||
storage_system = host.configManager.storageSystem
|
||||
multipath_info = storage_system.storageDeviceInfo.multipathInfo
|
||||
if multipath_info is None:
|
||||
self.critical.append("no multipath info")
|
||||
return
|
||||
for lun in multipath_info.lun:
|
||||
ds = self.uuid_datastore.get(lun.id)
|
||||
if not ds:
|
||||
#print(f"lun {lun.id} is not a datastore")
|
||||
continue # not a datastore
|
||||
|
||||
active, standby, dead, other = [], [], [], []
|
||||
for path in lun.path:
|
||||
#print(f"{path.name} {path.pathState} {path.adapter} {path.transport.__class__.__name__ if path.transport else '?'}")
|
||||
if path.pathState == 'active':
|
||||
active.append(path)
|
||||
elif path.pathState == 'standby':
|
||||
standby.append(path)
|
||||
elif path.pathState == 'dead':
|
||||
dead.append(path)
|
||||
else:
|
||||
other.append(path)
|
||||
|
||||
if ds['local']:
|
||||
minpath = 1
|
||||
prefix = f"{ds['name']} (local)"
|
||||
elif re.search(r'-local\d?$', ds['name']):
|
||||
minpath = 1
|
||||
prefix = f"{ds['name']} (local-by-name)"
|
||||
else:
|
||||
minpath = 2
|
||||
prefix = f"{ds['name']}"
|
||||
paths = f"{len(active)}+{len(standby)} active/standby"
|
||||
if len(dead) > 0:
|
||||
paths += f", {len(dead)}"
|
||||
if len(other) > 0:
|
||||
for path in other:
|
||||
paths += f", 1 {path.pathState}"
|
||||
paths += " paths"
|
||||
if len(active) + len(standby) < minpath:
|
||||
self.critical.append(f"{prefix} NOT REDUNDANT: {paths}")
|
||||
elif len(dead) > 0:
|
||||
self.critical.append(f"{prefix} DEAD PATH: {paths}")
|
||||
elif len(other) > 0:
|
||||
self.warning.append(f"{prefix} OTHER STATE: {paths}")
|
||||
else:
|
||||
self.ok.append(f"{prefix}: {paths}")
|
||||
|
||||
def connect(self):
|
||||
if not self.args.site in self.site_conf:
|
||||
print(f"site not found: {self.args.site}")
|
||||
exit(1)
|
||||
host = self.site_conf[self.args.site]['vcenter']
|
||||
user = self.site_conf[self.args.site]['vcenter_user']
|
||||
passwd = self.site_conf[self.args.site]['vcenter_passwd']
|
||||
|
||||
si = pyVim.connect.SmartConnect(
|
||||
host = host,
|
||||
user = user,
|
||||
pwd = passwd,
|
||||
disableSslCertValidation = True
|
||||
)
|
||||
atexit.register(pyVim.connect.Disconnect, si)
|
||||
self.content = si.RetrieveContent()
|
||||
|
||||
def get_obj(self, vimtype, name):
|
||||
"""
|
||||
Return an object by name, if name is None the
|
||||
first found object is returned
|
||||
"""
|
||||
obj = None
|
||||
container = self.content.viewManager.CreateContainerView(
|
||||
self.content.rootFolder, vimtype, True)
|
||||
for c in container.view:
|
||||
if name:
|
||||
if c.name == name:
|
||||
obj = c
|
||||
break
|
||||
else:
|
||||
obj = c
|
||||
break
|
||||
|
||||
return obj
|
||||
|
||||
def status_exit(self):
|
||||
message = []
|
||||
exitcode = 0
|
||||
if len(self.critical) > 0:
|
||||
exitcode = 2
|
||||
message.append("CRITICAL: "+ " / ".join(self.critical))
|
||||
if len(self.warning) > 0:
|
||||
if exitcode == 0:
|
||||
exitcode = 1
|
||||
message.append("WARNING: "+ " / ".join(self.warning))
|
||||
if exitcode > 0:
|
||||
print(" / ".join(message))
|
||||
sys.exit(exitcode)
|
||||
|
||||
print("OK: "+ " / ".join(self.ok))
|
||||
sys.exit(exitcode)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
Main().run()
|
||||
except Exception as e:
|
||||
print(f"UNKNOWN: {e}")
|
||||
print(type(e))
|
||||
sys.exit(3)
|
||||
|
||||
# vim: set tabstop=4 shiftwidth=4 expandtab smarttab:
|
||||
Loading…
x
Reference in New Issue
Block a user