#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2018, Abhijeet Kasurde # 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 = r''' --- module: vcenter_folder short_description: Manage folders on given datacenter description: - This module can be used to create, delete, move and rename folder on then given datacenter. version_added: '2.5' author: - Abhijeet Kasurde (@Akasurde) notes: - Tested on vSphere 6.5 requirements: - python >= 2.6 - PyVmomi options: datacenter: description: - Name of the datacenter. required: True folder_name: description: - Name of folder to be managed. - This is case sensitive parameter. - Folder name should be under 80 characters. This is a VMware restriction. required: True parent_folder: description: - Name of the parent folder under which new folder needs to be created. - This is case sensitive parameter. - Please specify unique folder name as there is no way to detect duplicate names. - "If user wants to create a folder under '/DC0/vm/vm_folder', this value will be 'vm_folder'." required: False folder_type: description: - This is type of folder. - "If set to C(vm), then 'VM and Template Folder' is created under datacenter." - "If set to C(host), then 'Host and Cluster Folder' is created under datacenter." - "If set to C(datastore), then 'Storage Folder' is created under datacenter." - "If set to C(network), then 'Network Folder' is created under datacenter." - This parameter is required, if C(state) is set to C(present) and parent_folder is absent. - This option is ignored, if C(parent_folder) is set. default: vm required: False choices: [ datastore, host, network, vm ] state: description: - State of folder. - If set to C(present) without parent folder parameter, then folder with C(folder_type) is created. - If set to C(present) with parent folder parameter, then folder in created under parent folder. C(folder_type) is ignored. - If set to C(absent), then folder is unregistered and destroyed. default: present choices: [ present, absent ] extends_documentation_fragment: vmware.documentation ''' EXAMPLES = r''' - name: Create a VM folder on given datacenter vcenter_folder: hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' password: '{{ vcenter_password }}' datacenter: datacenter_name folder_name: sample_vm_folder folder_type: vm state: present register: vm_folder_creation_result delegate_to: localhost - name: Create a datastore folder on given datacenter vcenter_folder: hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' password: '{{ vcenter_password }}' datacenter: datacenter_name folder_name: sample_datastore_folder folder_type: datastore state: present register: datastore_folder_creation_result delegate_to: localhost - name: Create a sub folder under VM folder on given datacenter vcenter_folder: hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' password: '{{ vcenter_password }}' datacenter: datacenter_name folder_name: sample_sub_folder parent_folder: vm_folder state: present register: sub_folder_creation_result delegate_to: localhost - name: Delete a VM folder on given datacenter vcenter_folder: hostname: '{{ vcenter_hostname }}' username: '{{ vcenter_username }}' password: '{{ vcenter_password }}' datacenter: datacenter_name folder_name: sample_vm_folder folder_type: vm state: absent register: vm_folder_deletion_result delegate_to: localhost ''' RETURN = r''' result: description: - string stating about result returned: success type: string sample: "Folder 'sub_network_folder' of type 'vm' created under vm_folder successfully." ''' try: from pyVmomi import vim except ImportError as e: pass from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.vmware import vmware_argument_spec, PyVmomi, find_datacenter_by_name, wait_for_task, get_all_objs from ansible.module_utils._text import to_native class VmwareFolderManager(PyVmomi): def __init__(self, module): super(VmwareFolderManager, self).__init__(module) datacenter_name = self.params.get('datacenter', None) self.datacenter_obj = find_datacenter_by_name(self.content, datacenter_name=datacenter_name) if self.datacenter_obj is None: self.module.fail_json(msg="Failed to find datacenter %s" % datacenter_name) def ensure(self): """ Function to manage internal state management Returns: """ state = self.module.params.get('state') folder_type = self.module.params.get('folder_type') folder_name = self.module.params.get('folder_name') parent_folder = self.module.params.get('parent_folder', None) results = dict(changed=False, result=dict()) if state == 'present': # Create a new folder try: if parent_folder: folder = self.get_folder_by_name(folder_name=parent_folder) if folder and not self.get_folder_by_name(folder_name=folder_name, parent_folder=folder): folder.CreateFolder(folder_name) results['changed'] = True results['result'] = "Folder '%s' of type '%s' created under %s" \ " successfully." % (folder_name, folder_type, parent_folder) elif folder is None: self.module.fail_json(msg="Failed to find the parent folder %s" " for folder %s" % (parent_folder, folder_name)) else: datacenter_folder_type = { 'vm': self.datacenter_obj.vmFolder, 'host': self.datacenter_obj.hostFolder, 'datastore': self.datacenter_obj.datastoreFolder, 'network': self.datacenter_obj.networkFolder, } datacenter_folder_type[folder_type].CreateFolder(folder_name) results['changed'] = True results['result'] = "Folder '%s' of type '%s' created successfully" % (folder_name, folder_type) except vim.fault.DuplicateName as duplicate_name: # To be consistent with the other vmware modules, We decided to accept this error # and the playbook should simply carry on with other tasks. # User will have to take care of this exception # https://github.com/ansible/ansible/issues/35388#issuecomment-362283078 results['changed'] = False results['result'] = "Failed to create folder as another object has same name" \ " in the same target folder : %s" % to_native(duplicate_name.msg) except vim.fault.InvalidName as invalid_name: self.module.fail_json(msg="Failed to create folder as folder name is not a valid " "entity name : %s" % to_native(invalid_name.msg)) except Exception as general_exc: self.module.fail_json(msg="Failed to create folder due to generic" " exception : %s " % to_native(general_exc)) self.module.exit_json(**results) elif state == 'absent': folder_obj = self.get_folder_by_name(folder_name=folder_name) if folder_obj: try: task = folder_obj.UnregisterAndDestroy() results['changed'], results['result'] = wait_for_task(task=task) except vim.fault.ConcurrentAccess as concurrent_access: self.module.fail_json(msg="Failed to remove folder as another client" " modified folder before this operation : %s" % to_native(concurrent_access.msg)) except vim.fault.InvalidState as invalid_state: self.module.fail_json(msg="Failed to remove folder as folder is in" " invalid state" % to_native(invalid_state.msg)) except Exception as e: self.module.fail_json(msg="Failed to remove folder due to generic" " exception %s " % to_native(e)) self.module.exit_json(**results) def get_folder_by_name(self, folder_name, parent_folder=None): """ Function to get managed object of folder by name Returns: Managed object of folder by name """ folder_objs = get_all_objs(self.content, [vim.Folder], parent_folder) for folder in folder_objs: if folder.name == folder_name: return folder return None def main(): argument_spec = vmware_argument_spec() argument_spec.update( datacenter=dict(type='str', required=True), folder_name=dict(type='str', required=True), parent_folder=dict(type='str', required=False), state=dict(type='str', choices=['present', 'absent'], default='present'), folder_type=dict(type='str', default='vm', choices=['datastore', 'host', 'network', 'vm'], required=False), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=False, ) if len(module.params.get('folder_name')) > 79: module.fail_json(msg="Failed to manage folder as folder_name can only contain 80 characters.") vcenter_folder_mgr = VmwareFolderManager(module) vcenter_folder_mgr.ensure() if __name__ == "__main__": main()