mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
vmware_guest: Amazing speed up module (#19937)
* vmware_guest: Amazing speed up module * vmware_guest: Change variables name to do PEP compliant
This commit is contained in:
parent
c10c7aa67b
commit
add06b505a
1 changed files with 22 additions and 170 deletions
|
@ -75,7 +75,7 @@ options:
|
||||||
version_added: "2.3"
|
version_added: "2.3"
|
||||||
folder:
|
folder:
|
||||||
description:
|
description:
|
||||||
- Destination folder path for the new VM
|
- Destination folder, absolute path to find an existing guest or create the new guest
|
||||||
required: False
|
required: False
|
||||||
hardware:
|
hardware:
|
||||||
description:
|
description:
|
||||||
|
@ -526,10 +526,6 @@ class PyVmomiHelper(object):
|
||||||
self.params = module.params
|
self.params = module.params
|
||||||
self.si = None
|
self.si = None
|
||||||
self.content = connect_to_api(self.module)
|
self.content = connect_to_api(self.module)
|
||||||
self.datacenter = None
|
|
||||||
self.folders = None
|
|
||||||
self.foldermap = {'fvim_by_path': {}, 'path_by_fvim': {}, 'path_by_vvim': {}, 'paths': {},
|
|
||||||
'uuids': {}}
|
|
||||||
self.configspec = None
|
self.configspec = None
|
||||||
self.change_detected = False
|
self.change_detected = False
|
||||||
self.customspec = None
|
self.customspec = None
|
||||||
|
@ -539,94 +535,7 @@ class PyVmomiHelper(object):
|
||||||
def should_deploy_from_template(self):
|
def should_deploy_from_template(self):
|
||||||
return self.params.get('template') is not None
|
return self.params.get('template') is not None
|
||||||
|
|
||||||
def _build_folder_tree(self, folder):
|
def getvm(self, name=None, uuid=None, folder=None):
|
||||||
|
|
||||||
tree = {'virtualmachines': [],
|
|
||||||
'subfolders': {},
|
|
||||||
'vimobj': folder,
|
|
||||||
'name': folder.name}
|
|
||||||
|
|
||||||
children = None
|
|
||||||
if hasattr(folder, 'childEntity'):
|
|
||||||
children = folder.childEntity
|
|
||||||
|
|
||||||
if children:
|
|
||||||
for child in children:
|
|
||||||
if child == folder or child in tree:
|
|
||||||
continue
|
|
||||||
if isinstance(child, vim.Folder):
|
|
||||||
ctree = self._build_folder_tree(child)
|
|
||||||
tree['subfolders'][child] = dict.copy(ctree)
|
|
||||||
elif isinstance(child, vim.VirtualMachine):
|
|
||||||
tree['virtualmachines'].append(child)
|
|
||||||
else:
|
|
||||||
if isinstance(folder, vim.VirtualMachine):
|
|
||||||
return folder
|
|
||||||
return tree
|
|
||||||
|
|
||||||
def _build_folder_map(self, folder, inpath='/'):
|
|
||||||
|
|
||||||
""" Build a searchable index for vms+uuids+folders """
|
|
||||||
if isinstance(folder, tuple):
|
|
||||||
folder = folder[1]
|
|
||||||
|
|
||||||
thispath = os.path.join(inpath, folder['name'])
|
|
||||||
|
|
||||||
if thispath not in self.foldermap['paths']:
|
|
||||||
self.foldermap['paths'][thispath] = []
|
|
||||||
|
|
||||||
# store object by path and store path by object
|
|
||||||
self.foldermap['fvim_by_path'][thispath] = folder['vimobj']
|
|
||||||
self.foldermap['path_by_fvim'][folder['vimobj']] = thispath
|
|
||||||
|
|
||||||
for item in folder.items():
|
|
||||||
k = item[0]
|
|
||||||
v = item[1]
|
|
||||||
|
|
||||||
if k == 'name':
|
|
||||||
pass
|
|
||||||
elif k == 'subfolders':
|
|
||||||
for x in v.items():
|
|
||||||
self._build_folder_map(x, inpath=thispath)
|
|
||||||
elif k == 'virtualmachines':
|
|
||||||
for x in v:
|
|
||||||
# Apparently x.config can be None on corrupted VMs
|
|
||||||
if x.config is None: continue
|
|
||||||
self.foldermap['uuids'][x.config.uuid] = x.config.name
|
|
||||||
self.foldermap['paths'][thispath].append(x.config.uuid)
|
|
||||||
|
|
||||||
if x not in self.foldermap['path_by_vvim']:
|
|
||||||
self.foldermap['path_by_vvim'][x] = thispath
|
|
||||||
|
|
||||||
def getfolders(self):
|
|
||||||
if not self.datacenter:
|
|
||||||
self.get_datacenter()
|
|
||||||
self.folders = self._build_folder_tree(self.datacenter.vmFolder)
|
|
||||||
self._build_folder_map(self.folders)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def compile_folder_path_for_object(vobj):
|
|
||||||
""" make a /vm/foo/bar/baz like folder path for an object """
|
|
||||||
|
|
||||||
paths = []
|
|
||||||
if isinstance(vobj, vim.Folder):
|
|
||||||
paths.append(vobj.name)
|
|
||||||
|
|
||||||
thisobj = vobj
|
|
||||||
while hasattr(thisobj, 'parent'):
|
|
||||||
thisobj = thisobj.parent
|
|
||||||
if isinstance(thisobj, vim.Folder):
|
|
||||||
paths.append(thisobj.name)
|
|
||||||
paths.reverse()
|
|
||||||
if paths[0] == 'Datacenters':
|
|
||||||
paths.remove('Datacenters')
|
|
||||||
return '/' + '/'.join(paths)
|
|
||||||
|
|
||||||
def get_datacenter(self):
|
|
||||||
self.datacenter = get_obj(self.content, [vim.Datacenter],
|
|
||||||
self.params['datacenter'])
|
|
||||||
|
|
||||||
def getvm(self, name=None, uuid=None, folder=None, name_match=None, cache=False):
|
|
||||||
|
|
||||||
# https://www.vmware.com/support/developer/vc-sdk/visdk2xpubs/ReferenceGuide/vim.SearchIndex.html
|
# https://www.vmware.com/support/developer/vc-sdk/visdk2xpubs/ReferenceGuide/vim.SearchIndex.html
|
||||||
# self.si.content.searchIndex.FindByInventoryPath('DC1/vm/test_folder')
|
# self.si.content.searchIndex.FindByInventoryPath('DC1/vm/test_folder')
|
||||||
|
@ -641,71 +550,23 @@ class PyVmomiHelper(object):
|
||||||
if self.params['folder'].startswith('/'):
|
if self.params['folder'].startswith('/'):
|
||||||
searchpath = '%(datacenter)s%(folder)s' % self.params
|
searchpath = '%(datacenter)s%(folder)s' % self.params
|
||||||
else:
|
else:
|
||||||
# need to look for matching absolute path
|
self.module.fail_json(msg="Folder %(folder)s needs to be an absolute path, starting with '/'." % self.params)
|
||||||
if not self.folders:
|
|
||||||
self.getfolders()
|
|
||||||
paths = self.foldermap['paths'].keys()
|
|
||||||
paths = [x for x in paths if x.endswith(self.params['folder'])]
|
|
||||||
if len(paths) > 1:
|
|
||||||
self.module.fail_json(
|
|
||||||
msg='%(folder)s matches more than one folder. Please use the absolute path starting with /vm/' % self.params)
|
|
||||||
elif paths:
|
|
||||||
searchpath = paths[0]
|
|
||||||
|
|
||||||
if searchpath:
|
if searchpath:
|
||||||
# get all objects for this path ...
|
# get all objects for this path ...
|
||||||
fObj = self.content.searchIndex.FindByInventoryPath(searchpath)
|
f_obj = self.content.searchIndex.FindByInventoryPath(searchpath)
|
||||||
if fObj:
|
if f_obj:
|
||||||
if isinstance(fObj, vim.Datacenter):
|
if isinstance(f_obj, vim.Datacenter):
|
||||||
fObj = fObj.vmFolder
|
f_obj = f_obj.vmFolder
|
||||||
for cObj in fObj.childEntity:
|
for c_obj in f_obj.childEntity:
|
||||||
if not isinstance(cObj, vim.VirtualMachine):
|
if not isinstance(c_obj, vim.VirtualMachine):
|
||||||
continue
|
continue
|
||||||
if cObj.name == name:
|
if c_obj.name == name:
|
||||||
vm = cObj
|
vm = c_obj
|
||||||
break
|
if self.params['name_match'] == 'first':
|
||||||
|
break
|
||||||
|
|
||||||
if not vm:
|
if vm:
|
||||||
# FIXME - this is unused if folder has a default value
|
|
||||||
# narrow down by folder
|
|
||||||
if folder:
|
|
||||||
if not self.folders:
|
|
||||||
self.getfolders()
|
|
||||||
|
|
||||||
# compare the folder path of each VM against the search path
|
|
||||||
vmList = get_all_objs(self.content, [vim.VirtualMachine])
|
|
||||||
for item in vmList.items():
|
|
||||||
vobj = item[0]
|
|
||||||
if not isinstance(vobj.parent, vim.Folder):
|
|
||||||
continue
|
|
||||||
if self.compile_folder_path_for_object(vobj) == searchpath:
|
|
||||||
# Match by name
|
|
||||||
if vobj.config.name == name:
|
|
||||||
self.current_vm_obj = vobj
|
|
||||||
return vobj
|
|
||||||
|
|
||||||
if name_match:
|
|
||||||
if name_match == 'first':
|
|
||||||
vm = get_obj(self.content, [vim.VirtualMachine], name)
|
|
||||||
elif name_match == 'last':
|
|
||||||
matches = []
|
|
||||||
for thisvm in get_all_objs(self.content, [vim.VirtualMachine]):
|
|
||||||
if thisvm.config.name == name:
|
|
||||||
matches.append(thisvm)
|
|
||||||
if matches:
|
|
||||||
vm = matches[-1]
|
|
||||||
else:
|
|
||||||
matches = []
|
|
||||||
for thisvm in get_all_objs(self.content, [vim.VirtualMachine]):
|
|
||||||
if thisvm.config.name == name:
|
|
||||||
matches.append(thisvm)
|
|
||||||
if len(matches) > 1:
|
|
||||||
self.module.fail_json(
|
|
||||||
msg='More than 1 VM exists by the name %s. Please specify a uuid, or a folder, '
|
|
||||||
'or a datacenter or name_match' % name)
|
|
||||||
if matches:
|
|
||||||
vm = matches[0]
|
|
||||||
if cache and vm:
|
|
||||||
self.current_vm_obj = vm
|
self.current_vm_obj = vm
|
||||||
|
|
||||||
return vm
|
return vm
|
||||||
|
@ -1314,22 +1175,15 @@ class PyVmomiHelper(object):
|
||||||
if not datacenter:
|
if not datacenter:
|
||||||
self.module.fail_json(msg='No datacenter named %(datacenter)s was found' % self.params)
|
self.module.fail_json(msg='No datacenter named %(datacenter)s was found' % self.params)
|
||||||
|
|
||||||
# find matching folders
|
destfolder = None
|
||||||
if self.params['folder'].startswith('/'):
|
if not self.params['folder'].startswith('/'):
|
||||||
folders = [x for x in self.foldermap['fvim_by_path'].items() if x[0] == self.params['folder']]
|
self.module.fail_json(msg="Folder %(folder)s needs to be an absolute path, starting with '/'." % self.params)
|
||||||
else:
|
|
||||||
folders = [x for x in self.foldermap['fvim_by_path'].items() if x[0].endswith(self.params['folder'])]
|
|
||||||
|
|
||||||
# throw error if more than one match or no matches
|
f_obj = self.content.searchIndex.FindByInventoryPath('/%(datacenter)s%(folder)s' % self.params)
|
||||||
if len(folders) == 0:
|
if f_obj is None:
|
||||||
self.module.fail_json(msg='No folder matched the path: %(folder)s' % self.params)
|
self.module.fail_json(msg='No folder matched the path: %(folder)s' % self.params)
|
||||||
elif len(folders) > 1:
|
destfolder = f_obj
|
||||||
self.module.fail_json(
|
|
||||||
msg='Too many folders matched "%s", please give the full path starting with /vm/' % self.params[
|
|
||||||
'folder'])
|
|
||||||
|
|
||||||
# grab the folder vim object
|
|
||||||
destfolder = folders[0][1]
|
|
||||||
hostsystem = self.select_host()
|
hostsystem = self.select_host()
|
||||||
|
|
||||||
if self.should_deploy_from_template():
|
if self.should_deploy_from_template():
|
||||||
|
@ -1648,7 +1502,7 @@ def main():
|
||||||
disk=dict(required=False, type='list', default=[]),
|
disk=dict(required=False, type='list', default=[]),
|
||||||
hardware=dict(required=False, type='dict', default={}),
|
hardware=dict(required=False, type='dict', default={}),
|
||||||
force=dict(required=False, type='bool', default=False),
|
force=dict(required=False, type='bool', default=False),
|
||||||
datacenter=dict(required=False, type='str', default=None),
|
datacenter=dict(required=True, type='str'),
|
||||||
esxi_hostname=dict(required=False, type='str', default=None),
|
esxi_hostname=dict(required=False, type='str', default=None),
|
||||||
cluster=dict(required=False, type='str', default=None),
|
cluster=dict(required=False, type='str', default=None),
|
||||||
wait_for_ip_address=dict(required=False, type='bool', default=True),
|
wait_for_ip_address=dict(required=False, type='bool', default=True),
|
||||||
|
@ -1677,9 +1531,7 @@ def main():
|
||||||
# Check if the VM exists before continuing
|
# Check if the VM exists before continuing
|
||||||
vm = pyv.getvm(name=module.params['name'],
|
vm = pyv.getvm(name=module.params['name'],
|
||||||
folder=module.params['folder'],
|
folder=module.params['folder'],
|
||||||
uuid=module.params['uuid'],
|
uuid=module.params['uuid'])
|
||||||
name_match=module.params['name_match'],
|
|
||||||
cache=True)
|
|
||||||
|
|
||||||
# VM already exists
|
# VM already exists
|
||||||
if vm:
|
if vm:
|
||||||
|
|
Loading…
Reference in a new issue