mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
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:
commit
132d8b7b88
@ -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.'
|
||||
|
@ -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
|
||||
'''
|
||||
|
@ -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)
|
||||
|
249
tests/unit/utils/vmware_test/test_cluster.py
Normal file
249
tests/unit/utils/vmware_test/test_cluster.py
Normal 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)
|
@ -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)
|
@ -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)
|
183
tests/unit/utils/vmware_test/test_datacenter.py
Normal file
183
tests/unit/utils/vmware_test/test_datacenter.py
Normal 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)
|
157
tests/unit/utils/vmware_test/test_host.py
Normal file
157
tests/unit/utils/vmware_test/test_host.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user