mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-23 19:01:26 -07:00
vca depend on pyvcloud, who depend on PyYAML 3.10, which support python 2.5 as a minimum, cf https://github.com/vmware/pyvcloud/blob/master/requirements.txt and http://pyyaml.org/wiki/PyYAML vmware.py depend on PyVIM, who depend on python 2.6. So we can use the modern syntax for both of them.
223 lines
6.9 KiB
Python
223 lines
6.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
|
#
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
try:
|
|
import atexit
|
|
import time
|
|
import ssl
|
|
# requests is required for exception handling of the ConnectionError
|
|
import requests
|
|
from pyVim import connect
|
|
from pyVmomi import vim
|
|
HAS_PYVMOMI = True
|
|
except ImportError:
|
|
HAS_PYVMOMI = False
|
|
|
|
|
|
class TaskError(Exception):
|
|
pass
|
|
|
|
|
|
def wait_for_task(task):
|
|
|
|
while True:
|
|
if task.info.state == vim.TaskInfo.State.success:
|
|
return True, task.info.result
|
|
if task.info.state == vim.TaskInfo.State.error:
|
|
try:
|
|
raise TaskError(task.info.error)
|
|
except AttributeError:
|
|
raise TaskError("An unknown error has occurred")
|
|
if task.info.state == vim.TaskInfo.State.running:
|
|
time.sleep(15)
|
|
if task.info.state == vim.TaskInfo.State.queued:
|
|
time.sleep(15)
|
|
|
|
|
|
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_entity_child_by_path(content, entityRootFolder, path):
|
|
|
|
entity = entityRootFolder
|
|
searchIndex = content.searchIndex
|
|
paths = path.split("/")
|
|
try:
|
|
for path in paths:
|
|
entity = searchIndex.FindChild (entity, path)
|
|
|
|
if entity.name == paths[-1]:
|
|
return entity
|
|
except:
|
|
pass
|
|
|
|
return None
|
|
|
|
|
|
# Maintain for legacy, or remove with 2.1 ?
|
|
# Should be replaced with find_cluster_by_name
|
|
def find_cluster_by_name_datacenter(datacenter, cluster_name):
|
|
|
|
host_folder = datacenter.hostFolder
|
|
for folder in host_folder.childEntity:
|
|
if folder.name == cluster_name:
|
|
return folder
|
|
return None
|
|
|
|
def find_cluster_by_name(content, cluster_name, datacenter=None):
|
|
|
|
if datacenter:
|
|
folder = datacenter.hostFolder
|
|
else:
|
|
folder = content.rootFolder
|
|
|
|
clusters = get_all_objs(content, [vim.ClusterComputeResource], folder)
|
|
for cluster in clusters:
|
|
if cluster.name == cluster_name:
|
|
return cluster
|
|
|
|
return None
|
|
|
|
def find_datacenter_by_name(content, datacenter_name):
|
|
|
|
datacenters = get_all_objs(content, [vim.Datacenter])
|
|
for dc in datacenters:
|
|
if dc.name == datacenter_name:
|
|
return dc
|
|
|
|
return None
|
|
|
|
|
|
def find_dvs_by_name(content, switch_name):
|
|
|
|
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
|
|
|
|
|
|
def find_hostsystem_by_name(content, hostname):
|
|
|
|
host_system = get_all_objs(content, [vim.HostSystem])
|
|
for host in host_system:
|
|
if host.name == hostname:
|
|
return host
|
|
return None
|
|
|
|
def find_vm_by_id(content, vm_id, vm_id_type="vm_name", datacenter=None, cluster=None):
|
|
""" UUID is unique to a VM, every other id returns the first match. """
|
|
si = content.searchIndex
|
|
vm = None
|
|
|
|
if vm_id_type == 'dns_name':
|
|
vm = si.FindByDnsName(datacenter=datacenter, dnsName=vm_id, vmSearch=True)
|
|
elif vm_id_type == 'inventory_path':
|
|
vm = si.FindByInventoryPath(inventoryPath=vm_id)
|
|
if type(vm) != type(vim.VirtualMachine):
|
|
vm = None
|
|
elif vm_id_type == 'uuid':
|
|
vm = si.FindByUuid(datacenter=datacenter, instanceUuid=vm_id, vmSearch=True)
|
|
elif vm_id_type == 'ip':
|
|
vm = si.FindByIp(datacenter=datacenter, ip=vm_id, vmSearch=True)
|
|
elif vm_id_type == 'vm_name':
|
|
folder = None
|
|
if cluster:
|
|
folder = cluster
|
|
elif datacenter:
|
|
folder = datacenter.hostFolder
|
|
vm = find_vm_by_name(content, vm_id, folder)
|
|
|
|
return vm
|
|
|
|
|
|
def find_vm_by_name(content, vm_name, folder=None, recurse=True):
|
|
|
|
vms = get_all_objs(content, [vim.VirtualMachine], folder, recurse=True)
|
|
for vm in vms:
|
|
if vm.name == vm_name:
|
|
return vm
|
|
return None
|
|
|
|
|
|
def find_host_portgroup_by_name(host, portgroup_name):
|
|
|
|
for portgroup in host.config.network.portgroup:
|
|
if portgroup.spec.name == portgroup_name:
|
|
return portgroup
|
|
return None
|
|
|
|
|
|
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),
|
|
validate_certs=dict(type='bool', required=False, default=True),
|
|
)
|
|
|
|
|
|
def connect_to_api(module, disconnect_atexit=True):
|
|
|
|
hostname = module.params['hostname']
|
|
username = module.params['username']
|
|
password = module.params['password']
|
|
validate_certs = module.params['validate_certs']
|
|
|
|
if validate_certs and not hasattr(ssl, 'SSLContext'):
|
|
module.fail_json(msg='pyVim does not support changing verification mode with python < 2.7.9. Either update python or or use validate_certs=false')
|
|
|
|
try:
|
|
service_instance = connect.SmartConnect(host=hostname, user=username, pwd=password)
|
|
except vim.fault.InvalidLogin as invalid_login:
|
|
module.fail_json(msg=invalid_login.msg, apierror=str(invalid_login))
|
|
except requests.ConnectionError as connection_error:
|
|
if '[SSL: CERTIFICATE_VERIFY_FAILED]' in str(connection_error) and not validate_certs:
|
|
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
|
context.verify_mode = ssl.CERT_NONE
|
|
service_instance = connect.SmartConnect(host=hostname, user=username, pwd=password, sslContext=context)
|
|
else:
|
|
module.fail_json(msg="Unable to connect to vCenter or ESXi API on TCP/443.", apierror=str(connection_error))
|
|
|
|
# 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()
|
|
|
|
def get_all_objs(content, vimtype, folder=None, recurse=True):
|
|
if not folder:
|
|
folder = content.rootFolder
|
|
|
|
obj = {}
|
|
container = content.viewManager.CreateContainerView(folder, vimtype, recurse)
|
|
for managed_object_ref in container.view:
|
|
obj.update({managed_object_ref: managed_object_ref.name})
|
|
return obj
|
|
|