diff --git a/lib/ansible/module_utils/vmware.py b/lib/ansible/module_utils/vmware.py new file mode 100644 index 00000000000..d7dcc256fec --- /dev/null +++ b/lib/ansible/module_utils/vmware.py @@ -0,0 +1,181 @@ +#!/bin/python +# -*- coding: utf-8 -*- + +# (c) 2015, Joseph Callen +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + + +try: + import atexit + import time + # requests is required for exception handling of the ConnectionError + import requests + from pyVim import connect + from pyVmomi import vim, vmodl + HAS_PYVMOMI = True +except ImportError: + HAS_PYVMOMI = False + + +class TaskError(Exception): + pass + + +def task_success(task): + return True + + +def task_running(task): + time.sleep(15) + return False + + +def task_error(task): + + try: + raise TaskError(task.info.error) + except AttributeError: + raise TaskError("Unknown error has occurred") + + +def task_queued(task): + time.sleep(15) + return False + + +def wait_for_task(task): + + task_state = { + vim.TaskInfo.State.success: task_success, + vim.TaskInfo.State.running: task_running, + vim.TaskInfo.State.queued: task_queued, + vim.TaskInfo.State.error: task_error, + } + + while True: + try: + is_finished = task_state[task.info.state](task) + if is_finished: + return True, task.info.result + # This exception should be handled in the module that calls this method + # and fail with an appropriate message to module.fail_json() + except TaskError: + raise + + +def find_dvspg_by_name(dv_switch, portgroup_name): + portgroups = dv_switch.portgroup + + for pg in portgroups: + if pg.name == portgroup_name: + return pg + + return None + + +def find_cluster_by_name_datacenter(datacenter, cluster_name): + try: + host_folder = datacenter.hostFolder + for folder in host_folder.childEntity: + if folder.name == cluster_name: + return folder + return None + # This exception should be handled in the module that calls this method + # and fail with an appropriate message to module.fail_json() + except vmodl.MethodFault: + raise + + +def find_datacenter_by_name(content, datacenter_name, throw=True): + try: + datacenters = get_all_objs(content, [vim.Datacenter]) + for dc in datacenters: + if dc.name == datacenter_name: + return dc + + return None + # This exception should be handled in the module that calls this method + # and fail with an appropriate message to module.fail_json() + except vmodl.MethodFault: + raise + + +def find_dvs_by_name(content, switch_name): + try: + vmware_distributed_switches = get_all_objs(content, [vim.dvs.VmwareDistributedVirtualSwitch]) + for dvs in vmware_distributed_switches: + if dvs.name == switch_name: + return dvs + return None + # This exception should be handled in the module that calls this method + # and fail with an appropriate message to module.fail_json() + except vmodl.MethodFault: + raise + + +def find_hostsystem_by_name(content, hostname): + try: + host_system = get_all_objs(content, [vim.HostSystem]) + for host in host_system: + if host.name == hostname: + return host + return None + # This exception should be handled in the module that calls this method + # and fail with an appropriate message to module.fail_json() + except vmodl.MethodFault: + raise + + +def vmware_argument_spec(): + return dict( + hostname=dict(type='str', required=True), + username=dict(type='str', aliases=['user', 'admin'], required=True), + password=dict(type='str', aliases=['pass', 'pwd'], required=True, no_log=True), + ) + + +def connect_to_api(module, disconnect_atexit=True): + hostname = module.params['hostname'] + username = module.params['username'] + password = module.params['password'] + try: + service_instance = connect.SmartConnect(host=hostname, user=username, pwd=password) + + # Disabling atexit should be used in special cases only. + # Such as IP change of the ESXi host which removes the connection anyway. + # Also removal significantly speeds up the return of the module + + if disconnect_atexit: + atexit.register(connect.Disconnect, service_instance) + return service_instance.RetrieveContent() + except vim.fault.InvalidLogin as invalid_login: + module.fail_json(msg=invalid_login.msg) + except requests.ConnectionError: + module.fail_json(msg="Unable to connect to vCenter or ESXi API on TCP/443.") + + +def get_all_objs(content, vimtype): + try: + obj = {} + container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True) + for managed_object_ref in container.view: + obj.update({managed_object_ref: managed_object_ref.name}) + return obj + # This exception should be handled in the module that calls this method + # and fail with an appropriate message to module.fail_json() + except vmodl.MethodFault: + raise \ No newline at end of file