import logging
import salt.exceptions
import saltext.vmware.utils.common as utils_common
import saltext.vmware.utils.datacenter as utils_datacenter
# pylint: disable=no-name-in-module
try:
from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError:
HAS_PYVMOMI = False
log = logging.getLogger(__name__)
[docs]def get_clusters(service_instance, datacenter_name=None, cluster_name=None):
"""
Returns clusters in a vCenter.
service_instance
The Service Instance Object from which to obtain cluster.
datacenter_name
(Optional) Datacenter name to filter by.
cluster_name
(Optional) Exact cluster name to filter by. Requires datacenter_name.
"""
if cluster_name and not datacenter_name:
raise salt.exceptions.ArgumentValueError(
"datacenter_name is required when looking up by cluster_name"
)
clusters = []
for cluster in utils_common.get_mors_with_properties(
service_instance, vim.ClusterComputeResource, property_list=["name"]
):
if cluster_name and cluster_name != cluster["name"]:
continue
if (
datacenter_name
and datacenter_name
!= utils_common.get_parent_of_type(cluster["object"], vim.Datacenter).name
):
continue
clusters.append(cluster["object"])
return clusters
[docs]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 = utils_common.get_managed_object_name(dc_ref)
log.trace("Retrieving cluster '%s' from datacenter '%s'", cluster, dc_name)
si = utils_common.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 utils_common.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 '{}' was not found in datacenter " "'{}'".format(cluster, dc_name)
)
return items[0]
[docs]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 = utils_common.get_managed_object_name(dc_ref)
log.trace("Creating cluster '%s' in datacenter '%s'", cluster_name, dc_name)
try:
dc_ref.hostFolder.CreateClusterEx(cluster_name, cluster_spec)
except vim.fault.NoPermission as exc:
log.exception(exc)
raise salt.exceptions.VMwareApiError(
"Not enough permissions. Required privilege: " "{}".format(exc.privilegeId)
)
except vim.fault.VimFault as exc:
log.exception(exc)
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
log.exception(exc)
raise salt.exceptions.VMwareRuntimeError(exc.msg)
[docs]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 = utils_common.get_managed_object_name(cluster_ref)
log.trace("Updating cluster '%s'", cluster_name)
try:
task = cluster_ref.ReconfigureComputeResource_Task(cluster_spec, modify=True)
except vim.fault.NoPermission as exc:
log.exception(exc)
raise salt.exceptions.VMwareApiError(
"Not enough permissions. Required privilege: " "{}".format(exc.privilegeId)
)
except vim.fault.VimFault as exc:
log.exception(exc)
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
log.exception(exc)
raise salt.exceptions.VMwareRuntimeError(exc.msg)
utils_common.wait_for_task(task, cluster_name, "ClusterUpdateTask")
[docs]def delete_cluster(service_instance, cluster_name, datacenter_name):
"""
Deletes a datacenter.
service_instance
The Service Instance Object
cluster_name
The name of the cluster to delete
datacenter_name
The datacenter name to which the cluster belongs
"""
root_folder = utils_common.get_root_folder(service_instance)
log.trace("Deleting cluster '%s' in '%s'", cluster_name, datacenter_name)
try:
dc_obj = utils_datacenter.get_datacenter(service_instance, datacenter_name)
cluster_obj = get_cluster(dc_ref=dc_obj, cluster=cluster_name)
task = cluster_obj.Destroy_Task()
except vim.fault.NoPermission as exc:
log.exception(exc)
raise salt.exceptions.VMwareApiError(
"Not enough permissions. Required privilege: {}".format(exc.privilegeId)
)
except vim.fault.VimFault as exc:
log.exception(exc)
raise salt.exceptions.VMwareApiError(exc.msg)
except vmodl.RuntimeFault as exc:
log.exception(exc)
raise salt.exceptions.VMwareRuntimeError(exc.msg)
utils_common.wait_for_task(task, cluster_name, "DeleteClusterTask")
[docs]def list_clusters(service_instance):
"""
Returns a list of clusters associated with a given service instance.
service_instance
The Service Instance Object from which to obtain clusters.
"""
return utils_common.list_objects(service_instance, vim.ClusterComputeResource)
[docs]def create_drs_rule(name, affinity, vm_refs, enabled, mandatory, cluster_ref):
"""
Create a virtual machine to virtual machine affinity or anti affinity DRS rule
name
The name of the rule.
affinity
(boolean) Describes whether to make affinity or anti affinity rule.
vm_refs
Array of virtual machines associated with DRS rule.
enabled
(boolean) Enable the DRS rule being created.
mandatory
(boolean) Sets whether the rule being created is mandatory.
cluster_ref
Reference to cluster DRS rule is being created on.
"""
if affinity:
rule_spec = vim.cluster.AffinityRuleSpec()
else:
rule_spec = vim.cluster.AntiAffinityRuleSpec()
rule_spec.vm = vm_refs
rule_spec.enabled = enabled
rule_spec.mandatory = mandatory
rule_spec.name = name
spec = vim.cluster.RuleSpec(info=rule_spec, operation="add")
config_spec = vim.cluster.ConfigSpecEx(rulesSpec=[spec])
task = cluster_ref.ReconfigureEx(config_spec, modify=True)
utils_common.wait_for_task(task, "Cluster", "Create DRS rule Task")
[docs]def update_drs_rule(rule_ref, vm_refs, enabled, mandatory, cluster_ref):
"""
Update a virtual machine to virtual machine affinity or anti affinity DRS rule
rule_ref
Reference to rule with same name.
vm_refs
Array of virtual machines associated with DRS rule.
enabled
(boolean) Enable the DRS rule being created. Defaults to True.
mandatory
(optional, boolean) Sets whether the rule being created is mandatory. Defaults to None.
cluster_ref
Reference to cluster DRS rule is being created on.
"""
rule_ref.vm = vm_refs
rule_ref.enabled = enabled
rule_ref.mandatory = mandatory
spec = vim.cluster.RuleSpec(info=rule_ref, operation="edit")
config_spec = vim.cluster.ConfigSpecEx(rulesSpec=[spec])
task = cluster_ref.ReconfigureEx(config_spec, modify=True)
utils_common.wait_for_task(task, "Cluster", "Create DRS rule Task")
[docs]def drs_rule_info(rule):
"""
Returns info on a DRS rule.
rule
Reference to DRS rule.
"""
rule_info = {
"name": rule.name,
"uuid": rule.ruleUuid,
"enabled": rule.enabled,
"mandatory": rule.mandatory,
"key": rule.key,
"in_compliance": rule.inCompliance,
}
if type(rule) == vim.cluster.AntiAffinityRuleSpec or type(rule) == vim.cluster.AffinityRuleSpec:
vms = []
for vm in rule.vm:
vms.append(vm.name)
rule_info["type"] = "vm_affinity_rule"
rule_info["vms"] = vms
rule_info["affinity"] = check_affinity(rule)
elif type(rule) == vim.cluster.VmHostRuleInfo:
rule_info["type"] = "vm_host_rule"
rule_info["vm_group_name"] = rule.vmGroupName
rule_info["affine_host_group_name"] = rule.affineHostGroupName
rule_info["anti_affine_host_group_name"] = rule.antiAffineHostGroupName
elif type(rule) == vim.cluster.DependencyRuleInfo:
rule_info["type"] = "dependency_rule"
rule_info["vm_group"] = rule.vmGroup
rule_info["depends_on_vm_group"] = rule.dependsOnVmGroup
else:
raise salt.exceptions.VMwareApiError({f"Unknown affinity rule type {type(rule)}"})
return rule_info
[docs]def check_affinity(rule):
"""
returns True if rule is Affine, or False if rule is AntiAffine.
rule
Reference to DRS rule.
"""
if type(rule) == vim.cluster.AntiAffinityRuleSpec:
return False
elif type(rule) == vim.cluster.AffinityRuleSpec:
return True
else:
raise Exception(f"Rule type {type(rule)} has no affinity.")