Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions src/saltext/vmware/modules/datacenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ def create(name, service_instance=None, profile=None):
try:
utils_datacenter.create_datacenter(service_instance, name)
except salt.exceptions.VMwareApiError as exc:
return {name: False, "reason": str(exc)}
return {name: True}
return {name: False, "reason": str(exc), "success": False}
return {name: True, "success": True}


def get(name, service_instance=None, profile=None):
Expand Down Expand Up @@ -103,7 +103,19 @@ def get(name, service_instance=None, profile=None):
ret = dc[0]
except (salt.exceptions.VMwareApiError, salt.exceptions.VMwareObjectRetrievalError) as exc:
return {name: False, "reason": str(exc)}
return ret

vm_folders = utils_common.get_all_folders(service_instance, datacenter_name=None, datacenter=dc_ref)
ds_folders = utils_common.get_all_folders(service_instance, datacenter_name=None, datacenter=dc_ref, folder_key="datastoreFolder")
hs_folders = utils_common.get_all_folders(service_instance, datacenter_name=None, datacenter=dc_ref, folder_key="networkFolder")
nt_folders = utils_common.get_all_folders(service_instance, datacenter_name=None, datacenter=dc_ref, folder_key="hostFolder")
return {
"name": ret["name"],
"status": ret["overallStatus"],
"vm_folders": [f.name for f in vm_folders],
"ds_folders": [f.name for f in ds_folders],
"hst_folders": [f.name for f in hs_folders],
"ntwk_folders": [f.name for f in nt_folders],
}


def delete(name, service_instance=None, profile=None):
Expand Down Expand Up @@ -131,5 +143,5 @@ def delete(name, service_instance=None, profile=None):
try:
utils_datacenter.delete_datacenter(service_instance, name)
except (salt.exceptions.VMwareApiError, salt.exceptions.VMwareObjectRetrievalError) as exc:
return {name: False, "reason": str(exc)}
return {name: True}
return {name: False, "reason": str(exc), "success": False}
return {name: True, "success": True}
219 changes: 214 additions & 5 deletions src/saltext/vmware/modules/datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ def get(
"type": summary.type,
"url": summary.url,
"uncommitted": summary.uncommitted if summary.uncommitted else 0,
"folder": utils_common.get_path(datastore, service_instance),
}
ret.append(info)

Expand Down Expand Up @@ -230,7 +231,6 @@ def list_datastores(
datastores = utils_datastore.get_datastores_from_ref(
service_instance, host, datastore_names, backing_disk_ids, get_all_datastores
)

# Search for disk backed datastores if target is host
# to be able to add the backing_disk_ids
mount_infos = []
Expand All @@ -247,17 +247,18 @@ def list_datastores(
"type": datastore.summary.type,
"free_space": datastore.summary.freeSpace,
"capacity": datastore.summary.capacity,
"uuid": datastore.info.vmfs.uuid,
}
backing_disk_ids = []
backing_disk_id_list = []
for vol in [
i.volume
for i in mount_infos
if i.volume.name == datastore.name and isinstance(i.volume, vim.HostVmfsVolume)
]:

backing_disk_ids.extend([e.diskName for e in vol.extent])
if backing_disk_ids:
datastore_dict["backing_disk_ids"] = backing_disk_ids
backing_disk_id_list.extend([e.diskName for e in vol.extent])
if backing_disk_id_list:
datastore_dict["backing_disk_ids"] = backing_disk_id_list
ret[host.name].append(datastore_dict)
return ret

Expand Down Expand Up @@ -408,3 +409,211 @@ def list_datastore_clusters(
get_all_hosts=host_name is None,
)
return utils_datastore.list_datastore_clusters(service_instance)

def unmount_datastore(
datastore_name,
datacenter_name=None,
cluster_name=None,
host_name=None,
service_instance=None,
profile=None,
):
"""
unmounts a datastore and detaches the backing disk

datastore_name
Name of the datastore to unmount

datacenter_name
Filter by this datacenter name (required when cluster is not specified)

cluster_name
Filter by this cluster name (required when datacenter is not specified)

host_name
Filter by this ESXi hostname (optional).

service_instance
Use this vCenter service connection instance instead of creating a new one. (optional).

profile
Profile to use (optional)

CLI Example:

.. code-block:: bash

salt '*' vmware_datastore.unmount_datastore datastore_name=ds1
salt '*' vmware_datastore.unmount_datastore datastore_name=ds1 cluster_name=cl1
"""
log.debug("Running vmware_datastore.unmount_datastore")
ret = {"success": True}
service_instance = service_instance or connect.get_service_instance(
config=__opts__, profile=profile
)
hosts = utils_esxi.get_hosts(
service_instance=service_instance,
host_names=[host_name] if host_name else None,
cluster_name=cluster_name,
datacenter_name=datacenter_name,
get_all_hosts=host_name is None,
)
for host in hosts:
ret[host.name] = []
datastores = utils_datastore.get_datastores_from_ref(
service_instance, host, [datastore_name], None, False
)
if isinstance(host, vim.HostSystem):
storage_system = utils_common.get_storage_system(service_instance, host, host.name)
props = utils_common.get_properties_of_managed_object(
storage_system, ["fileSystemVolumeInfo.mountInfo"]
)
mount_infos = props.get("fileSystemVolumeInfo.mountInfo", [])

for datastore in datastores:
for host_mount in datastore.host:
if host_mount.key.name == host.name:
if host_mount.mountInfo.mounted:
try:
ret[host.name].append(f"unmounting vmfs {datastore.info.vmfs.uuid} from {host.name}")
storage_system.UnmountVmfsVolume(datastore.info.vmfs.uuid)
except Exception as err:
ret["success"] = False
ret[host.name].append((False, f"Error unmounting vmfs: {err}"))
return ret
else:
ret[host.name].append(f"vmfs {datastore.info.vmfs.uuid} not mounted on {host.name}")
try:
for vol in [
i.volume
for i in mount_infos
if i.volume.name == datastore.name and isinstance(i.volume, vim.HostVmfsVolume)
]:
for dsk in vol.extent:
ret[host.name].append(f"detaching disk {dsk.diskName} from {host.name}")
storage_system.DetachScsiLun(dsk.diskName)
except Exception as err:
ret["success"] = False
ret[host.name].append((False, f"Error detaching lun: {err}"))
return ret

storage_system.RefreshStorageSystem()
ret[host.name].append(f"rescanning storage on {host.name}")
return ret

def mount_datastore(
datastore_name,
vmfs_uuid,
disk_id,
datacenter_name=None,
cluster_name=None,
host_name=None,
folder_name=None,
service_instance=None,
profile=None,
):
"""
attaches a lun and mounts the datastore in the lun

datastore_name
The name of the datastore that will be attached

vmfs_uuid
The uuid of the VMFS datastore to mount

disk_id
The id of the scsi lun to attach

datacenter_name
Filter by this datacenter name (required when cluster is not specified)

cluster_name
Filter by this cluster name (required when datacenter is not specified)

host_name
Filter by this ESXi hostname (optional).

folder_name
The name of the folder to put the datastore in (optional)

service_instance
Use this vCenter service connection instance instead of creating a new one. (optional).

profile
Profile to use (optional)

CLI Example:

.. code-block:: bash

salt '*' vmware_datastore.mount_datastore datastore_name=ds1 vmfs_uuid=xxxx=-xxx-xxxxx disk_id=naa.xxxxxxxx
salt '*' vmware_datastore.mount_datastore datastore_name=ds1 vmfs_uuid=xxxx=-xxx-xxxxx disk_id=naa.xxxxxxxx cluster_name=cl1
"""
log.debug("Running vmware_datastore.mount_datastore")
ret = {"success": True}
service_instance = service_instance or connect.get_service_instance(
config=__opts__, profile=profile
)
hosts = utils_esxi.get_hosts(
service_instance=service_instance,
host_names=[host_name] if host_name else None,
cluster_name=cluster_name,
datacenter_name=datacenter_name,
get_all_hosts=host_name is None,
)
for host in hosts:
ret[host.name] = []
datastores = utils_datastore.get_datastores_from_ref(
service_instance, host, [datastore_name], None, False
)
ds = utils_vmware.get_host_datastore_system(host)
if not datastores:
if isinstance(host, vim.HostSystem):
storage_system = utils_common.get_storage_system(service_instance, host, host.name)
props = utils_common.get_properties_of_managed_object(
storage_system, ["fileSystemVolumeInfo.mountInfo"]
)
try:
ret[host.name].append(f"attaching disk {disk_id} to {host.name}")
storage_system.AttachScsiLun(disk_id)
except vim.fault.InvalidState:
ret[host.name].append(f"disk {disk_id} already attached to {host.name}")

storage_system.RefreshStorageSystem()
ret[host.name].append(f"rescanning storage on {host.name}")
try:
ret[host.name].append(f"mounting vmfs {vmfs_uuid} to {host.name}")
storage_system.MountVmfsVolume(vmfs_uuid)
except vim.fault.NotFound as err:
ret[host.name].append(f"vmfs {vmfs_uuid} not found")
unresolved_vols = storage_system.QueryUnresolvedVmfsVolume()
if unresolved_vols:
ret[host.name].append(f"unresolved volumes found")
for un_vol in unresolved_vols:
if un_vol.vmfsUuid == vmfs_uuid:
if un_vol.resolveStatus.resolvable:
ret[host.name].append(f"{vmfs_uuid} has a resolvable conflict")
spec = vim.host.UnresolvedVmfsResolutionSpec()
paths = []
for extent in un_vol.extent:
paths.append(extent.devicePath)
spec.extentDevicePath = paths
spec.uuidResolution = "forceMounted"
try:
ret[host.name].append(f"resolving {vmfs_uuid}")
storage_system.ResolveMultipleUnresolvedVmfsVolumes([spec])
except Exception as err:
ret["success"] = False
ret[host.name].append(f"Error: {err}")
else:
ret["success"] = False
ret[host.name].append((False, f"{vmfs_uuid} has an unresolvable conflict"))
except vim.fault.InvalidState:
ret[host.name].append(f"vmfs {vmfs_uuid} already mounted")

storage_system.RefreshStorageSystem()
ret[host.name].append(f"rescanning storage on {host.name}")
else:
ret[host.name].append("datastore already mounted")

return ret
37 changes: 22 additions & 15 deletions src/saltext/vmware/modules/dvportgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def __virtual__():
return __virtualname__


def get(switch_name, portgroup_key, host_name=None, service_instance=None, profile=None):
def get(switch_name, portgroup_id=None, host_name=None, service_instance=None, profile=None):
"""
Get distributed portgroup from a distributed switch optionally from a host.

Expand All @@ -35,9 +35,9 @@ def get(switch_name, portgroup_key, host_name=None, service_instance=None, profi
switch_name
Name of the distributed switch.

portgroup_key
Portgroup key.

portgroup_id
Portgroup key or name. (Optional).
host_name
Name of the ESXi host. (optional).

Expand All @@ -47,25 +47,32 @@ def get(switch_name, portgroup_key, host_name=None, service_instance=None, profi
profile
Profile to use (optional)
"""
ret = {}
ret = []

service_instance = service_instance or connect.get_service_instance(
config=__opts__, profile=profile
)

switch_ref = utils_vmware._get_dvs(service_instance=service_instance, dvs_name=switch_name)

if switch_ref:
for portgroup in switch_ref.portgroup:
if portgroup.key == portgroup_key:
ret["name"] = portgroup.config.name
ret["vlan"] = portgroup.config.defaultPortConfig.vlan.vlanId
ret["pnic"] = []
if host_name:
for host in portgroup.config.distributedVirtualSwitch.config.host:
if host.config.host.name == host_name:
for pnic in host.config.backing.pnicSpec:
ret["pnic"].append(pnic.pnicDevice)
pg = {}
pg["name"] = portgroup.config.name
pg["key"] = portgroup.config.key
pg["vlan"] = portgroup.config.defaultPortConfig.vlan.vlanId
pg["ports"] = portgroup.config.numPorts
pg["pnic"] = []
if host_name:
for host in portgroup.config.distributedVirtualSwitch.config.host:
if host.config.host.name == host_name:
for pnic in host.config.backing.pnicSpec:
pg["pnic"].append(pnic.pnicDevice)

if portgroup_id and portgroup_id in [portgroup.config.name, portgroup.config.key]:
ret.append(pg)
elif not portgroup_id:
ret.append(pg)


ret = json.loads(json.dumps(ret, cls=VmomiSupport.VmomiJSONEncoder))
return ret
Loading