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:
aperigault 2017-01-24 17:42:37 +01:00 committed by jctanner
parent c10c7aa67b
commit add06b505a

View file

@ -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
if self.params['name_match'] == 'first':
break 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: