From 68de5791a35d3622d51469343bc5f4ed7aa4144c Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 5 Feb 2018 22:21:08 +0530 Subject: [PATCH] VMware: vmware_guest_file_operation refactor (#35560) Signed-off-by: Abhijeet Kasurde --- .../vmware/vmware_guest_file_operation.py | 447 +++++++++--------- 1 file changed, 233 insertions(+), 214 deletions(-) diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py b/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py index 9ed184b4970..ae977d8a665 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py +++ b/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py @@ -1,15 +1,15 @@ #!/usr/bin/python # -*- coding: utf-8 -*- - # Copyright: (c) 2017, Stéphane Travassac # 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'} +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} DOCUMENTATION = ''' --- @@ -38,7 +38,7 @@ options: - If set, it will help to speed up virtual machine search. folder: description: - - Destination folder, absolute or relative path to find an existing guest or create the new guest. + - Destination folder, absolute path to find an existing guest or create the new guest. - The folder should include the datacenter. ESX's datacenter is ha-datacenter - Used only if C(vm_id_type) is C(inventory_path). - 'Examples:' @@ -161,187 +161,248 @@ import os from ansible.module_utils.basic import AnsibleModule from ansible.module_utils import urls from ansible.module_utils._text import to_bytes, to_native -from ansible.module_utils.vmware import (connect_to_api, find_cluster_by_name, find_datacenter_by_name, - find_vm_by_id, HAS_PYVMOMI, vmware_argument_spec, PyVmomi) - - -def directory(module, content, vm): - result = {} - result['changed'] = True - result['uuid'] = vm.summary.config.uuid - vm_username = module.params['vm_username'] - vm_password = module.params['vm_password'] - - recurse = bool(module.params['directory']['recurse']) - operation = module.params["directory"]['operation'] - path = module.params["directory"]['path'] - creds = vim.vm.guest.NamePasswordAuthentication(username=vm_username, password=vm_password) - file_manager = content.guestOperationsManager.fileManager - if operation == "create": +from ansible.module_utils.vmware import (PyVmomi, find_cluster_by_name, find_datacenter_by_name, + find_vm_by_id, vmware_argument_spec) + + +class VmwareGuestFileManager(PyVmomi): + def __init__(self, module): + super(VmwareGuestFileManager, self).__init__(module) + datacenter_name = module.params['datacenter'] + cluster_name = module.params['cluster'] + folder = module.params['folder'] + + datacenter = None + if datacenter_name: + datacenter = find_datacenter_by_name(self.content, datacenter_name) + if not datacenter: + module.fail_json(msg="Unable to find %(datacenter)s datacenter" % module.params) + + cluster = None + if cluster_name: + cluster = find_cluster_by_name(self.content, cluster_name, datacenter) + if not cluster: + module.fail_json(msg="Unable to find %(cluster)s cluster" % module.params) + + if module.params['vm_id_type'] == 'inventory_path': + vm = find_vm_by_id(self.content, vm_id=module.params['vm_id'], vm_id_type="inventory_path", folder=folder) + else: + vm = find_vm_by_id(self.content, vm_id=module.params['vm_id'], vm_id_type=module.params['vm_id_type'], + datacenter=datacenter, cluster=cluster) + + if not vm: + module.fail_json(msg='Unable to find virtual machine.') + + self.vm = vm try: - file_manager.MakeDirectoryInGuest(vm=vm, auth=creds, directoryPath=path, - createParentDirectories=recurse) - except vim.fault.FileAlreadyExists: - result['changed'] = False - result['msg'] = "Guest directory %s already exist" % path + result = dict(changed=False) + if module.params['directory']: + result = self.directory() + if module.params['copy']: + result = self.copy() + if module.params['fetch']: + result = self.fetch() + module.exit_json(**result) + except vmodl.RuntimeFault as runtime_fault: + module.fail_json(msg=to_native(runtime_fault.msg)) + except vmodl.MethodFault as method_fault: + module.fail_json(msg=to_native(method_fault.msg)) + except Exception as e: + module.fail_json(msg=to_native(e)) + + def directory(self): + result = dict(changed=True, uuid=self.vm.summary.config.uuid) + vm_username = self.module.params['vm_username'] + vm_password = self.module.params['vm_password'] + + recurse = bool(self.module.params['directory']['recurse']) + operation = self.module.params["directory"]['operation'] + path = self.module.params["directory"]['path'] + creds = vim.vm.guest.NamePasswordAuthentication(username=vm_username, password=vm_password) + file_manager = self.content.guestOperationsManager.fileManager + if operation == "create": + try: + file_manager.MakeDirectoryInGuest(vm=self.vm, + auth=creds, + directoryPath=path, + createParentDirectories=recurse) + except vim.fault.FileAlreadyExists as file_already_exists: + result['changed'] = False + result['msg'] = "Guest directory %s already exist: %s" % (path, + to_native(file_already_exists.msg)) + except vim.fault.GuestPermissionDenied as permission_denied: + self.module.fail_json(msg="Permission denied for path %s : %s" % (path, + to_native(permission_denied.msg)), + uuid=self.vm.summary.config.uuid) + except vim.fault.InvalidGuestLogin as invalid_guest_login: + self.module.fail_json(msg="Invalid guest login for user %s : %s" % (vm_username, + to_native(invalid_guest_login.msg)), + uuid=self.vm.summary.config.uuid) + # other exceptions + except Exception as e: + self.module.fail_json(msg="Failed to Create directory into VM VMware exception : %s" % to_native(e), + uuid=self.vm.summary.config.uuid) + + if operation == "delete": + try: + file_manager.DeleteDirectoryInGuest(vm=self.vm, auth=creds, directoryPath=path, + recursive=recurse) + except vim.fault.FileNotFound as file_not_found: + result['changed'] = False + result['msg'] = "Guest directory %s not exists %s" % (path, + to_native(file_not_found.msg)) + except vim.fault.FileFault as e: + self.module.fail_json(msg="FileFault : %s" % e.msg, + uuid=self.vm.summary.config.uuid) + except vim.fault.GuestPermissionDenied as permission_denied: + self.module.fail_json(msg="Permission denied for path %s : %s" % (path, + to_native(permission_denied.msg)), + uuid=self.vm.summary.config.uuid) + except vim.fault.InvalidGuestLogin as invalid_guest_login: + self.module.fail_json(msg="Invalid guest login for user %s : %s" % (vm_username, + to_native(invalid_guest_login.msg)), + uuid=self.vm.summary.config.uuid) + # other exceptions + except Exception as e: + self.module.fail_json(msg="Failed to Delete directory into Vm VMware exception : %s" % to_native(e), + uuid=self.vm.summary.config.uuid) + + return result + + def fetch(self): + result = dict(changed=True, uuid=self.vm.summary.config.uuid) + vm_username = self.module.params['vm_username'] + vm_password = self.module.params['vm_password'] + dest = self.module.params["fetch"]['dest'] + src = self.module.params['fetch']['src'] + creds = vim.vm.guest.NamePasswordAuthentication(username=vm_username, password=vm_password) + file_manager = self.content.guestOperationsManager.fileManager + + try: + fileTransferInfo = file_manager.InitiateFileTransferFromGuest(vm=self.vm, auth=creds, + guestFilePath=src) + url = fileTransferInfo.url + resp, info = urls.fetch_url(self.module, url, method="GET") + try: + with open(dest, "wb") as local_file: + local_file.write(resp.read()) + except Exception as e: + self.module.fail_json(msg="local file write exception : %s" % to_native(e), + uuid=self.vm.summary.config.uuid) + except vim.fault.FileNotFound as file_not_found: + self.module.fail_json(msg="Guest file %s does not exist : %s" % (src, to_native(file_not_found.msg)), + uuid=self.vm.summary.config.uuid) + except vim.fault.FileFault as e: + self.module.fail_json(msg="FileFault : %s" % to_native(e.msg), + uuid=self.vm.summary.config.uuid) except vim.fault.GuestPermissionDenied: - module.fail_json(msg="Permission denied for path %s" % path, uuid=vm.summary.config.uuid) + self.module.fail_json(msg="Permission denied to fetch file %s" % src, + uuid=self.vm.summary.config.uuid) except vim.fault.InvalidGuestLogin: - module.fail_json(msg="Invalid guest login for user %s" % vm_username, uuid=vm.summary.config.uuid) + self.module.fail_json(msg="Invalid guest login for user %s" % vm_username, + uuid=self.vm.summary.config.uuid) # other exceptions except Exception as e: - module.fail_json(msg="Failed to Create directory into Vm VMware exception:%s" % e, - uuid=vm.summary.config.uuid) + self.module.fail_json(msg="Failed to Fetch file from Vm VMware exception : %s" % to_native(e), + uuid=self.vm.summary.config.uuid) + + return result - if operation == "delete": + def copy(self): + result = dict(changed=True, uuid=self.vm.summary.config.uuid) + vm_username = self.module.params['vm_username'] + vm_password = self.module.params['vm_password'] + overwrite = self.module.params["copy"]["overwrite"] + dest = self.module.params["copy"]['dest'] + src = self.module.params['copy']['src'] + b_src = to_bytes(src, errors='surrogate_or_strict') + + if not os.path.exists(b_src): + self.module.fail_json(msg="Source %s not found" % src) + if not os.access(b_src, os.R_OK): + self.module.fail_json(msg="Source %s not readable" % src) + if os.path.isdir(b_src): + self.module.fail_json(msg="copy does not support copy of directory: %s" % src) + + data = None + with open(b_src, "r") as local_file: + data = local_file.read() + file_size = os.path.getsize(b_src) + + creds = vim.vm.guest.NamePasswordAuthentication(username=vm_username, password=vm_password) + file_attributes = vim.vm.guest.FileManager.FileAttributes() + file_manager = self.content.guestOperationsManager.fileManager try: - file_manager.DeleteDirectoryInGuest(vm=vm, auth=creds, directoryPath=path, - recursive=recurse) - except vim.fault.FileNotFound: + url = file_manager.InitiateFileTransferToGuest(vm=self.vm, auth=creds, guestFilePath=dest, + fileAttributes=file_attributes, overwrite=overwrite, + fileSize=file_size) + resp, info = urls.fetch_url(self.module, url, data=data, method="PUT") + + status_code = info["status"] + if status_code != 200: + self.module.fail_json(msg='initiateFileTransferToGuest : problem during file transfer', + uuid=self.vm.summary.config.uuid) + except vim.fault.FileAlreadyExists: result['changed'] = False - result['msg'] = "Guest directory %s not exists" % path + result['msg'] = "Guest file %s already exists" % dest + return result except vim.fault.FileFault as e: - module.fail_json(msg="FileFault:%s" % e.msg, uuid=vm.summary.config.uuid) - except vim.fault.GuestPermissionDenied: - module.fail_json(msg="Permission denied for path %s" % path, uuid=vm.summary.config.uuid) - except vim.fault.InvalidGuestLogin: - module.fail_json(msg="Invalid guest login for user %s" % vm_username, uuid=vm.summary.config.uuid) + self.module.fail_json(msg="FileFault:%s" % to_native(e.msg), + uuid=self.vm.summary.config.uuid) + except vim.fault.GuestPermissionDenied as permission_denied: + self.module.fail_json(msg="Permission denied to copy file into " + "destination %s : %s" % (dest, to_native(permission_denied.msg)), + uuid=self.vm.summary.config.uuid) + except vim.fault.InvalidGuestLogin as invalid_guest_login: + self.module.fail_json(msg="Invalid guest login for user" + " %s : %s" % (vm_username, to_native(invalid_guest_login.msg))) # other exceptions except Exception as e: - module.fail_json(msg="Failed to Delete directory into Vm VMware exception:%s" % e, - uuid=vm.summary.config.uuid) - - return result - - -def fetch(module, content, vm): - result = {} - result['changed'] = True - result['uuid'] = vm.summary.config.uuid - vm_username = module.params['vm_username'] - vm_password = module.params['vm_password'] - dest = module.params["fetch"]['dest'] - src = module.params['fetch']['src'] - creds = vim.vm.guest.NamePasswordAuthentication(username=vm_username, password=vm_password) - file_manager = content.guestOperationsManager.fileManager - - try: - fileTransferInfo = file_manager.InitiateFileTransferFromGuest(vm=vm, auth=creds, - guestFilePath=src) - except vim.fault.FileNotFound: - module.fail_json(msg="Guest file %s does not exist" % src, uuid=vm.summary.config.uuid) - except vim.fault.FileFault as e: - module.fail_json(msg="FileFault:%s" % e.msg, uuid=vm.summary.config.uuid) - except vim.fault.GuestPermissionDenied: - module.fail_json(msg="Permission denied to fetch file %s" % src, uuid=vm.summary.config.uuid) - except vim.fault.InvalidGuestLogin: - module.fail_json(msg="Invalid guest login for user %s" % vm_username, uuid=vm.summary.config.uuid) - # other exceptions - except Exception as e: - module.fail_json(msg="Failed to Fetch file from Vm VMware exception:%s" % e, uuid=vm.summary.config.uuid) - - url = fileTransferInfo.url - try: - resp, info = urls.fetch_url(module, url, method="GET") - except Exception as e: - module.fail_json(msg="Failed to Fetch file from Vm VMware exception:%s" % e, - uuid=vm.summary.config.uuid) - - try: - with open(dest, "wb") as local_file: - local_file.write(resp.read()) - except Exception as e: - module.fail_json(msg="local file write exception:%s" % e, uuid=vm.summary.config.uuid) - - return result - - -def copy(module, content, vm): - result = {} - result['changed'] = True - result['uuid'] = vm.summary.config.uuid - vm_username = module.params['vm_username'] - vm_password = module.params['vm_password'] - overwrite = module.params["copy"]["overwrite"] - dest = module.params["copy"]['dest'] - src = module.params['copy']['src'] - b_src = to_bytes(src, errors='surrogate_or_strict') - - if not os.path.exists(b_src): - module.fail_json(msg="Source %s not found" % (src)) - if not os.access(b_src, os.R_OK): - module.fail_json(msg="Source %s not readable" % (src)) - if os.path.isdir(b_src): - module.fail_json(msg="copy does not support copy of directory: %s" % (src)) - - data = None - with open(b_src, "r") as local_file: - data = local_file.read() - file_size = os.path.getsize(b_src) - - creds = vim.vm.guest.NamePasswordAuthentication(username=vm_username, password=vm_password) - file_attributes = vim.vm.guest.FileManager.FileAttributes() - file_manager = content.guestOperationsManager.fileManager - try: - url = file_manager.InitiateFileTransferToGuest(vm=vm, auth=creds, guestFilePath=dest, - fileAttributes=file_attributes, overwrite=overwrite, - fileSize=file_size) - except vim.fault.FileAlreadyExists: - result['changed'] = False - result['msg'] = "Guest file %s already exists" % dest + self.module.fail_json(msg="Failed to Copy file to Vm VMware exception : %s" % to_native(e), + uuid=self.vm.summary.config.uuid) return result - except vim.fault.FileFault as e: - module.fail_json(msg="FileFault:%s" % e.msg, uuid=vm.summary.config.uuid) - except vim.fault.GuestPermissionDenied: - module.fail_json(msg="Permission denied to copy file into destination %s" % dest, uuid=vm.summary.config.uuid) - except vim.fault.InvalidGuestLogin: - module.fail_json(msg="Invalid guest login for user %s" % vm_username) - # other exceptions - except Exception as e: - module.fail_json(msg="Failed to Copy file to Vm VMware exception:%s" % e, uuid=vm.summary.config.uuid) - - resp, info = urls.fetch_url(module, url, data=data, method="PUT") - - status_code = info["status"] - if status_code != 200: - module.fail_json(msg='initiateFileTransferToGuest : problem during file transfer', uuid=vm.summary.config.uuid) - return result def main(): argument_spec = vmware_argument_spec() - argument_spec.update(dict(datacenter=dict(type='str'), - cluster=dict(type='str'), - folder=dict(type='str'), - vm_id=dict(type='str', required=True), - vm_id_type=dict(default='vm_name', type='str', - choices=['inventory_path', 'uuid', 'dns_name', 'vm_name']), - vm_username=dict(type='str', required=True), - vm_password=dict(type='str', no_log=True, required=True), - directory=dict( - type='dict', - default=None, - options=dict( - path=dict(required=True, type='str'), - operation=dict(required=True, type='str', - choices=['create', 'delete']), - recurse=dict(required=False, type='bool', default=False) - )), - copy=dict( - type='dict', - default=None, - options=dict( - src=dict(required=True, type='str'), - dest=dict(required=True, type='str'), - overwrite=dict(required=False, type='bool', default=False) - )), - fetch=dict( - type='dict', - default=None, - options=dict(src=dict(required=True, type='str'), - dest=dict(required=True, type='str'), - )) - )) + argument_spec.update(dict( + datacenter=dict(type='str'), + cluster=dict(type='str'), + folder=dict(type='str'), + vm_id=dict(type='str', required=True), + vm_id_type=dict( + default='vm_name', + type='str', + choices=['inventory_path', 'uuid', 'dns_name', 'vm_name']), + vm_username=dict(type='str', required=True), + vm_password=dict(type='str', no_log=True, required=True), + directory=dict( + type='dict', + default=None, + options=dict( + path=dict(required=True, type='str'), + operation=dict(required=True, type='str', choices=['create', 'delete']), + recurse=dict(required=False, type='bool', default=False) + ) + ), + copy=dict( + type='dict', + default=None, + options=dict(src=dict(required=True, type='str'), + dest=dict(required=True, type='str'), + overwrite=dict(required=False, type='bool', default=False) + ) + ), + fetch=dict( + type='dict', + default=None, + options=dict( + src=dict(required=True, type='str'), + dest=dict(required=True, type='str'), + ) + ) + ) + ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_if=[['vm_id_type', 'inventory_path', ['folder']]], @@ -349,52 +410,10 @@ def main(): required_one_of=[['directory', 'copy', 'fetch']], ) - if not HAS_PYVMOMI: - module.fail_json(msg='pyvmomi is required for this module') - if module.params['vm_id_type'] == 'inventory_path' and not module.params['folder']: module.fail_json(msg='Folder is required parameter when vm_id_type is inventory_path') - datacenter_name = module.params['datacenter'] - cluster_name = module.params['cluster'] - folder = module.params['folder'] - content = connect_to_api(module) - - datacenter = None - if datacenter_name: - datacenter = find_datacenter_by_name(content, datacenter_name) - if not datacenter: - module.fail_json(msg="Unable to find %(datacenter)s datacenter" % module.params) - - cluster = None - if cluster_name: - cluster = find_cluster_by_name(content, cluster_name, datacenter) - if not cluster: - module.fail_json(msg="Unable to find %(cluster)s cluster" % module.params) - - if module.params['vm_id_type'] == 'inventory_path': - vm = find_vm_by_id(content, vm_id=module.params['vm_id'], vm_id_type="inventory_path", folder=folder) - else: - vm = find_vm_by_id(content, vm_id=module.params['vm_id'], vm_id_type=module.params['vm_id_type'], - datacenter=datacenter, cluster=cluster) - - if not vm: - module.fail_json(msg='Unable to find virtual machine.') - - try: - if module.params['directory']: - result = directory(module, content, vm) - if module.params['copy']: - result = copy(module, content, vm) - if module.params['fetch']: - result = fetch(module, content, vm) - module.exit_json(**result) - except vmodl.RuntimeFault as runtime_fault: - module.fail_json(msg=runtime_fault.msg) - except vmodl.MethodFault as method_fault: - module.fail_json(msg=method_fault.msg) - except Exception as e: - module.fail_json(msg=to_native(e)) + vmware_guest_file_manager = VmwareGuestFileManager(module) if __name__ == '__main__':