Using pyVmomi to configure vSAN disk groups on an ESXi Host
This time we are using pyVmomi configure vSAN disk groups on an ESXi host. With vSAN disk groups, we have disks that are used as cache drives and disks that are used as capacity drives. As noted in the link from VMware “Disk groups contain at most 1 cache device and between 1 to 7 capacity devices.” In our use case, the cache drives are smaller than the capacity drives. Thus, our script sorts into a “smallerSize” list and appends the cache drives there. This is after starting with a baseline size above 300GB (we want to ignore anything that small that happens to be attached, like say a SATADOM) Like our script share from previously with vSAN, download the vSAN Management SDK for Python, as VMware has not put this library on Pypi.
As before, you will most likely also want to use something like argparse instead of hard coding like I do in the examples here.
Later I plan on sharing a simple argparse vc connection script and also demonstrating how to use your debugger (in VS Code or in Pycharm) to manipulate and understand pyVmomi objects and methods.
'''
Configures the esxi host for vSan. This includes sorting found flash drives (only doing flash for now, no hybrid)
and then tagging/creating the "cache" and "capacity" disk groups
relies on vsanapituils.py and vsanmgmtObjects.py
hard coded variables for now that should change include vCenter, esxihost, vCenter pw
also, if vsan disks are already configured, then none will be found and program exits.
marcus_sharp 11/24/2020
'''
import atexit
import ssl
from pyVim import connect
from pyVmomi import vim
# import the VSAN API python bindings
# have to download these manually and extract from https://code.vmware.com/web/sdk/7.0%20U1/vsan-python
import vsanmgmtObjects
import vsanapiutils
def main():
server = 'vcenter'
si = vc_connect(server)
atexit.register(connect.Disconnect, si)
dc = si.content.rootFolder.childEntity[0] # first datacenter
content = si.RetrieveContent()
esxihost = get_obj(content, [vim.HostSystem], 'esxi_host')
if esxihost is None:
print(f'Failed to find {esxihost} in datacenter {dc.name}')
else:
# https://www.tachytelic.net/2014/03/posix-size-converter/
# formula for bock to GB conversion = Number Of 512 byte blocks/2/1024/1024
diskmap = {esxihost: {'cache': [], 'capacity': []}}
cacheDisks = []
capacityDisks = []
result = esxihost.configManager.vsanSystem.QueryDisksForVsan()
ssds = []
for ssd in result:
if ssd.state == 'eligible' and (ssd.disk.capacity.block) / 2 / 1024 / 1024 > 300:
ssds.append(ssd.disk)
# https://bit.ly/37lvGc3 vSAN SDKs Programming Guide
if ssds:
smallerSize = min([disk.capacity.block * disk.capacity.blockSize for disk in ssds])
for ssd in ssds:
size = ssd.capacity.block * ssd.capacity.blockSize
if size == smallerSize:
diskmap[esxihost]['cache'].append(ssd)
cacheDisks.append((ssd.displayName, size, esxihost.name))
else:
diskmap[esxihost]['capacity'].append(ssd)
capacityDisks.append((ssd.displayName, size, esxihost.name))
for host, disks in diskmap.items():
if disks['cache'] and disks['capacity']:
dm = vim.VimVsanHostDiskMappingCreationSpec(
cacheDisks=disks['cache'], capacityDisks=disks['capacity'],
creationType='allFlash',
host=host)
# Execute the task
tasks = []
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
# next two lines from https://github.com/storage-code/vsanDeploy/blob/master/vsanDeploy.py
vcMos = vsanapiutils.GetVsanVcMos(si._stub, context=context)
vsanVcDiskManagementSystem = vcMos['vsan-disk-management-system']
task = vsanVcDiskManagementSystem.InitializeDiskMappings(dm)
tasks.append(task)
vsanapiutils.WaitForTasks(tasks, si)
else:
print('no disks to add')
exit()
def get_obj(content, vimtype, name):
obj = None
container = content.viewManager.CreateContainerView(
content.rootFolder, vimtype, True)
for c in container.view:
if c.name == name:
obj = c
break
return obj
def vc_connect(vc):
# Disabling SSL warnings
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
service_instance = None
try:
print(f'attempting to connect to {vc}')
service_instance = connect.SmartConnect(host=vc,
user='vcenter_admin_here',
pwd='passwordhere',
port=443,
sslContext=context)
except IOError as e:
pass
if not service_instance:
raise SystemExit("Unable to connect to host with supplied info.")
return service_instance
if __name__ == '__main__':
main()
As always, hope this helps out someone.