Merge pull request #40376 from nmadhok/2016.11

Backporting changes in vmware cloud driver from develop branch to 2016.11 branch
This commit is contained in:
Mike Place 2017-03-30 16:35:12 -06:00 committed by GitHub
commit 132d8b7b88
8 changed files with 1739 additions and 193 deletions

View File

@ -116,7 +116,7 @@ configuration, run :py:func:`test_vcenter_connection`
# Import python libs
from __future__ import absolute_import
from random import randint
from re import findall
from re import findall, split, search, compile
import pprint
import logging
import time
@ -126,6 +126,7 @@ import subprocess
# Import salt libs
import salt.utils
import salt.utils.cloud
import salt.utils.network
import salt.utils.xmlutil
import salt.utils.vmware
from salt.exceptions import SaltCloudSystemExit
@ -133,15 +134,10 @@ from salt.exceptions import SaltCloudSystemExit
# Import salt cloud libs
import salt.config as config
# Attempt to import pyVim and pyVmomi libs
ESX_5_5_NAME_PORTION = 'VMware ESXi 5.5'
SAFE_ESX_5_5_CONTROLLER_KEY_INDEX = 200
FLATTEN_DISK_FULL_CLONE = 'moveAllDiskBackingsAndDisallowSharing'
COPY_ALL_DISKS_FULL_CLONE = 'moveAllDiskBackingsAndAllowSharing'
CURRENT_STATE_LINKED_CLONE = 'moveChildMostDiskBacking'
QUICK_LINKED_CLONE = 'createNewChildDiskBacking'
# Import 3rd-party libs
import salt.ext.six as six
try:
# Attempt to import pyVmomi libs
from pyVmomi import vim
HAS_PYVMOMI = True
except Exception:
@ -154,15 +150,13 @@ try:
except Exception:
pass
try:
import salt.ext.six as six
HAS_SIX = True
except ImportError:
# Salt version <= 2014.7.0
try:
import six
except ImportError:
HAS_SIX = False
ESX_5_5_NAME_PORTION = 'VMware ESXi 5.5'
SAFE_ESX_5_5_CONTROLLER_KEY_INDEX = 200
FLATTEN_DISK_FULL_CLONE = 'moveAllDiskBackingsAndDisallowSharing'
COPY_ALL_DISKS_FULL_CLONE = 'moveAllDiskBackingsAndAllowSharing'
CURRENT_STATE_LINKED_CLONE = 'moveChildMostDiskBacking'
QUICK_LINKED_CLONE = 'createNewChildDiskBacking'
IP_RE = r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
@ -203,7 +197,6 @@ def get_dependencies():
'''
deps = {
'pyVmomi': HAS_PYVMOMI,
'six': HAS_SIX
}
return config.check_driver_dependencies(
__virtualname__,
@ -267,8 +260,11 @@ def _get_si():
port=port)
def _edit_existing_hard_disk_helper(disk, size_kb):
disk.capacityInKB = size_kb
def _edit_existing_hard_disk_helper(disk, size_kb=None, size_gb=None, mode=None):
if size_kb or size_gb:
disk.capacityInKB = size_kb if size_kb else int(size_gb * 1024.0 * 1024.0)
if mode:
disk.backing.diskMode = mode
disk_spec = vim.vm.device.VirtualDeviceSpec()
disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
disk_spec.device = disk
@ -276,18 +272,8 @@ def _edit_existing_hard_disk_helper(disk, size_kb):
return disk_spec
def _edit_existing_hard_disk_mode_helper(disk, mode):
disk_spec = vim.vm.device.VirtualDeviceSpec()
disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
disk.backing.diskMode = mode
disk_spec.device = disk
return disk_spec
def _add_new_hard_disk_helper(disk_label, size_gb, unit_number, controller_key=1000, thin_provision=False):
def _add_new_hard_disk_helper(disk_label, size_gb, unit_number, controller_key=1000, thin_provision=False, datastore=None, vm_name=None):
random_key = randint(-2099, -2000)
size_kb = int(size_gb * 1024.0 * 1024.0)
disk_spec = vim.vm.device.VirtualDeviceSpec()
@ -299,9 +285,19 @@ def _add_new_hard_disk_helper(disk_label, size_gb, unit_number, controller_key=1
disk_spec.device.deviceInfo = vim.Description()
disk_spec.device.deviceInfo.label = disk_label
disk_spec.device.deviceInfo.summary = "{0} GB".format(size_gb)
disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
disk_spec.device.backing.thinProvisioned = thin_provision
disk_spec.device.backing.diskMode = 'persistent'
if datastore:
ds_ref = salt.utils.vmware.get_datastore_ref(_get_si(), datastore)
if not ds_ref:
raise SaltCloudSystemExit('Requested {0} disk in datastore {1}, but no such datastore found.'.format(disk_label, datastore))
datastore_path = '[' + str(ds_ref.name) + '] ' + vm_name
disk_spec.device.backing.fileName = datastore_path + '/' + disk_label + '.vmdk'
disk_spec.device.backing.datastore = ds_ref
disk_spec.device.controllerKey = controller_key
disk_spec.device.unitNumber = unit_number
disk_spec.device.capacityInKB = size_kb
@ -373,7 +369,7 @@ def _edit_existing_network_adapter(network_adapter, new_network_name, adapter_ty
return network_spec
def _add_new_network_adapter_helper(network_adapter_label, network_name, adapter_type, switch_type, container_ref=None):
def _add_new_network_adapter_helper(network_adapter_label, network_name, adapter_type, switch_type, mac, container_ref=None):
random_key = randint(-4099, -4000)
adapter_type.strip().lower()
@ -419,6 +415,9 @@ def _add_new_network_adapter_helper(network_adapter_label, network_name, adapter
switch_type)
raise SaltCloudSystemExit(err_msg)
if mac != '':
network_spec.device.addressType = 'assigned'
network_spec.device.macAddress = mac
network_spec.device.key = random_key
network_spec.device.deviceInfo = vim.Description()
network_spec.device.deviceInfo.label = network_adapter_label
@ -605,7 +604,26 @@ def _set_network_adapter_mapping(adapter_specs):
return adapter_mapping
def _manage_devices(devices, vm=None, container_ref=None):
def _get_mode_spec(device, mode, disk_spec):
if device.backing.diskMode != mode:
if not disk_spec:
disk_spec = _edit_existing_hard_disk_helper(
disk=device,
mode=mode
)
else:
disk_spec.device.backing.diskMode = mode
return disk_spec
def _get_size_spec(device, size_gb=None, size_kb=None):
if size_kb is None and size_gb is not None:
size_kb = int(size_gb * 1024.0 * 1024.0)
disk_spec = _edit_existing_hard_disk_helper(disk=device, size_kb=size_kb) if device.capacityInKB < size_kb else None
return disk_spec
def _manage_devices(devices, vm=None, container_ref=None, new_vm_name=None):
unit_number = 0
bus_number = 0
device_specs = []
@ -625,35 +643,41 @@ def _manage_devices(devices, vm=None, container_ref=None):
if isinstance(device, vim.vm.device.VirtualDisk):
# this is a hard disk
if 'disk' in list(devices.keys()):
# there is at least one disk specified to be created/configured
# there is atleast one disk specified to be created/configured
unit_number += 1
existing_disks_label.append(device.deviceInfo.label)
if device.deviceInfo.label in list(devices['disk'].keys()):
disk_spec = None
if 'size' in devices['disk'][device.deviceInfo.label]:
disk_spec = _get_size_spec(device, devices)
size_kb = float(
devices['disk'][device.deviceInfo.label]['size']
) * 1024 * 1024
size_gb = float(devices['disk'][device.deviceInfo.label]['size'])
size_kb = int(size_gb * 1024.0 * 1024.0)
else:
# User didn't specify disk size
# in the cloud profile
# so use the existing disk size
log.info('Virtual disk size was not'
' specified in the cloud profile.'
' Using existing disk size.')
# User didn't specify disk size in the cloud
# profile so use the existing disk size
size_kb = device.capacityInKB
if device.capacityInKB < size_kb:
# expand the disk
disk_spec = _edit_existing_hard_disk_helper(device, size_kb)
elif device.capacityInKB > size_kb:
raise SaltCloudSystemExit(
'The specified disk size is smaller than the '
'size of the disk image. It must be equal to '
'or greater than the disk image'
size_gb = size_kb / (1024.0 * 1024.0)
log.debug(
'Virtual disk size for \'{0}\' was not '
'specified in the cloud profile or map file. '
'Using existing virtual disk size of \'{1}GB\''.format(
device.deviceInfo.label,
size_gb
)
)
if device.capacityInKB > size_kb:
raise SaltCloudSystemExit(
'The specified disk size \'{0}GB\' for \'{1}\' is '
'smaller than the disk image size \'{2}GB\'. It must '
'be equal to or greater than the disk image'.format(
float(devices['disk'][device.deviceInfo.label]['size']),
device.deviceInfo.label,
float(device.capacityInKB / (1024.0 * 1024.0))
)
)
else:
disk_spec = _get_size_spec(device=device, size_kb=size_kb)
if 'mode' in devices['disk'][device.deviceInfo.label]:
if devices['disk'][device.deviceInfo.label]['mode'] \
in [
@ -661,12 +685,14 @@ def _manage_devices(devices, vm=None, container_ref=None):
'independent_nonpersistent',
'dependent',
]:
disk_spec = _get_mode_spec(device, devices, disk_spec)
mode = devices['disk'][device.deviceInfo.label]['mode']
disk_spec = _get_mode_spec(device, mode, disk_spec)
else:
raise SaltCloudSystemExit('Invalid disk'
' backing mode'
' specified!')
device_specs.append(disk_spec)
if disk_spec is not None:
device_specs.append(disk_spec)
elif isinstance(device.backing, vim.vm.device.VirtualEthernetCard.NetworkBackingInfo) or isinstance(device.backing, vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo):
# this is a network adapter
@ -723,8 +749,9 @@ def _manage_devices(devices, vm=None, container_ref=None):
network_name = devices['network'][network_adapter_label]['name']
adapter_type = devices['network'][network_adapter_label]['adapter_type'] if 'adapter_type' in devices['network'][network_adapter_label] else ''
switch_type = devices['network'][network_adapter_label]['switch_type'] if 'switch_type' in devices['network'][network_adapter_label] else ''
mac = devices['network'][network_adapter_label]['mac'] if 'mac' in devices['network'][network_adapter_label] else ''
# create the network adapter
network_spec = _add_new_network_adapter_helper(network_adapter_label, network_name, adapter_type, switch_type, container_ref)
network_spec = _add_new_network_adapter_helper(network_adapter_label, network_name, adapter_type, switch_type, mac, container_ref)
adapter_mapping = _set_network_adapter_mapping(devices['network'][network_adapter_label])
device_specs.append(network_spec)
nics_map.append(adapter_mapping)
@ -769,7 +796,8 @@ def _manage_devices(devices, vm=None, container_ref=None):
# create the disk
size_gb = float(devices['disk'][disk_label]['size'])
thin_provision = bool(devices['disk'][disk_label]['thin_provision']) if 'thin_provision' in devices['disk'][disk_label] else False
disk_spec = _add_new_hard_disk_helper(disk_label, size_gb, unit_number, thin_provision=thin_provision)
datastore = devices['disk'][disk_label].get('datastore', None)
disk_spec = _add_new_hard_disk_helper(disk_label, size_gb, unit_number, thin_provision=thin_provision, datastore=datastore, vm_name=new_vm_name)
# when creating both SCSI controller and Hard disk at the same time we need the randomly
# assigned (temporary) key of the newly created SCSI controller
@ -822,31 +850,6 @@ def _manage_devices(devices, vm=None, container_ref=None):
return ret
def _get_mode_spec(device, devices, disk_spec):
if device.backing.diskMode != \
devices['disk'][device.deviceInfo.label]['mode']:
if not disk_spec:
disk_spec = \
_edit_existing_hard_disk_mode_helper(
device,
devices['disk'][device.deviceInfo.label]['mode']
)
else:
disk_spec.device.backing.diskMode = \
devices['disk'][device.deviceInfo.label]['mode']
return disk_spec
def _get_size_spec(device, devices):
size_gb = float(devices['disk'][device.deviceInfo.label]['size'])
size_kb = int(size_gb * 1024.0 * 1024.0)
disk_spec = None
if device.capacityInKB < size_kb:
# expand the disk
disk_spec = _edit_existing_hard_disk_helper(device, size_kb)
return disk_spec
def _wait_for_vmware_tools(vm_ref, max_wait):
time_counter = 0
starttime = time.time()
@ -911,7 +914,16 @@ def _wait_for_ip(vm_ref, max_wait):
max_wait_ip = max_wait
vmware_tools_status = _wait_for_vmware_tools(vm_ref, max_wait_vmware_tools)
if not vmware_tools_status:
return False
# VMware will only report the IP if VMware tools are installed. Try to
# determine the IP using DNS
vm_name = vm_ref.summary.config.name
resolved_ips = salt.utils.network.host_to_ips(vm_name)
log.debug("Timeout waiting for VMware tools. The name {0} resolved "
"to {1}".format(vm_name, str(resolved_ips)))
if isinstance(resolved_ips, list) and len(resolved_ips):
return resolved_ips[0]
else:
return False
time_counter = 0
starttime = time.time()
while time_counter < max_wait_ip:
@ -1206,6 +1218,29 @@ def _get_snapshots(snapshot_list, current_snapshot=None, parent_snapshot_path=""
return snapshots
def _get_snapshot_ref_helper(base_snapshot, snapshot_name):
if base_snapshot.name == snapshot_name:
return base_snapshot
else:
for snapshot in base_snapshot.childSnapshotList:
snapshot_ref = _get_snapshot_ref_helper(snapshot, snapshot_name)
if snapshot_ref is not None:
return snapshot_ref
def _get_snapshot_ref_by_name(vm_ref, snapshot_name):
snapshot_ref = None
try:
for root_snapshot in vm_ref.snapshot.rootSnapshotList:
snapshot_ref = _get_snapshot_ref_helper(root_snapshot, snapshot_name)
if snapshot_ref is not None:
break
except (IndexError, AttributeError):
snapshot_ref = None
return snapshot_ref
def _upg_tools_helper(vm, reboot=False):
# Exit if template
if vm.config.template:
@ -1902,6 +1937,9 @@ def list_snapshots(kwargs=None, call=None):
return {vm["name"]: _get_snapshots(vm["snapshot"].rootSnapshotList)}
else:
ret[vm["name"]] = _get_snapshots(vm["snapshot"].rootSnapshotList)
else:
if kwargs and kwargs.get('name') == vm["name"]:
return {}
return ret
@ -1953,15 +1991,24 @@ def start(name, call=None):
return 'powered on'
def stop(name, call=None):
def stop(name, soft=False, call=None):
'''
To stop/power off a VM using its name
.. note::
If ``soft=True`` then issues a command to the guest operating system
asking it to perform a clean shutdown of all services.
Default is soft=False
For ``soft=True`` vmtools should be installed on guest system.
CLI Example:
.. code-block:: bash
salt-cloud -a stop vmname
salt-cloud -a stop vmname soft=True
'''
if call != 'action':
raise SaltCloudSystemExit(
@ -1984,8 +2031,11 @@ def stop(name, call=None):
return ret
try:
log.info('Stopping VM {0}'.format(name))
task = vm["object"].PowerOff()
salt.utils.vmware.wait_for_task(task, name, 'power off')
if soft:
vm["object"].ShutdownGuest()
else:
task = vm["object"].PowerOff()
salt.utils.vmware.wait_for_task(task, name, 'power off')
except Exception as exc:
log.error(
'Error while powering off VM {0}: {1}'.format(
@ -2051,15 +2101,24 @@ def suspend(name, call=None):
return 'suspended'
def reset(name, call=None):
def reset(name, soft=False, call=None):
'''
To reset a VM using its name
.. note::
If ``soft=True`` then issues a command to the guest operating system
asking it to perform a reboot. Otherwise hypervisor will terminate VM and start it again.
Default is soft=False
For ``soft=True`` vmtools should be installed on guest system.
CLI Example:
.. code-block:: bash
salt-cloud -a reset vmname
salt-cloud -a reset vmname soft=True
'''
if call != 'action':
raise SaltCloudSystemExit(
@ -2082,8 +2141,11 @@ def reset(name, call=None):
return ret
try:
log.info('Resetting VM {0}'.format(name))
task = vm["object"].ResetVM_Task()
salt.utils.vmware.wait_for_task(task, name, 'reset')
if soft:
vm["object"].RebootGuest()
else:
task = vm["object"].ResetVM_Task()
salt.utils.vmware.wait_for_task(task, name, 'reset')
except Exception as exc:
log.error(
'Error while resetting VM {0}: {1}'.format(
@ -2330,6 +2392,9 @@ def create(vm_):
customization = config.get_cloud_config_value(
'customization', vm_, __opts__, search_global=False, default=True
)
customization_spec = config.get_cloud_config_value(
'customization_spec', vm_, __opts__, search_global=False, default=None
)
win_password = config.get_cloud_config_value(
'win_password', vm_, __opts__, search_global=False, default=None
)
@ -2343,6 +2408,9 @@ def create(vm_):
'win_user_fullname', vm_, __opts__, search_global=False, default='Windows User'
)
# Get service instance object
si = _get_si()
container_ref = None
# If datacenter is specified, set the container reference to start search from it instead
@ -2351,9 +2419,13 @@ def create(vm_):
container_ref = datacenter_ref if datacenter_ref else None
if 'clonefrom' in vm_:
# If datacenter is specified, set the container reference to start search from it instead
if datacenter:
datacenter_ref = salt.utils.vmware.get_mor_by_property(si, vim.Datacenter, datacenter)
container_ref = datacenter_ref if datacenter_ref else None
# Clone VM/template from specified VM/template
object_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.VirtualMachine, vm_['clonefrom'], container_ref=container_ref)
object_ref = salt.utils.vmware.get_mor_by_property(si, vim.VirtualMachine, vm_['clonefrom'], container_ref=container_ref)
if object_ref:
clone_type = "template" if object_ref.config.template else "vm"
else:
@ -2366,13 +2438,13 @@ def create(vm_):
# Either a cluster, or a resource pool must be specified when cloning from template or creating.
if resourcepool:
resourcepool_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.ResourcePool, resourcepool, container_ref=container_ref)
resourcepool_ref = salt.utils.vmware.get_mor_by_property(si, vim.ResourcePool, resourcepool, container_ref=container_ref)
if not resourcepool_ref:
log.error("Specified resource pool: '{0}' does not exist".format(resourcepool))
if not clone_type or clone_type == "template":
raise SaltCloudSystemExit('You must specify a resource pool that exists.')
elif cluster:
cluster_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.ClusterComputeResource, cluster, container_ref=container_ref)
cluster_ref = salt.utils.vmware.get_mor_by_property(si, vim.ClusterComputeResource, cluster, container_ref=container_ref)
if not cluster_ref:
log.error("Specified cluster: '{0}' does not exist".format(cluster))
if not clone_type or clone_type == "template":
@ -2393,7 +2465,7 @@ def create(vm_):
# Either a datacenter or a folder can be optionally specified when cloning, required when creating.
# If not specified when cloning, the existing VM/template\'s parent folder is used.
if folder:
folder_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.Folder, folder, container_ref=container_ref)
folder_ref = salt.utils.vmware.get_mor_by_property(si, vim.Folder, folder, container_ref=container_ref)
if not folder_ref:
log.error("Specified folder: '{0}' does not exist".format(folder))
log.debug("Using folder in which {0} {1} is present".format(clone_type, vm_['clonefrom']))
@ -2423,12 +2495,12 @@ def create(vm_):
# Either a datastore/datastore cluster can be optionally specified.
# If not specified, the current datastore is used.
if datastore:
datastore_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.Datastore, datastore, container_ref=container_ref)
datastore_ref = salt.utils.vmware.get_mor_by_property(si, vim.Datastore, datastore, container_ref=container_ref)
if datastore_ref:
# specific datastore has been specified
reloc_spec.datastore = datastore_ref
else:
datastore_cluster_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.StoragePod, datastore, container_ref=container_ref)
datastore_cluster_ref = salt.utils.vmware.get_mor_by_property(si, vim.StoragePod, datastore, container_ref=container_ref)
if not datastore_cluster_ref:
log.error("Specified datastore/datastore cluster: '{0}' does not exist".format(datastore))
log.debug("Using datastore used by the {0} {1}".format(clone_type, vm_['clonefrom']))
@ -2437,7 +2509,7 @@ def create(vm_):
log.debug("Using datastore used by the {0} {1}".format(clone_type, vm_['clonefrom']))
if host:
host_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.HostSystem, host, container_ref=container_ref)
host_ref = salt.utils.vmware.get_mor_by_property(si, vim.HostSystem, host, container_ref=container_ref)
if host_ref:
reloc_spec.host = host_ref
else:
@ -2448,7 +2520,7 @@ def create(vm_):
'You must specify a datastore when creating not cloning.'
)
else:
datastore_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.Datastore, datastore)
datastore_ref = salt.utils.vmware.get_mor_by_property(si, vim.Datastore, datastore)
if not datastore_ref:
raise SaltCloudSystemExit("Specified datastore: '{0}' does not exist".format(datastore))
@ -2498,7 +2570,7 @@ def create(vm_):
config_spec.memoryMB = memory_mb
if devices:
specs = _manage_devices(devices, object_ref)
specs = _manage_devices(devices, vm=object_ref, new_vm_name=vm_name)
config_spec.deviceChange = specs['device_specs']
if extra_config:
@ -2520,12 +2592,21 @@ def create(vm_):
reloc_spec,
template)
if customization and (devices and 'network' in list(devices.keys())):
if customization and customization_spec:
customization_spec = salt.utils.vmware.get_customizationspec_ref(si=si, customization_spec_name=customization_spec)
clone_spec.customization = customization_spec.spec
elif customization and (devices and 'network' in list(devices.keys())):
global_ip = vim.vm.customization.GlobalIPSettings()
if 'dns_servers' in list(vm_.keys()):
global_ip.dnsServerList = vm_['dns_servers']
hostName = vm_name.split('.')[0]
domainName = vm_name.split('.', 1)[-1]
non_hostname_chars = compile(r'[^\w-]')
if search(non_hostname_chars, vm_name):
hostName = split(non_hostname_chars, vm_name, maxsplit=1)[0]
else:
hostName = vm_name
domainName = hostName.split('.', 1)[-1]
if 'Windows' not in object_ref.config.guestFullName:
identity = vim.vm.customization.LinuxPrep()
identity.hostName = vim.vm.customization.FixedName(name=hostName)
@ -2568,6 +2649,9 @@ def create(vm_):
pprint.pformat(config_spec))
)
event_kwargs = vm_.copy()
del event_kwargs['password']
try:
__utils__['cloud.fire_event'](
'event',
@ -2598,9 +2682,6 @@ def create(vm_):
folder=folder_ref
)
# get si instance to refer to the content
si = _get_si()
# get recommended datastores
recommended_datastores = si.content.storageResourceManager.RecommendDatastores(storageSpec=storage_spec)
@ -2628,7 +2709,7 @@ def create(vm_):
)
return {'Error': err_msg}
new_vm_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.VirtualMachine, vm_name, container_ref=container_ref)
new_vm_ref = salt.utils.vmware.get_mor_by_property(si, vim.VirtualMachine, vm_name, container_ref=container_ref)
# Find how to power on in CreateVM_Task (if possible), for now this will do
try:
@ -2769,14 +2850,14 @@ def create_datacenter(kwargs=None, call=None):
'The datacenter name must be a non empty string of less than 80 characters.'
)
# Check if datacenter already exists
datacenter_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.Datacenter, datacenter_name)
if datacenter_ref:
return {datacenter_name: 'datacenter already exists'}
# Get the service instance
si = _get_si()
# Check if datacenter already exists
datacenter_ref = salt.utils.vmware.get_mor_by_property(si, vim.Datacenter, datacenter_name)
if datacenter_ref:
return {datacenter_name: 'datacenter already exists'}
folder = si.content.rootFolder
# Verify that the folder is of type vim.Folder
@ -2829,15 +2910,18 @@ def create_cluster(kwargs=None, call=None):
'You must specify name of the datacenter where the cluster should be created.'
)
# Get the service instance
si = _get_si()
if not isinstance(datacenter, vim.Datacenter):
datacenter = salt.utils.vmware.get_mor_by_property(_get_si(), vim.Datacenter, datacenter)
datacenter = salt.utils.vmware.get_mor_by_property(si, vim.Datacenter, datacenter)
if not datacenter:
raise SaltCloudSystemExit(
'The specified datacenter does not exist.'
)
# Check if cluster already exists
cluster_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.ClusterComputeResource, cluster_name)
cluster_ref = salt.utils.vmware.get_mor_by_property(si, vim.ClusterComputeResource, cluster_name)
if cluster_ref:
return {cluster_name: 'cluster already exists'}
@ -3487,29 +3571,6 @@ def create_snapshot(name, kwargs=None, call=None):
vm_ref.snapshot.currentSnapshot)}
def _get_snapshot_ref_helper(base_snapshot, snapshot_name):
if base_snapshot.name == snapshot_name:
return base_snapshot
else:
for snapshot in base_snapshot.childSnapshotList:
snapshot_ref = _get_snapshot_ref_helper(snapshot, snapshot_name)
if snapshot_ref is not None:
return snapshot_ref
def _get_snapshot_ref_by_name(vm_ref, snapshot_name):
snapshot_ref = None
try:
for root_snapshot in vm_ref.snapshot.rootSnapshotList:
snapshot_ref = _get_snapshot_ref_helper(root_snapshot, snapshot_name)
if snapshot_ref is not None:
break
except (IndexError, AttributeError):
snapshot_ref = None
return snapshot_ref
def revert_to_snapshot(name, kwargs=None, call=None):
'''
Revert virtual machine to it's current snapshot. If no snapshot
@ -3706,15 +3767,18 @@ def add_host(kwargs=None, call=None):
'You must specify either the cluster name or the datacenter name.'
)
# Get the service instance
si = _get_si()
if cluster_name:
cluster_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.ClusterComputeResource, cluster_name)
cluster_ref = salt.utils.vmware.get_mor_by_property(si, vim.ClusterComputeResource, cluster_name)
if not cluster_ref:
raise SaltCloudSystemExit(
'Specified cluster does not exist.'
)
if datacenter_name:
datacenter_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.Datacenter, datacenter_name)
datacenter_ref = salt.utils.vmware.get_mor_by_property(si, vim.Datacenter, datacenter_name)
if not datacenter_ref:
raise SaltCloudSystemExit(
'Specified datacenter does not exist.'
@ -3798,7 +3862,10 @@ def remove_host(kwargs=None, call=None):
'You must specify name of the host system.'
)
host_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.HostSystem, host_name)
# Get the service instance
si = _get_si()
host_ref = salt.utils.vmware.get_mor_by_property(si, vim.HostSystem, host_name)
if not host_ref:
raise SaltCloudSystemExit(
'Specified host system does not exist.'
@ -3849,7 +3916,10 @@ def connect_host(kwargs=None, call=None):
'You must specify name of the host system.'
)
host_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.HostSystem, host_name)
# Get the service instance
si = _get_si()
host_ref = salt.utils.vmware.get_mor_by_property(si, vim.HostSystem, host_name)
if not host_ref:
raise SaltCloudSystemExit(
'Specified host system does not exist.'
@ -3898,7 +3968,10 @@ def disconnect_host(kwargs=None, call=None):
'You must specify name of the host system.'
)
host_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.HostSystem, host_name)
# Get the service instance
si = _get_si()
host_ref = salt.utils.vmware.get_mor_by_property(si, vim.HostSystem, host_name)
if not host_ref:
raise SaltCloudSystemExit(
'Specified host system does not exist.'
@ -3954,7 +4027,10 @@ def reboot_host(kwargs=None, call=None):
'You must specify name of the host system.'
)
host_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.HostSystem, host_name)
# Get the service instance
si = _get_si()
host_ref = salt.utils.vmware.get_mor_by_property(si, vim.HostSystem, host_name)
if not host_ref:
raise SaltCloudSystemExit(
'Specified host system does not exist.'
@ -4028,12 +4104,15 @@ def create_datastore_cluster(kwargs=None, call=None):
'You must specify name of the datacenter where the datastore cluster should be created.'
)
# Get the service instance
si = _get_si()
# Check if datastore cluster already exists
datastore_cluster_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.StoragePod, datastore_cluster_name)
datastore_cluster_ref = salt.utils.vmware.get_mor_by_property(si, vim.StoragePod, datastore_cluster_name)
if datastore_cluster_ref:
return {datastore_cluster_name: 'datastore cluster already exists'}
datacenter_ref = salt.utils.vmware.get_mor_by_property(_get_si(), vim.Datacenter, datacenter_name)
datacenter_ref = salt.utils.vmware.get_mor_by_property(si, vim.Datacenter, datacenter_name)
if not datacenter_ref:
raise SaltCloudSystemExit(
'The specified datacenter does not exist.'

View File

@ -386,6 +386,13 @@ class VMwareSaltError(CommandExecutionError):
'''
class VMwareRuntimeError(VMwareSaltError):
'''
Used when a runtime error is encountered when communicating with the
vCenter
'''
class VMwareConnectionError(VMwareSaltError):
'''
Used when the client fails to connect to a either a VMware vCenter server or
@ -393,7 +400,19 @@ class VMwareConnectionError(VMwareSaltError):
'''
class VMwareApiError(VMwareSaltError):
class VMwareObjectRetrievalError(VMwareSaltError):
'''
Used when a VMware object cannot be retrieved
'''
class VMwareApiError(VMwareSaltError):
'''
Used when representing a generic VMware API error
'''
class VMwareSystemError(VMwareSaltError):
'''
Used when representing a generic VMware system error
'''

View File

@ -116,7 +116,7 @@ def __virtual__():
return False, 'Missing dependency: The salt.utils.vmware module requires pyVmomi.'
def esxcli(host, user, pwd, cmd, protocol=None, port=None, esxi_host=None):
def esxcli(host, user, pwd, cmd, protocol=None, port=None, esxi_host=None, credstore=None):
'''
Shell out and call the specified esxcli commmand, parse the result
and return something sane.
@ -128,6 +128,8 @@ def esxcli(host, user, pwd, cmd, protocol=None, port=None, esxi_host=None):
:param cmd: esxcli command and arguments
:param esxi_host: If `host` is a vCenter host, then esxi_host is the
ESXi machine on which to execute this command
:param credstore: Optional path to the credential store file
:return: Dictionary
'''
@ -142,6 +144,9 @@ def esxcli(host, user, pwd, cmd, protocol=None, port=None, esxi_host=None):
if protocol is None:
protocol = 'https'
if credstore:
esx_cmd += ' --credstore \'{0}\''.format(credstore)
if not esxi_host:
# Then we are connecting directly to an ESXi server,
# 'host' points at that server, and esxi_host is a reference to the
@ -269,6 +274,40 @@ def _get_service_instance(host, username, password, protocol,
return service_instance
def get_customizationspec_ref(si, customization_spec_name):
'''
Get a reference to a VMware customization spec for the purposes of customizing a clone
si
ServiceInstance for the vSphere or ESXi server (see get_service_instance)
customization_spec_name
Name of the customization spec
'''
customization_spec_name = si.content.customizationSpecManager.GetCustomizationSpec(name=customization_spec_name)
return customization_spec_name
def get_datastore_ref(si, datastore_name):
'''
Get a reference to a VMware datastore for the purposes of adding/removing disks
si
ServiceInstance for the vSphere or ESXi server (see get_service_instance)
datastore_name
Name of the datastore
'''
inventory = get_inventory(si)
container = inventory.viewManager.CreateContainerView(inventory.rootFolder, [vim.Datastore], True)
for item in container.view:
if item.name == datastore_name:
return item
return None
def get_service_instance(host, username=None, password=None, protocol=None,
port=None, mechanism='userpass', principal=None,
domain=None):
@ -348,10 +387,49 @@ def get_service_instance(host, username=None, password=None, protocol=None,
mechanism,
principal,
domain)
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
return service_instance
def get_service_instance_from_managed_object(mo_ref, name='<unnamed>'):
'''
Retrieves the service instance from a managed object.
me_ref
Reference to a managed object (of type vim.ManagedEntity).
name
Name of managed object. This field is optional.
'''
if not name:
name = mo_ref.name
log.trace('[{0}] Retrieving service instance from managed object'
''.format(name))
si = vim.ServiceInstance('ServiceInstance')
si._stub = mo_ref._stub
return si
def disconnect(service_instance):
'''
Function that disconnects from the vCenter server or ESXi host
service_instance
The Service Instance from which to obtain managed object references.
'''
log.trace('Disconnecting')
try:
Disconnect(service_instance)
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
def is_connection_to_a_vcenter(service_instance):
'''
Function that returns True if the connection is made to a vCenter Server and
@ -360,7 +438,12 @@ def is_connection_to_a_vcenter(service_instance):
service_instance
The Service Instance from which to obtain managed object references.
'''
api_type = service_instance.content.about.apiType
try:
api_type = service_instance.content.about.apiType
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
log.trace('api_type = {0}'.format(api_type))
if api_type == 'VirtualCenter':
return True
@ -553,6 +636,22 @@ def get_inventory(service_instance):
return service_instance.RetrieveContent()
def get_root_folder(service_instance):
'''
Returns the root folder of a vCenter.
service_instance
The Service Instance Object for which to obtain the root folder.
'''
try:
log.trace('Retrieving root folder')
return service_instance.RetrieveContent().rootFolder
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
def get_content(service_instance, obj_type, property_list=None,
container_ref=None, traversal_spec=None,
local_properties=False):
@ -586,7 +685,7 @@ def get_content(service_instance, obj_type, property_list=None,
'''
# Start at the rootFolder if container starting point not specified
if not container_ref:
container_ref = service_instance.content.rootFolder
container_ref = get_root_folder(service_instance)
# By default, the object reference used as the starting poing for the filter
# is the container_ref passed in the function
@ -596,8 +695,14 @@ def get_content(service_instance, obj_type, property_list=None,
local_traversal_spec = True
# We don't have a specific traversal spec override so we are going to
# get everything using a container view
obj_ref = service_instance.content.viewManager.CreateContainerView(
container_ref, [obj_type], True)
try:
obj_ref = service_instance.content.viewManager.CreateContainerView(
container_ref, [obj_type], True)
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
# Create 'Traverse All' traversal spec to determine the path for
# collection
traversal_spec = vmodl.query.PropertyCollector.TraversalSpec(
@ -629,11 +734,21 @@ def get_content(service_instance, obj_type, property_list=None,
)
# Retrieve the contents
content = service_instance.content.propertyCollector.RetrieveContents([filter_spec])
try:
content = service_instance.content.propertyCollector.RetrieveContents([filter_spec])
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
# Destroy the object view
if local_traversal_spec:
obj_ref.Destroy()
try:
obj_ref.Destroy()
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
return content
@ -663,7 +778,8 @@ def get_mor_by_property(service_instance, object_type, property_value, property_
object_list = get_mors_with_properties(service_instance, object_type, property_list=[property_name], container_ref=container_ref)
for obj in object_list:
if obj[property_name] == property_value:
obj_id = str(obj.get('object', '')).strip('\'"')
if obj[property_name] == property_value or property_value == obj_id:
return obj['object']
return None
@ -723,6 +839,54 @@ def get_mors_with_properties(service_instance, object_type, property_list=None,
return object_list
def get_properties_of_managed_object(mo_ref, properties):
'''
Returns specific properties of a managed object, retrieved in an
optimally.
mo_ref
The managed object reference.
properties
List of properties of the managed object to retrieve.
'''
service_instance = get_service_instance_from_managed_object(mo_ref)
log.trace('Retrieving name of {0}'''.format(type(mo_ref).__name__))
try:
items = get_mors_with_properties(service_instance,
type(mo_ref),
container_ref=mo_ref,
property_list=['name'],
local_properties=True)
mo_name = items[0]['name']
except vmodl.query.InvalidProperty:
mo_name = '<unnamed>'
log.trace('Retrieving properties \'{0}\' of {1} \'{2}\''
''.format(properties, type(mo_ref).__name__, mo_name))
items = get_mors_with_properties(service_instance,
type(mo_ref),
container_ref=mo_ref,
property_list=properties,
local_properties=True)
if not items:
raise salt.exceptions.VMwareApiError(
'Properties of managed object \'{0}\' weren\'t '
'retrieved'.format(mo_name))
return items[0]
def get_managed_object_name(mo_ref):
'''
Returns the name of a managed object.
If the name wasn't found, it returns None.
mo_ref
The managed object reference.
'''
props = get_properties_of_managed_object(mo_ref, ['name'])
return props.get('name')
def get_network_adapter_type(adapter_type):
'''
Return the network adapter type.
@ -776,6 +940,155 @@ def list_datacenters(service_instance):
return list_objects(service_instance, vim.Datacenter)
def get_datacenters(service_instance, datacenter_names=None,
get_all_datacenters=False):
'''
Returns all datacenters in a vCenter.
service_instance
The Service Instance Object from which to obtain cluster.
datacenter_names
List of datacenter names to filter by. Default value is None.
get_all_datacenters
Flag specifying whether to retrieve all datacenters.
Default value is None.
'''
items = [i['object'] for i in
get_mors_with_properties(service_instance,
vim.Datacenter,
property_list=['name'])
if get_all_datacenters or
(datacenter_names and i['name'] in datacenter_names)]
return items
def get_datacenter(service_instance, datacenter_name):
'''
Returns a vim.Datacenter managed object.
service_instance
The Service Instance Object from which to obtain datacenter.
datacenter_name
The datacenter name
'''
items = get_datacenters(service_instance,
datacenter_names=[datacenter_name])
if not items:
raise salt.exceptions.VMwareObjectRetrievalError(
'Datacenter \'{0}\' was not found'.format(datacenter_name))
return items[0]
def create_datacenter(service_instance, datacenter_name):
'''
Creates a datacenter.
.. versionadded:: Nitrogen
service_instance
The Service Instance Object
datacenter_name
The datacenter name
'''
root_folder = get_root_folder(service_instance)
log.trace('Creating datacenter \'{0}\''.format(datacenter_name))
try:
dc_obj = root_folder.CreateDatacenter(datacenter_name)
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
return dc_obj
def get_cluster(dc_ref, cluster):
'''
Returns a cluster in a datacenter.
dc_ref
The datacenter reference
cluster
The cluster to be retrieved
'''
dc_name = get_managed_object_name(dc_ref)
log.trace('Retrieving cluster \'{0}\' from datacenter \'{1}\''
''.format(cluster, dc_name))
si = get_service_instance_from_managed_object(dc_ref, name=dc_name)
traversal_spec = vmodl.query.PropertyCollector.TraversalSpec(
path='hostFolder',
skip=True,
type=vim.Datacenter,
selectSet=[vmodl.query.PropertyCollector.TraversalSpec(
path='childEntity',
skip=False,
type=vim.Folder)])
items = [i['object'] for i in
get_mors_with_properties(si,
vim.ClusterComputeResource,
container_ref=dc_ref,
property_list=['name'],
traversal_spec=traversal_spec)
if i['name'] == cluster]
if not items:
raise salt.exceptions.VMwareObjectRetrievalError(
'Cluster \'{0}\' was not found in datacenter '
'\'{1}\''. format(cluster, dc_name))
return items[0]
def create_cluster(dc_ref, cluster_name, cluster_spec):
'''
Creates a cluster in a datacenter.
dc_ref
The parent datacenter reference.
cluster_name
The cluster name.
cluster_spec
The cluster spec (vim.ClusterConfigSpecEx).
Defaults to None.
'''
dc_name = get_managed_object_name(dc_ref)
log.trace('Creating cluster \'{0}\' in datacenter \'{1}\''
''.format(cluster_name, dc_name))
try:
dc_ref.hostFolder.CreateClusterEx(cluster_name, cluster_spec)
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
def update_cluster(cluster_ref, cluster_spec):
'''
Updates a cluster in a datacenter.
cluster_ref
The cluster reference.
cluster_spec
The cluster spec (vim.ClusterConfigSpecEx).
Defaults to None.
'''
cluster_name = get_managed_object_name(cluster_ref)
log.trace('Updating cluster \'{0}\''.format(cluster_name))
try:
task = cluster_ref.ReconfigureComputeResource_Task(cluster_spec,
modify=True)
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
wait_for_task(task, cluster_name, 'ClusterUpdateTask')
def list_clusters(service_instance):
'''
Returns a list of clusters associated with a given service instance.
@ -806,6 +1119,68 @@ def list_datastores(service_instance):
return list_objects(service_instance, vim.Datastore)
def get_hosts(service_instance, datacenter_name=None, host_names=None,
cluster_name=None, get_all_hosts=False):
'''
Returns a list of vim.HostSystem objects representing ESXi hosts
in a vcenter filtered by their names and/or datacenter, cluster membership.
service_instance
The Service Instance Object from which to obtain the hosts.
datacenter_name
The datacenter name. Default is None.
host_names
The host_names to be retrieved. Default is None.
cluster_name
The cluster name - used to restrict the hosts retrieved. Only used if
the datacenter is set. This argument is optional.
get_all_hosts
Specifies whether to retrieve all hosts in the container.
Default value is False.
'''
properties = ['name']
if not host_names:
host_names = []
if cluster_name:
properties.append('parent')
if datacenter_name:
start_point = get_datacenter(service_instance, datacenter_name)
if cluster_name:
# Retrieval to test if cluster exists. Cluster existence only makes
# sense if the cluster has been specified
cluster = get_cluster(start_point, cluster_name)
else:
# Assume the root folder is the starting point
start_point = get_root_folder(service_instance)
# Search for the objects
hosts = get_mors_with_properties(service_instance,
vim.HostSystem,
container_ref=start_point,
property_list=properties)
filtered_hosts = []
for h in hosts:
# Complex conditions checking if a host should be added to the
# filtered list (either due to its name and/or cluster membership)
name_condition = get_all_hosts or (h['name'] in host_names)
# the datacenter_name needs to be set in order for the cluster
# condition membership to be checked, otherwise the condition is
# ignored
cluster_condition = \
(not datacenter_name or not cluster_name or
(isinstance(h['parent'], vim.ClusterComputeResource) and
h['parent'].name == cluster_name))
if name_condition and cluster_condition:
filtered_hosts.append(h['object'])
return filtered_hosts
def list_hosts(service_instance):
'''
Returns a list of hosts associated with a given service instance.
@ -910,7 +1285,15 @@ def wait_for_task(task, instance_name, task_type, sleep_seconds=1, log_level='de
'''
time_counter = 0
start_time = time.time()
while task.info.state == 'running' or task.info.state == 'queued':
log.trace('task = {0}, task_type = {1}'.format(task,
task.__class__.__name__))
try:
task_info = task.info
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
while task_info.state == 'running' or task_info.state == 'queued':
if time_counter % sleep_seconds == 0:
msg = '[ {0} ] Waiting for {1} task to finish [{2} s]'.format(
instance_name, task_type, time_counter)
@ -920,9 +1303,13 @@ def wait_for_task(task, instance_name, task_type, sleep_seconds=1, log_level='de
log.debug(msg)
time.sleep(1.0 - ((time.time() - start_time) % 1.0))
time_counter += 1
log.trace('task = {0}, task_type = {1}'.format(task,
task.__class__.__name__))
if task.info.state == 'success':
try:
task_info = task.info
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
raise salt.exceptions.VMwareRuntimeError(exc.msg)
if task_info.state == 'success':
msg = '[ {0} ] Successfully completed {1} task in {2} seconds'.format(
instance_name, task_type, time_counter)
if log_level == 'info':
@ -930,7 +1317,18 @@ def wait_for_task(task, instance_name, task_type, sleep_seconds=1, log_level='de
else:
log.debug(msg)
# task is in a successful state
return task.info.result
return task_info.result
else:
# task is in an error state
raise task.info.error
try:
raise task_info.error
except vim.fault.VimFault as exc:
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.fault.SystemError as exc:
raise salt.exceptions.VMwareSystemError(exc.msg)
except vmodl.fault.InvalidArgument as exc:
exc_message = exc.msg
if exc.faultMessage:
exc_message = '{0} ({1})'.format(exc_message,
exc.faultMessage[0].message)
raise salt.exceptions.VMwareApiError(exc_message)

View File

@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
'''
:codeauthor: :email:`Alexandru Bleotu <alexandru.bleotu@morganstanley.com>`
Tests for cluster related functions in salt.utils.vmware
'''
# Import python libraries
from __future__ import absolute_import
import logging
# Import Salt testing libraries
from salttesting import TestCase, skipIf
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock, call
# Import Salt libraries
from salt.exceptions import VMwareApiError, VMwareRuntimeError, \
VMwareObjectRetrievalError
import salt.utils.vmware as vmware
# Import Third Party Libs
try:
from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError:
HAS_PYVMOMI = False
# Get Logging Started
log = logging.getLogger(__name__)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_managed_object_name',
MagicMock())
@patch('salt.utils.vmware.get_service_instance_from_managed_object',
MagicMock())
@patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[{'name': 'fake_cluster',
'object': MagicMock()}]))
class GetClusterTestCase(TestCase):
'''Tests for salt.utils.vmware.get_cluster'''
def setUp(self):
self.mock_si = MagicMock()
self.mock_dc = MagicMock()
self.mock_cluster1 = MagicMock()
self.mock_cluster2 = MagicMock()
self.mock_entries = [{'name': 'fake_cluster1',
'object': self.mock_cluster1},
{'name': 'fake_cluster2',
'object': self.mock_cluster2}]
def test_get_managed_object_name_call(self):
mock_get_managed_object_name = MagicMock()
with patch('salt.utils.vmware.get_managed_object_name',
mock_get_managed_object_name):
vmware.get_cluster(self.mock_dc, 'fake_cluster')
mock_get_managed_object_name.assert_called_once_with(self.mock_dc)
def test_get_service_instance_from_managed_object(self):
mock_dc_name = MagicMock()
mock_get_service_instance_from_managed_object = MagicMock()
with patch('salt.utils.vmware.get_managed_object_name',
MagicMock(return_value=mock_dc_name)):
with patch(
'salt.utils.vmware.get_service_instance_from_managed_object',
mock_get_service_instance_from_managed_object):
vmware.get_cluster(self.mock_dc, 'fake_cluster')
mock_get_service_instance_from_managed_object.assert_called_once_with(
self.mock_dc, name=mock_dc_name)
def test_traversal_spec_init(self):
mock_dc_name = MagicMock()
mock_traversal_spec = MagicMock()
mock_traversal_spec_ini = MagicMock(return_value=mock_traversal_spec)
mock_get_service_instance_from_managed_object = MagicMock()
patch_traversal_spec_str = \
'salt.utils.vmware.vmodl.query.PropertyCollector.TraversalSpec'
with patch(patch_traversal_spec_str, mock_traversal_spec_ini):
vmware.get_cluster(self.mock_dc, 'fake_cluster')
mock_traversal_spec_ini.assert_has_calls(
[call(path='childEntity',
skip=False,
type=vim.Folder),
call(path='hostFolder',
skip=True,
type=vim.Datacenter,
selectSet=[mock_traversal_spec])])
def test_get_mors_with_properties_call(self):
mock_get_mors_with_properties = MagicMock(
return_value=[{'name': 'fake_cluster', 'object': MagicMock()}])
mock_traversal_spec = MagicMock()
patch_traversal_spec_str = \
'salt.utils.vmware.vmodl.query.PropertyCollector.TraversalSpec'
with patch(
'salt.utils.vmware.get_service_instance_from_managed_object',
MagicMock(return_value=self.mock_si)):
with patch('salt.utils.vmware.get_mors_with_properties',
mock_get_mors_with_properties):
with patch(patch_traversal_spec_str,
MagicMock(return_value=mock_traversal_spec)):
vmware.get_cluster(self.mock_dc, 'fake_cluster')
mock_get_mors_with_properties.assert_called_once_with(
self.mock_si, vim.ClusterComputeResource,
container_ref=self.mock_dc,
property_list=['name'],
traversal_spec=mock_traversal_spec)
def test_get_mors_with_properties_returns_empty_array(self):
with patch('salt.utils.vmware.get_managed_object_name',
MagicMock(return_value='fake_dc')):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[])):
with self.assertRaises(VMwareObjectRetrievalError) as excinfo:
vmware.get_cluster(self.mock_dc, 'fake_cluster')
self.assertEqual(excinfo.exception.strerror,
'Cluster \'fake_cluster\' was not found in '
'datacenter \'fake_dc\'')
def test_cluster_not_found(self):
with patch('salt.utils.vmware.get_managed_object_name',
MagicMock(return_value='fake_dc')):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_entries)):
with self.assertRaises(VMwareObjectRetrievalError) as excinfo:
vmware.get_cluster(self.mock_dc, 'fake_cluster')
self.assertEqual(excinfo.exception.strerror,
'Cluster \'fake_cluster\' was not found in '
'datacenter \'fake_dc\'')
def test_cluster_found(self):
with patch('salt.utils.vmware.get_managed_object_name',
MagicMock(return_value='fake_dc')):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_entries)):
res = vmware.get_cluster(self.mock_dc, 'fake_cluster2')
self.assertEqual(res, self.mock_cluster2)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_managed_object_name', MagicMock())
class CreateClusterTestCase(TestCase):
'''Tests for salt.utils.vmware.create_cluster'''
def setUp(self):
self.mock_create_cluster_ex = MagicMock()
self.mock_dc = MagicMock(
hostFolder=MagicMock(CreateClusterEx=self.mock_create_cluster_ex))
self.mock_cluster_spec = MagicMock()
def test_get_managed_object_name(self):
mock_get_managed_object_name = MagicMock()
with patch('salt.utils.vmware.get_managed_object_name',
mock_get_managed_object_name):
vmware.create_cluster(self.mock_dc, 'fake_cluster',
self.mock_cluster_spec)
mock_get_managed_object_name.assert_called_once_with(self.mock_dc)
def test_create_cluster_call(self):
vmware.create_cluster(self.mock_dc, 'fake_cluster',
self.mock_cluster_spec)
self.mock_create_cluster_ex.assert_called_once_with(
'fake_cluster', self.mock_cluster_spec)
def test_create_cluster_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
self.mock_dc.hostFolder.CreateClusterEx = MagicMock(
side_effect=exc)
with self.assertRaises(VMwareApiError) as excinfo:
vmware.create_cluster(self.mock_dc, 'fake_cluster',
self.mock_cluster_spec)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_create_cluster_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
self.mock_dc.hostFolder.CreateClusterEx = MagicMock(
side_effect=exc)
with self.assertRaises(VMwareRuntimeError) as excinfo:
vmware.create_cluster(self.mock_dc, 'fake_cluster',
self.mock_cluster_spec)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_managed_object_name', MagicMock())
@patch('salt.utils.vmware.wait_for_task', MagicMock())
class UpdateClusterTestCase(TestCase):
'''Tests for salt.utils.vmware.update_cluster'''
def setUp(self):
self.mock_task = MagicMock()
self.mock_reconfigure_compute_resource_task = \
MagicMock(return_value=self.mock_task)
self.mock_cluster = MagicMock(ReconfigureComputeResource_Task=
self.mock_reconfigure_compute_resource_task)
self.mock_cluster_spec = MagicMock()
def test_get_managed_object_name(self):
mock_get_managed_object_name = MagicMock()
with patch('salt.utils.vmware.get_managed_object_name',
mock_get_managed_object_name):
vmware.update_cluster(self.mock_cluster, self.mock_cluster_spec)
mock_get_managed_object_name.assert_called_once_with(self.mock_cluster)
def test_reconfigure_compute_resource_task_call(self):
vmware.update_cluster(self.mock_cluster, self.mock_cluster_spec)
self.mock_reconfigure_compute_resource_task.assert_called_once_with(
self.mock_cluster_spec, modify=True)
def test_reconfigure_compute_resource_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
self.mock_cluster.ReconfigureComputeResource_Task = \
MagicMock(side_effect=exc)
with self.assertRaises(VMwareApiError) as excinfo:
vmware.update_cluster(self.mock_cluster, self.mock_cluster_spec)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_reconfigure_compute_resource_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
self.mock_cluster.ReconfigureComputeResource_Task = \
MagicMock(side_effect=exc)
with self.assertRaises(VMwareRuntimeError) as excinfo:
vmware.update_cluster(self.mock_cluster, self.mock_cluster_spec)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_wait_for_task_call(self):
mock_wait_for_task = MagicMock()
with patch('salt.utils.vmware.get_managed_object_name',
MagicMock(return_value='fake_cluster')):
with patch('salt.utils.vmware.wait_for_task', mock_wait_for_task):
vmware.update_cluster(self.mock_cluster,
self.mock_cluster_spec)
mock_wait_for_task.assert_called_once_with(
self.mock_task, 'fake_cluster', 'ClusterUpdateTask')
if __name__ == '__main__':
from integration import run_tests
run_tests(GetClusterTestCase, needs_daemon=False)
run_tests(CreateClusterTestCase, needs_daemon=False)
run_tests(UpdateClusterTestCase, needs_daemon=False)

View File

@ -11,14 +11,15 @@ import logging
# Import Salt testing libraries
from salttesting import TestCase, skipIf
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock, \
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock, call, \
PropertyMock
# Import Salt libraries
import salt.exceptions as excs
import salt.utils.vmware
# Import Third Party Libs
try:
from pyVmomi import vim
from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError:
HAS_PYVMOMI = False
@ -34,9 +35,59 @@ log = logging.getLogger(__name__)
class WaitForTaskTestCase(TestCase):
'''Tests for salt.utils.vmware.wait_for_task'''
def test_info_state_running(self):
def test_first_task_info_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
mock_task = MagicMock()
type(mock_task).info = PropertyMock(side_effect=exc)
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_first_task_info_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
mock_task = MagicMock()
type(mock_task).info = PropertyMock(side_effect=exc)
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_inner_loop_task_info_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
mock_task = MagicMock()
mock_info1 = MagicMock()
type(mock_task).info = PropertyMock(
side_effect=[mock_info1, exc])
type(mock_info1).state = PropertyMock(side_effect=['running', 'bad'])
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_inner_loop_task_info_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
mock_task = MagicMock()
mock_info1 = MagicMock()
type(mock_task).info = PropertyMock(
side_effect=[mock_info1, exc])
type(mock_info1).state = PropertyMock(side_effect=['running', 'bad'])
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_info_state_running(self):
# The 'bad' values are invalid in the while loop
mock_task = MagicMock()
prop_mock_state = PropertyMock(side_effect=['running', 'bad', 'bad',
'success'])
prop_mock_result = PropertyMock()
@ -48,11 +99,27 @@ class WaitForTaskTestCase(TestCase):
self.assertEqual(prop_mock_state.call_count, 4)
self.assertEqual(prop_mock_result.call_count, 1)
def test_info_state_queued(self):
def test_info_state_running_continues_loop(self):
mock_task = MagicMock()
# The 'bad' values are invalid in the while loop
prop_mock_state = PropertyMock(side_effect=['bad', 'queued', 'bad',
'bad', 'success'])
# The 'fake' values are required to match all the lookups and end the
# loop
prop_mock_state = PropertyMock(side_effect=['running', 'fake', 'fake',
'success'])
prop_mock_result = PropertyMock()
type(mock_task.info).state = prop_mock_state
type(mock_task.info).result = prop_mock_result
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(prop_mock_state.call_count, 4)
self.assertEqual(prop_mock_result.call_count, 1)
def test_info_state_queued_continues_loop(self):
mock_task = MagicMock()
# The 'fake' values are required to match all the lookups and end the
# loop
prop_mock_state = PropertyMock(side_effect=['fake', 'queued', 'fake',
'fake', 'success'])
prop_mock_result = PropertyMock()
type(mock_task.info).state = prop_mock_state
type(mock_task.info).result = prop_mock_result
@ -74,9 +141,8 @@ class WaitForTaskTestCase(TestCase):
self.assertEqual(prop_mock_state.call_count, 3)
self.assertEqual(prop_mock_result.call_count, 1)
def test_info_state_different_no_error_attr(self):
def test_info_error_exception(self):
mock_task = MagicMock()
# The 'bad' values are invalid in the while loop
prop_mock_state = PropertyMock(return_value='error')
prop_mock_error = PropertyMock(side_effect=Exception('error exc'))
type(mock_task.info).state = prop_mock_state
@ -85,9 +151,69 @@ class WaitForTaskTestCase(TestCase):
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(prop_mock_state.call_count, 3)
self.assertEqual(prop_mock_error.call_count, 1)
self.assertEqual('error exc', excinfo.exception.message)
self.assertEqual(excinfo.exception.message, 'error exc')
def test_info_error_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
mock_task = MagicMock()
prop_mock_state = PropertyMock(return_value='error')
prop_mock_error = PropertyMock(side_effect=exc)
type(mock_task.info).state = prop_mock_state
type(mock_task.info).error = prop_mock_error
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_info_error_system_fault(self):
exc = vmodl.fault.SystemError()
exc.msg = 'SystemError msg'
mock_task = MagicMock()
prop_mock_state = PropertyMock(return_value='error')
prop_mock_error = PropertyMock(side_effect=exc)
type(mock_task.info).state = prop_mock_state
type(mock_task.info).error = prop_mock_error
with self.assertRaises(excs.VMwareSystemError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror, 'SystemError msg')
def test_info_error_invalid_argument_no_fault_message(self):
exc = vmodl.fault.InvalidArgument()
exc.faultMessage = None
exc.msg = 'InvalidArgumentFault msg'
mock_task = MagicMock()
prop_mock_state = PropertyMock(return_value='error')
prop_mock_error = PropertyMock(side_effect=exc)
type(mock_task.info).state = prop_mock_state
type(mock_task.info).error = prop_mock_error
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror,
'InvalidArgumentFault msg')
def test_info_error_invalid_argument_with_fault_message(self):
exc = vmodl.fault.InvalidArgument()
fault_message = vim.LocalizableMessage()
fault_message.message = 'LocalFault msg'
exc.faultMessage = [fault_message]
exc.msg = 'InvalidArgumentFault msg'
mock_task = MagicMock()
prop_mock_state = PropertyMock(return_value='error')
prop_mock_error = PropertyMock(side_effect=exc)
type(mock_task.info).state = prop_mock_state
type(mock_task.info).error = prop_mock_error
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.wait_for_task(mock_task,
'fake_instance_name',
'task_type')
self.assertEqual(excinfo.exception.strerror,
'InvalidArgumentFault msg (LocalFault msg)')
@skipIf(NO_MOCK, NO_MOCK_REASON)
@ -300,6 +426,101 @@ class GetMorsWithPropertiesTestCase(TestCase):
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_service_instance_from_managed_object',
MagicMock())
@patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[MagicMock()]))
class GetPropertiesOfManagedObjectTestCase(TestCase):
'''Tests for salt.utils.get_properties_of_managed_object'''
def setUp(self):
self.mock_si = MagicMock()
self.fake_mo_ref = vim.ManagedEntity('Fake')
self.mock_props = MagicMock()
self.mock_item_name = {'name': 'fake_name'}
self.mock_item = MagicMock()
def test_get_service_instance_from_managed_object_call(self):
mock_get_instance_from_managed_object = MagicMock()
with patch(
'salt.utils.vmware.get_service_instance_from_managed_object',
mock_get_instance_from_managed_object):
salt.utils.vmware.get_properties_of_managed_object(
self.fake_mo_ref, self.mock_props)
mock_get_instance_from_managed_object.assert_called_once_with(
self.fake_mo_ref)
def test_get_mors_with_properties_calls(self):
mock_get_mors_with_properties = MagicMock(return_value=[MagicMock()])
with patch(
'salt.utils.vmware.get_service_instance_from_managed_object',
MagicMock(return_value=self.mock_si)):
with patch('salt.utils.vmware.get_mors_with_properties',
mock_get_mors_with_properties):
salt.utils.vmware.get_properties_of_managed_object(
self.fake_mo_ref, self.mock_props)
mock_get_mors_with_properties.assert_has_calls(
[call(self.mock_si, vim.ManagedEntity,
container_ref=self.fake_mo_ref,
property_list=['name'],
local_properties=True),
call(self.mock_si, vim.ManagedEntity,
container_ref=self.fake_mo_ref,
property_list=self.mock_props,
local_properties=True)])
def test_managed_object_no_name_property(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(side_effect=[vmodl.query.InvalidProperty(), []])):
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.get_properties_of_managed_object(
self.fake_mo_ref, self.mock_props)
self.assertEqual('Properties of managed object \'<unnamed>\' weren\'t '
'retrieved', excinfo.exception.strerror)
def test_no_items_named_object(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(side_effect=[[self.mock_item_name], []])):
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.get_properties_of_managed_object(
self.fake_mo_ref, self.mock_props)
self.assertEqual('Properties of managed object \'fake_name\' weren\'t '
'retrieved', excinfo.exception.strerror)
@patch('salt.utils.vmware.get_properties_of_managed_object',
MagicMock(return_value={'key': 'value'}))
class GetManagedObjectName(TestCase):
'''Tests for salt.utils.get_managed_object_name'''
def setUp(self):
self.mock_mo_ref = MagicMock()
def test_get_properties_of_managed_object_call(self):
mock_get_properties_of_managed_object = MagicMock()
with patch('salt.utils.vmware.get_properties_of_managed_object',
mock_get_properties_of_managed_object):
salt.utils.vmware.get_managed_object_name(self.mock_mo_ref)
mock_get_properties_of_managed_object.assert_called_once_with(
self.mock_mo_ref, ['name'])
def test_no_name_in_property_dict(self):
ret = salt.utils.vmware.get_managed_object_name(self.mock_mo_ref)
self.assertIsNone(ret)
def test_return_managed_object_name(self):
mock_get_properties_of_managed_object = MagicMock()
with patch('salt.utils.vmware.get_properties_of_managed_object',
MagicMock(return_value={'name': 'fake_name'})):
ret = salt.utils.vmware.get_managed_object_name(self.mock_mo_ref)
self.assertEqual(ret, 'fake_name')
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_root_folder', MagicMock())
@patch('salt.utils.vmware.vmodl.query.PropertyCollector.TraversalSpec',
MagicMock(return_value=MagicMock()))
@patch('salt.utils.vmware.vmodl.query.PropertyCollector.PropertySpec',
@ -345,8 +566,8 @@ class GetContentTestCase(TestCase):
self.si_mock = MagicMock()
# RootFolder
self.root_folder_mock = MagicMock()
self.root_folder_prop = PropertyMock(return_value=self.root_folder_mock)
type(self.si_mock.content).rootFolder = self.root_folder_prop
self.get_root_folder_mock = \
MagicMock(return_value=self.root_folder_mock)
# CreateContainerView()
self.container_view_mock = MagicMock()
self.create_container_view_mock = \
@ -378,28 +599,34 @@ class GetContentTestCase(TestCase):
MagicMock(return_value=self.filter_spec_ret_mock)
def test_empty_container_ref(self):
ret = salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.assertEqual(self.root_folder_prop.call_count, 1)
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.get_root_folder_mock.assert_called_once_with(self.si_mock)
self.create_container_view_mock.assert_called_once_with(
self.root_folder_mock, [self.obj_type_mock], True)
def test_defined_container_ref(self):
container_ref_mock = MagicMock()
with patch(self.obj_spec_method_name, self.obj_type_mock):
ret = salt.utils.vmware.get_content(
self.si_mock, self.obj_type_mock,
container_ref=container_ref_mock)
self.assertEqual(self.root_folder_prop.call_count, 0)
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
with patch(self.obj_spec_method_name, self.obj_type_mock):
salt.utils.vmware.get_content(
self.si_mock, self.obj_type_mock,
container_ref=container_ref_mock)
self.assertEqual(self.get_root_folder_mock.call_count, 0)
self.create_container_view_mock.assert_called_once_with(
container_ref_mock, [self.obj_type_mock], True)
# Also checks destroy is called
def test_local_traversal_spec(self):
with patch(self.traversal_spec_method_name, self.traversal_spec_mock):
with patch(self.obj_spec_method_name, self.obj_spec_mock):
ret = salt.utils.vmware.get_content(self.si_mock,
self.obj_type_mock)
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
with patch(self.traversal_spec_method_name,
self.traversal_spec_mock):
with patch(self.obj_spec_method_name, self.obj_spec_mock):
ret = salt.utils.vmware.get_content(self.si_mock,
self.obj_type_mock)
self.create_container_view_mock.assert_called_once_with(
self.root_folder_mock, [self.obj_type_mock], True)
self.traversal_spec_mock.assert_called_once_with(
@ -412,15 +639,62 @@ class GetContentTestCase(TestCase):
# check destroy is called
self.assertEqual(self.destroy_mock.call_count, 1)
def test_create_container_view_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
self.si_mock.content.viewManager.CreateContainerView = \
MagicMock(side_effect=exc)
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_create_container_view_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
self.si_mock.content.viewManager.CreateContainerView = \
MagicMock(side_effect=exc)
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_destroy_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
self.si_mock.content.viewManager.CreateContainerView = MagicMock(
return_value=MagicMock(Destroy=MagicMock(side_effect=exc)))
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_destroy_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
self.si_mock.content.viewManager.CreateContainerView = MagicMock(
return_value=MagicMock(Destroy=MagicMock(side_effect=exc)))
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
# Also checks destroy is not called
def test_external_traversal_spec(self):
traversal_spec_obj_mock = MagicMock()
with patch(self.traversal_spec_method_name, self.traversal_spec_mock):
with patch(self.obj_spec_method_name, self.obj_spec_mock):
ret = salt.utils.vmware.get_content(
self.si_mock,
self.obj_type_mock,
traversal_spec=traversal_spec_obj_mock)
with patch('salt.utils.vmware.get_root_folder',
self.get_root_folder_mock):
with patch(self.traversal_spec_method_name,
self.traversal_spec_mock):
with patch(self.obj_spec_method_name, self.obj_spec_mock):
salt.utils.vmware.get_content(
self.si_mock,
self.obj_type_mock,
traversal_spec=traversal_spec_obj_mock)
self.obj_spec_mock.assert_called_once_with(
obj=self.root_folder_mock,
skip=True,
@ -452,6 +726,24 @@ class GetContentTestCase(TestCase):
[self.filter_spec_ret_mock])
self.assertEqual(ret, self.result_mock)
def test_retrieve_contents_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
self.si_mock.content.propertyCollector.RetrieveContents = \
MagicMock(side_effect=exc)
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_retrieve_contents_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
self.si_mock.content.propertyCollector.RetrieveContents = \
MagicMock(side_effect=exc)
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.get_content(self.si_mock, self.obj_type_mock)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_local_properties_set(self):
container_ref_mock = MagicMock()
with patch(self.traversal_spec_method_name, self.traversal_spec_mock):
@ -467,8 +759,42 @@ class GetContentTestCase(TestCase):
obj=container_ref_mock, skip=False, selectSet=None)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
class GetRootFolderTestCase(TestCase):
'''Tests for salt.utils.get_root_folder'''
def setUp(self):
self.mock_root_folder = MagicMock()
self.mock_content = MagicMock(rootFolder=self.mock_root_folder)
self.mock_si = MagicMock(
RetrieveContent=MagicMock(return_value=self.mock_content))
def test_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
type(self.mock_content).rootFolder = PropertyMock(side_effect=exc)
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.get_root_folder(self.mock_si)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
type(self.mock_content).rootFolder = PropertyMock(side_effect=exc)
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.get_root_folder(self.mock_si)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_return(self):
ret = salt.utils.vmware.get_root_folder(self.mock_si)
self.assertEqual(ret, self.mock_root_folder)
if __name__ == '__main__':
from integration import run_tests
run_tests(WaitForTaskTestCase, needs_daemon=False)
run_tests(GetMorsWithPropertiesTestCase, needs_daemon=False)
run_tests(GetPropertiesOfManagedObjectTestCase, needs_daemon=False)
run_tests(GetManagedObjectName, needs_daemon=False)
run_tests(GetContentTestCase, needs_daemon=False)
run_tests(GetRootFolderTestCase, needs_daemon=False)

View File

@ -14,14 +14,15 @@ import sys
# Import Salt testing libraries
from salttesting import TestCase, skipIf
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock, call
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock, call, \
PropertyMock
import salt.exceptions as excs
# Import Salt libraries
import salt.utils.vmware
# Import Third Party Libs
try:
from pyVmomi import vim
from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError:
HAS_PYVMOMI = False
@ -665,12 +666,100 @@ class GetServiceInstanceTestCase(TestCase):
self.assertEqual(mock_disconnect.call_count, 1)
self.assertEqual(mock_get_si.call_count, 2)
def test_current_time_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
with patch('salt.utils.vmware._get_service_instance',
MagicMock(return_value=MagicMock(
CurrentTime=MagicMock(side_effect=exc)))):
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.get_service_instance(
host='fake_host',
username='fake_username',
password='fake_password',
protocol='fake_protocol',
port=1,
mechanism='fake_mechanism',
principal='fake_principal',
domain='fake_domain')
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_current_time_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
with patch('salt.utils.vmware._get_service_instance',
MagicMock(return_value=MagicMock(
CurrentTime=MagicMock(side_effect=exc)))):
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.get_service_instance(
host='fake_host',
username='fake_username',
password='fake_password',
protocol='fake_protocol',
port=1,
mechanism='fake_mechanism',
principal='fake_principal',
domain='fake_domain')
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
class DisconnectTestCase(TestCase):
'''Tests for salt.utils.vmware.disconnect'''
def setUp(self):
self.mock_si = MagicMock()
def test_disconnect(self):
mock_disconnect = MagicMock()
with patch('salt.utils.vmware.Disconnect', mock_disconnect):
salt.utils.vmware.disconnect(
service_instance=self.mock_si)
mock_disconnect.assert_called_once_with(self.mock_si)
def test_disconnect_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
with patch('salt.utils.vmware.Disconnect', MagicMock(side_effect=exc)):
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.disconnect(
service_instance=self.mock_si)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_disconnect_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
with patch('salt.utils.vmware.Disconnect', MagicMock(side_effect=exc)):
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.disconnect(
service_instance=self.mock_si)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
class IsConnectionToAVCenterTestCase(TestCase):
'''Tests for salt.utils.vmware.is_connection_to_a_vcenter'''
def test_api_type_raise_vim_fault(self):
exc = vim.fault.VimFault()
exc.msg = 'VimFault msg'
mock_si = MagicMock()
type(mock_si.content.about).apiType = PropertyMock(side_effect=exc)
with self.assertRaises(excs.VMwareApiError) as excinfo:
salt.utils.vmware.is_connection_to_a_vcenter(mock_si)
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_api_type_raise_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
mock_si = MagicMock()
type(mock_si.content.about).apiType = PropertyMock(side_effect=exc)
with self.assertRaises(excs.VMwareRuntimeError) as excinfo:
salt.utils.vmware.is_connection_to_a_vcenter(mock_si)
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_connected_to_a_vcenter(self):
mock_si = MagicMock()
mock_si.content.about.apiType = 'VirtualCenter'
@ -694,9 +783,55 @@ class IsConnectionToAVCenterTestCase(TestCase):
self.assertIn('Unexpected api type \'UnsupportedType\'',
excinfo.exception.strerror)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.vim.ServiceInstance', MagicMock())
class GetServiceInstanceFromManagedObjectTestCase(TestCase):
'''Tests for salt.utils.vmware.get_managed_instance_from_managed_object'''
def setUp(self):
self.mock_si = MagicMock()
self.mock_stub = PropertyMock()
self.mock_mo_ref = MagicMock(_stub=self.mock_stub)
def test_default_name_parameter(self):
mock_trace = MagicMock()
type(salt.utils.vmware.log).trace = mock_trace
salt.utils.vmware.get_service_instance_from_managed_object(
self.mock_mo_ref)
mock_trace.assert_called_once_with('[<unnamed>] Retrieving service '
'instance from managed object')
def test_name_parameter_passed_in(self):
mock_trace = MagicMock()
type(salt.utils.vmware.log).trace = mock_trace
salt.utils.vmware.get_service_instance_from_managed_object(
self.mock_mo_ref, 'fake_mo_name')
mock_trace.assert_called_once_with('[fake_mo_name] Retrieving service '
'instance from managed object')
def test_service_instance_instantiation(self):
mock_service_instance_ini = MagicMock()
with patch('salt.utils.vmware.vim.ServiceInstance',
mock_service_instance_ini):
salt.utils.vmware.get_service_instance_from_managed_object(
self.mock_mo_ref)
mock_service_instance_ini.assert_called_once_with('ServiceInstance')
def test_si_return_and_stub_assignment(self):
with patch('salt.utils.vmware.vim.ServiceInstance',
MagicMock(return_value=self.mock_si)):
ret = salt.utils.vmware.get_service_instance_from_managed_object(
self.mock_mo_ref)
self.assertEqual(ret, self.mock_si)
self.assertEqual(ret._stub, self.mock_stub)
if __name__ == '__main__':
from integration import run_tests
run_tests(GssapiTokenTest, needs_daemon=False)
run_tests(PrivateGetServiceInstanceTestCase, needs_daemon=False)
run_tests(GetServiceInstanceTestCase, needs_daemon=False)
run_tests(DisconnectTestCase, needs_daemon=False)
run_tests(IsConnectionToAVCenterTestCase, needs_daemon=False)
run_tests(GetServiceInstanceFromManagedObjectTestCase, needs_daemon=False)

View File

@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
'''
:codeauthor: :email:`Alexandru Bleotu <alexandru.bleotu@morganstanley.com>`
Tests for datacenter related functions in salt.utils.vmware
'''
# Import python libraries
from __future__ import absolute_import
import logging
# Import Salt testing libraries
from salttesting import TestCase, skipIf
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock
from salt.exceptions import VMwareObjectRetrievalError, VMwareApiError, \
VMwareRuntimeError
# Import Salt libraries
import salt.utils.vmware as vmware
# Import Third Party Libs
try:
from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError:
HAS_PYVMOMI = False
# Get Logging Started
log = logging.getLogger(__name__)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[{'name': 'fake_dc', 'object': MagicMock()}]))
class GetDatacentersTestCase(TestCase):
'''Tests for salt.utils.vmware.get_datacenters'''
def setUp(self):
self.mock_si = MagicMock()
self.mock_dc1 = MagicMock()
self.mock_dc2 = MagicMock()
self.mock_entries = [{'name': 'fake_dc1',
'object': self.mock_dc1},
{'name': 'fake_dc2',
'object': self.mock_dc2}]
def test_get_mors_with_properties_call(self):
mock_get_mors_with_properties = MagicMock(
return_value=[{'name': 'fake_dc', 'object': MagicMock()}])
with patch('salt.utils.vmware.get_mors_with_properties',
mock_get_mors_with_properties):
vmware.get_datacenters(self.mock_si, datacenter_names=['fake_dc1'])
mock_get_mors_with_properties.assert_called_once_with(
self.mock_si, vim.Datacenter, property_list=['name'])
def test_get_mors_with_properties_returns_empty_array(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[])):
res = vmware.get_datacenters(self.mock_si,
datacenter_names=['fake_dc1'])
self.assertEqual(res, [])
def test_no_parameters(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_entries)):
res = vmware.get_datacenters(self.mock_si)
self.assertEqual(res, [])
def test_datastore_not_found(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_entries)):
res = vmware.get_datacenters(self.mock_si,
datacenter_names=['fake_dc'])
self.assertEqual(res, [])
def test_datastore_found(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_entries)):
res = vmware.get_datacenters(
self.mock_si, datacenter_names=['fake_dc2'])
self.assertEqual(res, [self.mock_dc2])
def test_get_all_datastores(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_entries)):
res = vmware.get_datacenters(
self.mock_si, get_all_datacenters=True)
self.assertEqual(res, [self.mock_dc1, self.mock_dc2])
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_datacenters',
MagicMock(return_value=[MagicMock()]))
class GetDatacenterTestCase(TestCase):
'''Tests for salt.utils.vmware.get_datacenter'''
def setUp(self):
self.mock_si = MagicMock()
self.mock_dc = MagicMock()
def test_get_datacenters_call(self):
mock_get_datacenters = MagicMock(return_value=[MagicMock()])
with patch('salt.utils.vmware.get_datacenters',
mock_get_datacenters):
vmware.get_datacenter(self.mock_si, 'fake_dc1')
mock_get_datacenters.assert_called_once_with(
self.mock_si, datacenter_names=['fake_dc1'])
def test_no_datacenters_returned(self):
with patch('salt.utils.vmware.get_datacenters',
MagicMock(return_value=[])):
with self.assertRaises(VMwareObjectRetrievalError) as excinfo:
vmware.get_datacenter(self.mock_si, 'fake_dc1')
self.assertEqual('Datacenter \'fake_dc1\' was not found',
excinfo.exception.strerror)
def test_get_datacenter_return(self):
with patch('salt.utils.vmware.get_datacenters',
MagicMock(return_value=[self.mock_dc])):
res = vmware.get_datacenter(self.mock_si, 'fake_dc1')
self.assertEqual(res, self.mock_dc)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_root_folder', MagicMock())
class CreateDatacenterTestCase(TestCase):
'''Tests for salt.utils.vmware.create_datacenter'''
def setUp(self):
self.mock_si = MagicMock()
self.mock_dc = MagicMock()
self.mock_create_datacenter = MagicMock(return_value=self.mock_dc)
self.mock_root_folder = MagicMock(
CreateDatacenter=self.mock_create_datacenter)
def test_get_root_folder(self):
mock_get_root_folder = MagicMock()
with patch('salt.utils.vmware.get_root_folder', mock_get_root_folder):
vmware.create_datacenter(self.mock_si, 'fake_dc')
mock_get_root_folder.assert_called_once_with(self.mock_si)
def test_create_datacenter_call(self):
with patch('salt.utils.vmware.get_root_folder',
MagicMock(return_value=self.mock_root_folder)):
vmware.create_datacenter(self.mock_si, 'fake_dc')
self.mock_create_datacenter.assert_called_once_with('fake_dc')
def test_create_datacenter_raise_vim_fault(self):
exc = vim.VimFault()
exc.msg = 'VimFault msg'
self.mock_root_folder = MagicMock(
CreateDatacenter=MagicMock(side_effect=exc))
with patch('salt.utils.vmware.get_root_folder',
MagicMock(return_value=self.mock_root_folder)):
with self.assertRaises(VMwareApiError) as excinfo:
vmware.create_datacenter(self.mock_si, 'fake_dc')
self.assertEqual(excinfo.exception.strerror, 'VimFault msg')
def test_create_datacenter_runtime_fault(self):
exc = vmodl.RuntimeFault()
exc.msg = 'RuntimeFault msg'
self.mock_root_folder = MagicMock(
CreateDatacenter=MagicMock(side_effect=exc))
with patch('salt.utils.vmware.get_root_folder',
MagicMock(return_value=self.mock_root_folder)):
with self.assertRaises(VMwareRuntimeError) as excinfo:
vmware.create_datacenter(self.mock_si, 'fake_dc')
self.assertEqual(excinfo.exception.strerror, 'RuntimeFault msg')
def test_datastore_successfully_created(self):
with patch('salt.utils.vmware.get_root_folder',
MagicMock(return_value=self.mock_root_folder)):
res = vmware.create_datacenter(self.mock_si, 'fake_dc')
self.assertEqual(res, self.mock_dc)
if __name__ == '__main__':
from integration import run_tests
run_tests(GetDatacentersTestCase, needs_daemon=False)
run_tests(GetDatacenterTestCase, needs_daemon=False)
run_tests(CreateDatacenterTestCase, needs_daemon=False)

View File

@ -0,0 +1,157 @@
# -*- coding: utf-8 -*-
'''
:codeauthor: :email:`Alexandru Bleotu <alexandru.bleotu@morganstanley.com>`
Tests for host functions in salt.utils.vmware
'''
# Import python libraries
from __future__ import absolute_import
import logging
# Import Salt testing libraries
from salttesting import TestCase, skipIf
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, patch, MagicMock
# Import Salt libraries
import salt.utils.vmware
# Import Third Party Libs
try:
from pyVmomi import vim
HAS_PYVMOMI = True
except ImportError:
HAS_PYVMOMI = False
# Get Logging Started
log = logging.getLogger(__name__)
@skipIf(NO_MOCK, NO_MOCK_REASON)
@skipIf(not HAS_PYVMOMI, 'The \'pyvmomi\' library is missing')
@patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[]))
@patch('salt.utils.vmware.get_datacenter',
MagicMock(return_value=None))
@patch('salt.utils.vmware.get_cluster',
MagicMock(return_value=None))
class GetHostsTestCase(TestCase):
'''Tests for salt.utils.vmware.get_hosts'''
def setUp(self):
self.mock_root_folder = MagicMock()
self.mock_si = MagicMock()
self.mock_host1, self.mock_host2, self.mock_host3 = MagicMock(), \
MagicMock(), MagicMock()
self.mock_prop_host1 = {'name': 'fake_hostname1',
'object': self.mock_host1}
self.mock_prop_host2 = {'name': 'fake_hostname2',
'object': self.mock_host2}
self.mock_prop_host3 = {'name': 'fake_hostname3',
'object': self.mock_host3}
self.mock_prop_hosts = [self.mock_prop_host1, self.mock_prop_host2,
self.mock_prop_host3]
def test_get_si_no_datacenter_no_cluster(self):
mock_get_mors = MagicMock()
mock_get_root_folder = MagicMock(return_value=self.mock_root_folder)
with patch('salt.utils.vmware.get_root_folder', mock_get_root_folder):
with patch('salt.utils.vmware.get_mors_with_properties',
mock_get_mors):
salt.utils.vmware.get_hosts(self.mock_si)
mock_get_root_folder.assert_called_once_with(self.mock_si)
mock_get_mors.assert_called_once_with(
self.mock_si, vim.HostSystem, container_ref=self.mock_root_folder,
property_list=['name'])
def test_get_si_datacenter_name_no_cluster_name(self):
mock_dc = MagicMock()
mock_get_dc = MagicMock(return_value=mock_dc)
mock_get_mors = MagicMock()
with patch('salt.utils.vmware.get_datacenter', mock_get_dc):
with patch('salt.utils.vmware.get_mors_with_properties',
mock_get_mors):
salt.utils.vmware.get_hosts(self.mock_si,
datacenter_name='fake_datacenter')
mock_get_dc.assert_called_once_with(self.mock_si, 'fake_datacenter')
mock_get_mors.assert_called_once_with(self.mock_si,
vim.HostSystem,
container_ref=mock_dc,
property_list=['name'])
def test_get_si_datacenter_name_and_cluster_name(self):
mock_dc = MagicMock()
mock_get_dc = MagicMock(return_value=mock_dc)
mock_get_cl = MagicMock()
mock_get_mors = MagicMock()
with patch('salt.utils.vmware.get_datacenter', mock_get_dc):
with patch('salt.utils.vmware.get_cluster', mock_get_cl):
with patch('salt.utils.vmware.get_mors_with_properties',
mock_get_mors):
salt.utils.vmware.get_hosts(
self.mock_si, datacenter_name='fake_datacenter',
cluster_name='fake_cluster')
mock_get_dc.assert_called_once_with(self.mock_si, 'fake_datacenter')
mock_get_cl.assert_called_once_with(mock_dc, 'fake_cluster')
mock_get_mors.assert_called_once_with(self.mock_si,
vim.HostSystem,
container_ref=mock_dc,
property_list=['name', 'parent'])
def test_host_get_all_hosts(self):
with patch('salt.utils.vmware.get_root_folder',
MagicMock(return_value=self.mock_root_folder)):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_prop_hosts)):
res = salt.utils.vmware.get_hosts(self.mock_si, get_all_hosts=True)
self.assertEqual(res, [self.mock_host1, self.mock_host2,
self.mock_host3])
def test_filter_hostname(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_prop_hosts)):
res = salt.utils.vmware.get_hosts(self.mock_si,
host_names=['fake_hostname1',
'fake_hostname2'])
self.assertEqual(res, [self.mock_host1, self.mock_host2])
def test_get_all_host_flag_not_set_and_no_host_names(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_prop_hosts)):
res = salt.utils.vmware.get_hosts(self.mock_si)
self.assertEqual(res, [])
def test_filter_cluster(self):
cluster1 = vim.ClusterComputeResource('fake_good_cluster')
cluster2 = vim.ClusterComputeResource('fake_bad_cluster')
# Mock cluster1.name and cluster2.name
cluster1._stub = MagicMock(InvokeAccessor=MagicMock(
return_value='fake_good_cluster'))
cluster2._stub = MagicMock(InvokeAccessor=MagicMock(
return_value='fake_bad_cluster'))
self.mock_prop_host1['parent'] = cluster2
self.mock_prop_host2['parent'] = cluster1
self.mock_prop_host3['parent'] = cluster1
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=self.mock_prop_hosts)):
res = salt.utils.vmware.get_hosts(self.mock_si,
datacenter_name='fake_datacenter',
cluster_name='fake_good_cluster',
get_all_hosts=True)
self.assertEqual(res, [self.mock_host2, self.mock_host3])
def test_no_hosts(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[])):
res = salt.utils.vmware.get_hosts(self.mock_si, get_all_hosts=True)
self.assertEqual(res, [])
def test_one_host_returned(self):
with patch('salt.utils.vmware.get_mors_with_properties',
MagicMock(return_value=[self.mock_prop_host1])):
res = salt.utils.vmware.get_hosts(self.mock_si, get_all_hosts=True)
self.assertEqual(res, [self.mock_host1])
if __name__ == '__main__':
from integration import run_tests
run_tests(GetHostsTestCase, needs_daemon=False)