#!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright: Ansible Project # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} DOCUMENTATION = ''' --- module: vmware_guest_find short_description: Find the folder path(s) for a VM by name or UUID description: - Find the folder path(s) for a VM by name or UUID version_added: 2.4 author: - James Tanner notes: - Tested on vSphere 6.5 requirements: - "python >= 2.6" - PyVmomi options: name: description: - Name of the VM to work with. - This is required if uuid is not supplied. uuid: description: - UUID of the instance to manage if known, this is VMware's BIOS UUID. - This is required if name is not supplied. datacenter: description: - Destination datacenter for the find operation. required: True extends_documentation_fragment: vmware.documentation ''' EXAMPLES = ''' - name: Find Guest's Folder using name vmware_guest_find: hostname: 192.168.1.209 username: administrator@vsphere.local password: vmware validate_certs: no name: testvm register: vm_folder - name: Find Guest's Folder using UUID vmware_guest_find: hostname: 192.168.1.209 username: administrator@vsphere.local password: vmware validate_certs: no uuid: 38c4c89c-b3d7-4ae6-ae4e-43c5118eae49 register: vm_folder ''' RETURN = """ """ import os from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_native from ansible.module_utils.vmware import ( connect_to_api, gather_vm_facts, get_all_objs, compile_folder_path_for_object, vmware_argument_spec, find_datacenter_by_name ) try: import pyVmomi from pyVmomi import vim HAS_PYVMOMI = True except ImportError: HAS_PYVMOMI = False class PyVmomiHelper(object): def __init__(self, module): if not HAS_PYVMOMI: module.fail_json(msg='pyvmomi module required') self.datacenter = None self.folders = None self.foldermap = { 'fvim_by_path': {}, 'path_by_fvim': {}, 'path_by_vvim': {}, 'paths': {}, 'uuids': {} } self.module = module self.params = module.params self.content = connect_to_api(self.module) def getvm_folder_paths(self, name=None, uuid=None): results = [] 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 # Match by name or uuid if vobj.config.name == name or vobj.config.uuid == uuid: folderpath = compile_folder_path_for_object(vobj) results.append(folderpath) return results def gather_facts(self, vm): return gather_vm_facts(self.content, vm) def _build_folder_tree(self, folder): 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.datacenter = find_datacenter_by_name(self.content, self.params['datacenter']) if self.datacenter is None: self.module.fail_json(msg="Unable to find datacenter %(datacenter)s" % self.params) self.folders = self._build_folder_tree(self.datacenter.vmFolder) self._build_folder_map(self.folders) def main(): argument_spec = vmware_argument_spec() argument_spec.update( name=dict(type='str'), uuid=dict(type='str'), datacenter=dict(type='str', required=True) ) module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['name', 'uuid']]) pyv = PyVmomiHelper(module) # Check if the VM exists before continuing folders = pyv.getvm_folder_paths( name=module.params['name'], uuid=module.params['uuid'] ) # VM already exists if folders: try: module.exit_json(folders=folders) except Exception as exc: module.fail_json(msg="Folder enumeration failed with exception %s" % to_native(exc)) else: msg = "Unable to find folders for VM " if module.params['name']: msg += "%(name)s" % module.params elif module.params['uuid']: msg += "%(uuid)s" % module.params module.fail_json(msg=msg) if __name__ == '__main__': main()