/* * Copyright (c) 2012-2015 iWave Software LLC * All Rights Reserved */ package com.emc.sa.service.vmware; import static com.emc.sa.service.vipr.ViPRExecutionUtils.addAffectedResource; import static com.emc.sa.service.vipr.ViPRExecutionUtils.addInjectedValue; import static com.emc.sa.service.vipr.ViPRExecutionUtils.addRollback; import static com.emc.sa.service.vipr.ViPRExecutionUtils.execute; import static com.emc.sa.service.vipr.ViPRExecutionUtils.logError; import static com.emc.sa.service.vipr.ViPRExecutionUtils.logWarn; import java.net.URI; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import com.emc.sa.engine.ExecutionException; import com.emc.sa.engine.ExecutionUtils; import com.emc.sa.machinetags.KnownMachineTags; import com.emc.sa.service.vipr.block.tasks.GetBlockVolumeByWWN; import com.emc.sa.service.vipr.block.tasks.RemoveBlockVolumeMachineTag; import com.emc.sa.service.vipr.block.tasks.SetBlockVolumeMachineTag; import com.emc.sa.service.vipr.file.tasks.FindFilesystemWithDatastore; import com.emc.sa.service.vipr.tasks.GetCluster; import com.emc.sa.service.vipr.tasks.GetHost; import com.emc.sa.service.vmware.block.tasks.AttachScsiDisk; import com.emc.sa.service.vmware.block.tasks.CreateVmfsDatastore; import com.emc.sa.service.vmware.block.tasks.DetachLunsFromHost; import com.emc.sa.service.vmware.block.tasks.ExpandVmfsDatastore; import com.emc.sa.service.vmware.block.tasks.ExtendVmfsDatastore; import com.emc.sa.service.vmware.block.tasks.FindHostScsiDiskForLun; import com.emc.sa.service.vmware.block.tasks.FindLunsBackingDatastore; import com.emc.sa.service.vmware.block.tasks.MountDatastore; import com.emc.sa.service.vmware.block.tasks.RefreshStorage; import com.emc.sa.service.vmware.block.tasks.SetMultipathPolicy; import com.emc.sa.service.vmware.block.tasks.SetStorageIOControl; import com.emc.sa.service.vmware.block.tasks.UnmountVmfsDatastore; import com.emc.sa.service.vmware.block.tasks.VerifyDatastoreHostMounts; import com.emc.sa.service.vmware.file.tasks.CreateNfsDatastore; import com.emc.sa.service.vmware.file.tasks.GetEndpoints; import com.emc.sa.service.vmware.file.tasks.TagDatastoreOnFilesystem; import com.emc.sa.service.vmware.file.tasks.UntagDatastoreOnFilesystem; import com.emc.sa.service.vmware.tasks.ConnectToVCenter; import com.emc.sa.service.vmware.tasks.DeleteDatastore; import com.emc.sa.service.vmware.tasks.EnterMaintenanceMode; import com.emc.sa.service.vmware.tasks.FindCluster; import com.emc.sa.service.vmware.tasks.FindDatastore; import com.emc.sa.service.vmware.tasks.FindESXHost; import com.emc.sa.service.vmware.tasks.GetVcenter; import com.emc.sa.service.vmware.tasks.GetVcenterDataCenter; import com.emc.sa.service.vmware.tasks.VerifyDatastoreDoesNotExist; import com.emc.sa.service.vmware.tasks.VerifyDatastoreForRemoval; import com.emc.sa.service.vmware.tasks.VerifySupportedMultipathPolicy; import com.emc.storageos.db.client.model.Cluster; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.Vcenter; import com.emc.storageos.db.client.model.VcenterDataCenter; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.model.block.BlockObjectRestRep; import com.emc.storageos.model.block.VolumeRestRep; import com.emc.storageos.model.file.FileShareRestRep; import com.emc.storageos.model.file.FileSystemExportParam; import com.emc.vipr.client.core.util.ResourceUtils; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.iwave.ext.vmware.HostStorageAPI; import com.iwave.ext.vmware.VCenterAPI; import com.iwave.ext.vmware.VMWareException; import com.iwave.ext.vmware.VMwareUtils; import com.vmware.vim25.DatastoreHostMount; import com.vmware.vim25.DatastoreSummaryMaintenanceModeState; import com.vmware.vim25.HostRuntimeInfo; import com.vmware.vim25.HostScsiDisk; import com.vmware.vim25.HostSystemConnectionState; import com.vmware.vim25.MethodFault; import com.vmware.vim25.mo.ClusterComputeResource; import com.vmware.vim25.mo.Datastore; import com.vmware.vim25.mo.HostSystem; public class VMwareSupport { private URI vcenterId; private VCenterAPI vcenterAPI; public void connect(URI vcenterId) { this.vcenterId = vcenterId; Vcenter vcenter = getVcenter(vcenterId); vcenterAPI = execute(new ConnectToVCenter(vcenter)); addInjectedValue(VCenterAPI.class, vcenterAPI); } public void disconnect() { if (vcenterAPI != null) { vcenterAPI.logout(); vcenterAPI = null; } } public Vcenter getVcenter(URI vcenterId) { return execute(new GetVcenter(vcenterId)); } public VcenterDataCenter getDatacenter(URI datacenterId) { return execute(new GetVcenterDataCenter(datacenterId)); } public Host getESXHost(URI hostId) { return execute(new GetHost(hostId)); } public Cluster getCluster(URI clusterId) { if (NullColumnValueGetter.isNullURI(clusterId)) { return null; } return execute(new GetCluster(clusterId)); } public HostSystem getHostSystem(String datacenterName, String esxHostName, boolean verifyHostExists) { return execute(new FindESXHost(datacenterName, esxHostName, verifyHostExists)); } public ClusterComputeResource getCluster(String datacenterName, String clusterName, boolean checkClusterConnectivity) { return execute(new FindCluster(datacenterName, clusterName, checkClusterConnectivity)); } public ClusterComputeResource getCluster(String datacenterName, String clusterName) { return getCluster(datacenterName, clusterName, true); } public Datastore getDatastore(String datacenterName, String datastoreName) { return execute(new FindDatastore(datacenterName, datastoreName)); } public Set<String> getEndpoints(HostSystem host, ClusterComputeResource cluster) { return execute(new GetEndpoints(host, cluster)); } /** * Verify that the datastore does not exist. * * @param datacenterName * the datacenter name. * @param datastoreName * the datastore name. */ public void verifyDatastoreDoesNotExist(String datacenterName, String datastoreName) { execute(new VerifyDatastoreDoesNotExist(datacenterName, datastoreName)); } /** * Verify that the multipath policy is supported on a host. * * @param host * the host. * @param multipathPolicy * the multipath policy. */ public void verifySupportedMultipathPolicy(HostSystem host, String multipathPolicy) { if (VMwareUtils.isValidMultipathPolicy(multipathPolicy)) { execute(new VerifySupportedMultipathPolicy(host, multipathPolicy)); } } /** * Performs various checks to see if the datastore should be able to be removed. * * @param datastore * the datastore. */ public void verifyDatastoreForRemoval(Datastore datastore) { execute(new VerifyDatastoreForRemoval(datastore)); } /** * Performs various checks to see if the datatore should be able to be removed. * * @param datastore * the datastore. * @param datacenterName * the name of the datacenter that we will use to check hosts that can access the datastore. * @param hosts * the hosts that we will check to see if any VMs are running on this datastore. */ public void verifyDatastoreForRemoval(Datastore datastore, String datacenterName, List<Host> hosts) { execute(new VerifyDatastoreForRemoval(datastore, datacenterName, hosts)); } /** * Creates a VMFS datastore. * * @param host * the host to which the volume is assigned. * @param cluster * the cluster to which the volume is associated (may be null if the storage is exclusive to the host) * @param volume * the volume to create the datastore on. * @param datastoreName * the name of the datastore to create. * @return datastore */ public Datastore createVmfsDatastore(HostSystem host, ClusterComputeResource cluster, URI hostOrClusterId, BlockObjectRestRep volume, String datastoreName) { HostScsiDisk disk = findScsiDisk(host, cluster, volume, true); Datastore datastore = execute(new CreateVmfsDatastore(host, disk, datastoreName)); addAffectedResource(volume); addVmfsDatastoreTag(volume, hostOrClusterId, datastoreName); ExecutionUtils.clearRollback(); return datastore; } /** * Sets the multipath policy on the disks for the given host/cluster * * @param host * the host to which the volume is assigned. * @param cluster * the cluster to which the volume is associated (may be null if the storage is exclusive to the host) * @param multipathPolicy * the multipath policy to use. * @param volume * the volume with the created datastore. */ public void setMultipathPolicy(HostSystem host, ClusterComputeResource cluster, String multipathPolicy, BlockObjectRestRep volume) { if (VMwareUtils.isValidMultipathPolicy(multipathPolicy)) { Map<HostSystem, HostScsiDisk> hostDisks = Maps.newHashMap(); if (cluster != null) { List<HostSystem> clusterHosts = Lists.newArrayList(cluster.getHosts()); for (HostSystem clusterHost : clusterHosts) { if (isHostConnected(clusterHost)) { HostScsiDisk disk = execute(new FindHostScsiDiskForLun(clusterHost, volume)); hostDisks.put(clusterHost, disk); } } } else if (host != null) { HostScsiDisk disk = execute(new FindHostScsiDiskForLun(host, volume)); hostDisks.put(host, disk); } if (hostDisks.size() > 0) { execute(new SetMultipathPolicy(hostDisks, multipathPolicy)); } } } public void detachLuns(HostSystem host, List<HostScsiDisk> disks) { execute(new DetachLunsFromHost(host, disks)); addRollback(new AttachScsiDisk(host, disks)); } public void unmountVmfsDatastore(HostSystem host, Datastore datastore) { execute(new UnmountVmfsDatastore(host, datastore)); addRollback(new MountDatastore(host, datastore)); } /** * Sets the storage IO control for the given datastore * * @param datastore * the datastore to set the storage io control on * @param enabled * true to enable storage io control or false to disable storage io control */ public void setStorageIOControl(Datastore datastore, Boolean enabled) { setStorageIOControl(datastore, enabled, false); } /** * Sets the storage IO control for the given datastore * * @param datastore * the datastore to set the storage io control on * @param enabled * true to enable storage io control or false to disable storage io control * @param failIfErrorDuringEnable * true to fail the operation of enabling storage I/O if storage I/O is not supported */ public void setStorageIOControl(Datastore datastore, Boolean enabled, Boolean failIfErrorDuringEnable) { if (enabled != null && datastore != null) { if (datastore.getCapability() != null && datastore.getCapability().storageIORMSupported) { execute(new SetStorageIOControl(datastore, enabled)); } else if (enabled && failIfErrorDuringEnable) { ExecutionUtils.fail("failTask.SetStorageIOControl", new Object[] {}, datastore.getName()); } else { logWarn("vmware.support.storage.io.control.not.supported", datastore.getName()); } } } /** * Extends a VMFS datastore. * * @param host * the host to which the volume is assigned. * @param cluster * the cluster to which the volume is associated (may be null if the storage is exclusive to the host) * @param volume * the volume to extend the datastore with. * @param datastore * the datastore to extend. */ public void extendVmfsDatastore(HostSystem host, ClusterComputeResource cluster, URI hostOrClusterId, BlockObjectRestRep volume, Datastore datastore) { HostScsiDisk disk = findScsiDisk(host, cluster, volume, true); execute(new ExtendVmfsDatastore(host, disk, datastore)); addAffectedResource(volume); addVmfsDatastoreTag(volume, hostOrClusterId, datastore.getName()); ExecutionUtils.clearRollback(); } /** * Expand a VMFS datastore. * * @param host * the host to which the volume is assigned. * @param cluster * the cluster to which the volume is associated (may be null if the storage is exclusive to the host) * @param volume * the volume that was expanded. * @param datastore * the datastore to expand. */ public void expandVmfsDatastore(HostSystem host, ClusterComputeResource cluster, URI hostOrClusterId, BlockObjectRestRep volume, Datastore datastore) { HostScsiDisk disk = findScsiDisk(host, cluster, volume); execute(new ExpandVmfsDatastore(host, disk, datastore)); addAffectedResource(volume); addVmfsDatastoreTag(volume, hostOrClusterId, datastore.getName()); ExecutionUtils.clearRollback(); } /** * Verifies that the datastore host configuration matches the host/cluster configuration. * * @param host * the host * @param cluster * the cluster, will be null when using exclusive storage * @param datastore * the datastore to verify. */ public void verifyDatastoreMounts(HostSystem host, ClusterComputeResource cluster, Datastore datastore) { execute(new VerifyDatastoreHostMounts(host, cluster, datastore)); } /** * Puts the datastore into maintenance mode, if required. * * @param datastore * the datastore. */ public void enterMaintenanceMode(Datastore datastore) { String maintenanceMode = datastore.getSummary().getMaintenanceMode(); // Only attempt to enter maintenance mode if the state is unknown (null) or normal if ((maintenanceMode == null) || maintenanceMode.equals(DatastoreSummaryMaintenanceModeState.normal.name())) { execute(new EnterMaintenanceMode(datastore)); } } /** * Deletes a VMFS datastore. Because VMFS datastores are shared across hosts, it only needs to be deleted from a * single host for it to be deleted. * * @param volumes * the volumes backing the datastore. * @param hostOrClusterId * the id of the host or cluster where the datastore is mounted. * @param datastore * the datastore to delete * @param detachLuns * if true, detach the luns from each host */ public void deleteVmfsDatastore(Collection<VolumeRestRep> volumes, URI hostOrClusterId, final Datastore datastore, boolean detachLuns) { List<HostSystem> hosts = getHostsForDatastore(datastore); if (hosts.isEmpty()) { throw new IllegalStateException("Datastore is not mounted by any hosts"); } enterMaintenanceMode(datastore); setStorageIOControl(datastore, false); HostSystem mountedHost = getHostMountedDatastore(hosts, datastore); if (mountedHost == null) { throw new IllegalStateException("Datastore is not mounted by any hosts"); } executeOnHosts(hosts, new HostSystemCallback() { @Override public void exec(HostSystem host) { if (VMwareUtils.isDatastoreMountedOnHost(datastore, host)) { unmountVmfsDatastore(host, datastore); } } }); final Map<HostSystem, List<HostScsiDisk>> hostDisks = buildHostDiskMap(hosts, datastore); execute(new DeleteDatastore(mountedHost, datastore)); if (detachLuns) { executeOnHosts(hosts, new HostSystemCallback() { @Override public void exec(HostSystem host) { List<HostScsiDisk> disks = hostDisks.get(host); detachLuns(host, disks); } }); } removeVmfsDatastoreTag(volumes, hostOrClusterId); } /** * Returns a host that has this datastore mounted on it * * @param hosts list of hosts * @param datastore the datastore * @return host that has this datastore mounted on it, or null if none of the hosts have this datastore mounted */ private HostSystem getHostMountedDatastore(List<HostSystem> hosts, Datastore datastore) { for (HostSystem host : hosts) { if (VMwareUtils.isDatastoreMountedOnHost(datastore, host)) { return host; } } return null; } private Map<HostSystem, List<HostScsiDisk>> buildHostDiskMap(List<HostSystem> hosts, Datastore datastore) { Map<HostSystem, List<HostScsiDisk>> hostDisks = new HashMap<>(); for (HostSystem host : hosts) { List<HostScsiDisk> disks = new HostStorageAPI(host).listDisks(datastore); hostDisks.put(host, disks); } return hostDisks; } private void executeOnHosts(List<HostSystem> hosts, HostSystemCallback callback) { for (HostSystem host : hosts) { callback.exec(host); } } private interface HostSystemCallback { public void exec(HostSystem host); } /** * Creates an NFS datastore for the hosts in the cluster * * @param cluster * the cluster. * @param fileSystem * the file system. * @param export * the export. * @param datacenterId * the datacenter ID. * @param datastoreName * the name of the datastore to create. * @return datastores */ public List<Datastore> createNfsDatastore(ClusterComputeResource cluster, FileShareRestRep fileSystem, FileSystemExportParam export, URI datacenterId, String datastoreName) { addNfsDatastoreTag(fileSystem, export, datacenterId, datastoreName); List<Datastore> datastores = Lists.newArrayList(); String fileServer = StringUtils.substringBefore(export.getMountPoint(), ":"); String mountPath = StringUtils.substringAfter(export.getMountPoint(), ":"); for (HostSystem host : cluster.getHosts()) { datastores.add(execute(new CreateNfsDatastore(host, fileServer, mountPath, datastoreName))); addAffectedResource(fileSystem); ExecutionUtils.clearRollback(); } return datastores; } /** * Creates an NFS datastore for a host. * * @param host * the host. * @param fileSystem * the file system. * @param export * the export. * @param datacenterId * the datacenter ID. * @param datastoreName * the name of the datastore to create. * @return datastore */ public Datastore createNfsDatastore(HostSystem host, FileShareRestRep fileSystem, FileSystemExportParam export, URI datacenterId, String datastoreName) { addNfsDatastoreTag(fileSystem, export, datacenterId, datastoreName); String fileServer = StringUtils.substringBefore(export.getMountPoint(), ":"); String mountPath = StringUtils.substringAfter(export.getMountPoint(), ":"); Datastore datastore = execute(new CreateNfsDatastore(host, fileServer, mountPath, datastoreName)); addAffectedResource(fileSystem); ExecutionUtils.clearRollback(); return datastore; } /** * Deletes an NFS datastore. The datastore will be removed from all hosts. * * @param datastore * the NFS datastore. */ public void deleteNfsDatastore(FileShareRestRep fileSystem, URI datacenterId, Datastore datastore) { String datastoreName = datastore.getName(); List<HostSystem> hosts = getHostsForDatastore(datastore); if (hosts.isEmpty()) { throw new IllegalStateException("Datastore is not mounted by any hosts"); } enterMaintenanceMode(datastore); setStorageIOControl(datastore, false); for (HostSystem host : hosts) { execute(new DeleteDatastore(host, datastore)); } removeNfsDatastoreTag(fileSystem, datacenterId, datastoreName); } /** * Gets the hosts for the given datastore. * * @param datastore * the datastore. * @return the hosts. */ public List<HostSystem> getHostsForDatastore(Datastore datastore) { List<HostSystem> hosts = Lists.newArrayList(); DatastoreHostMount[] hostMounts = datastore.getHost(); if (hostMounts != null) { for (DatastoreHostMount hostMount : hostMounts) { HostSystem host = vcenterAPI.lookupManagedEntity(hostMount.key); if (host != null) { hosts.add(host); } } } return hosts; } /** * Finds the file system containing the datastore. * * @param project * the project. * @param datacenterId * the datacenter name. * @param datastoreName * the datastore name. * @return the file system containing the datastore. */ public FileShareRestRep findFileSystemWithDatastore(URI project, URI datacenterId, String datastoreName) { return execute(new FindFilesystemWithDatastore(project, vcenterId, datacenterId, datastoreName)); } /** * Refreshes storage for the cluster or host. * * @param host * the host to refresh. * @param cluster * the cluster (may be null). */ public void refreshStorage(HostSystem host, ClusterComputeResource cluster) { if (cluster != null) { refreshStorage(cluster); } else { refreshStorage(host); } } /** * Refreshes the storage for all hosts in the cluster. * * @param cluster * the cluster to refresh. */ public void refreshStorage(ClusterComputeResource cluster) { List<HostSystem> hosts = Lists.newArrayList(cluster.getHosts()); refreshStorage(hosts); } /** * Refreshes the storage for the given host. * * @param host * the host to refresh. */ public void refreshStorage(HostSystem host) { List<HostSystem> hosts = Lists.newArrayList(host); refreshStorage(hosts); } /** * Refreshes the storage for a given list of hosts. * * @param hosts * the hosts to refresh; */ public void refreshStorage(List<HostSystem> hosts) { if (!hosts.isEmpty()) { execute(new RefreshStorage(hosts)); } } /** * Refreshes the storage for all hosts associated with the datastore. * * @param datastore * the datastore. */ public void refreshStorage(Datastore datastore) { List<HostSystem> hosts = VMwareUtils.getHostsForDatastore(vcenterAPI, datastore); refreshStorage(hosts); } /** * Finds the SCSI disk on the host system that matches the volume. * * @param host * the host system. * @param volume * the volume to find. * @return the disk for the volume. */ public HostScsiDisk findScsiDisk(HostSystem host, ClusterComputeResource cluster, BlockObjectRestRep volume) { return findScsiDisk(host, cluster, volume, false); } /** * Finds the SCSI disk on the host system that matches the volume. * * @param host * the host system. * @param volume * the volume to find. * @param availableDiskOnly * if true, only find available disk for VMFS. if false, find disk even if it's not available for VMFS. * @return the disk for the volume. */ public HostScsiDisk findScsiDisk(HostSystem host, ClusterComputeResource cluster, BlockObjectRestRep volume, boolean availableDiskOnly) { return findScsiDisk(host, cluster, volume, availableDiskOnly, true); } /** * Finds the SCSI disk on the host system that matches the volume. * * @param host * the host system * @param cluster * if specified, find disk on all hosts in the cluster * @param volume * the volume to find * @param availableDiskOnly * if true, only find available disk for VMFS. if false, find disk even if it's not available for VMFS. * @param throwIfNotFound * throw exception if the lun is not found. (defaults to true) * @return the disk for the volume */ public HostScsiDisk findScsiDisk(HostSystem host, ClusterComputeResource cluster, BlockObjectRestRep volume, boolean availableDiskOnly, boolean throwIfNotFound) { // Ensure that the volume has a WWN set or we won't be able to find the disk if (StringUtils.isBlank(volume.getWwn())) { String volumeId = ResourceUtils.stringId(volume); String volumeName = ResourceUtils.name(volume); ExecutionUtils.fail("failTask.VMwareSupport.findLun", new Object[] { volumeId }, new Object[] { volumeName }); } HostScsiDisk disk = execute(new FindHostScsiDiskForLun(host, volume, availableDiskOnly, throwIfNotFound)); // Find the volume on all other hosts in the cluster if (cluster != null) { HostSystem[] hosts = cluster.getHosts(); if (hosts == null) { throw new IllegalStateException("Cluster '" + cluster.getName() + "' contains no hosts"); } Map<HostSystem, HostScsiDisk> disks = Maps.newHashMap(); disks.put(host, disk); for (HostSystem otherHost : hosts) { if (StringUtils.equals(host.getName(), otherHost.getName())) { continue; } if (VMwareSupport.isHostConnected(otherHost)) { HostScsiDisk otherDisk = execute(new FindHostScsiDiskForLun(otherHost, volume, availableDiskOnly, throwIfNotFound)); disks.put(otherHost, otherDisk); } } } return disk; } /** * Returns true if the host is in a connected state * * @param host the host to check * @return true if host is connected, otherwise returns false */ public static boolean isHostConnected(HostSystem host) { HostRuntimeInfo runtime = (host != null) ? host.getRuntime() : null; HostSystemConnectionState connectionState = (runtime != null) ? runtime .getConnectionState() : null; return connectionState == HostSystemConnectionState.connected; } /** * Adds a tag associating the volumes to the datastore. * * @param volumes * the volumes. * @param datastoreName * the datastore name. */ public void addVmfsDatastoreTag(Collection<BlockObjectRestRep> volumes, URI hostOrClusterId, String datastoreName) { for (BlockObjectRestRep volume : volumes) { addVmfsDatastoreTag(volume, hostOrClusterId, datastoreName); } } /** * Adds a tag to the volume associating it with a datastore. * * @param volume * the volume to tag. * @param datastoreName * the name of the datastore to associate. */ public void addVmfsDatastoreTag(BlockObjectRestRep volume, URI hostOrClusterId, String datastoreName) { execute(new SetBlockVolumeMachineTag(volume.getId(), KnownMachineTags.getVMFSDatastoreTagName(hostOrClusterId), datastoreName)); addRollback(new RemoveBlockVolumeMachineTag(volume.getId(), KnownMachineTags.getVMFSDatastoreTagName(hostOrClusterId))); addAffectedResource(volume); } /** * Removes the VMFS datastore tag from the volumes. * * @param volumes * the volumes to remove the tag from. */ public void removeVmfsDatastoreTag(Collection<? extends BlockObjectRestRep> volumes, URI hostOrClusterId) { for (BlockObjectRestRep volume : volumes) { removeVmfsDatastoreTag(volume, hostOrClusterId); } } /** * Removes a datastore tag from the given volume. * * @param volume * the volume to remove the tag from. */ public void removeVmfsDatastoreTag(BlockObjectRestRep volume, URI hostOrClusterId) { execute(new RemoveBlockVolumeMachineTag(volume.getId(), KnownMachineTags.getVMFSDatastoreTagName(hostOrClusterId))); addAffectedResource(volume); } /** * Tags the fileshare with the NFS datastore information. * * @param fileSystem * @param export * @param datacenterId * @param datastoreName */ public void addNfsDatastoreTag(FileShareRestRep fileSystem, FileSystemExportParam export, URI datacenterId, String datastoreName) { execute(new TagDatastoreOnFilesystem(fileSystem.getId(), vcenterId, datacenterId, datastoreName, export.getMountPoint())); addRollback(new UntagDatastoreOnFilesystem(fileSystem.getId(), vcenterId, datacenterId, datastoreName)); addAffectedResource(fileSystem); } /** * Removes the NFS datastore tag from the filesystem. * * @param fileSystem * @param datacenterId * @param datastoreName */ public void removeNfsDatastoreTag(FileShareRestRep fileSystem, URI datacenterId, String datastoreName) { execute(new UntagDatastoreOnFilesystem(fileSystem.getId(), vcenterId, datacenterId, datastoreName)); addAffectedResource(fileSystem); } /** * Finds the volumes backing the datastore. * * @param host * the actual host system * @param hostId * host ID * @param datastore * the datastore. * @return the volumes backing the host system. */ public List<VolumeRestRep> findVolumesBackingDatastore(HostSystem host, URI hostId, Datastore datastore) { Set<String> luns = execute(new FindLunsBackingDatastore(host, datastore)); List<VolumeRestRep> volumes = Lists.newArrayList(); for (String lun : luns) { VolumeRestRep volume = execute(new GetBlockVolumeByWWN(lun)); if (volume != null) { // VBDU: Check to ensure the correct datastore tag is in the volume returned String tagValue = KnownMachineTags.getBlockVolumeVMFSDatastore(hostId, volume); if (tagValue == null || !tagValue.equalsIgnoreCase(datastore.getName())) { logError("vmware.support.datastore.doesntmatchvolume", volume.getName(), datastore.getName()); return null; } volumes.add(volume); } else { logError("vmware.support.datastore.volumenotfound", datastore.getName()); // Don't return any volume objects to quickly report there's an issue to the caller. return null; } } return volumes; } /** * Checks the exception cause for VMware specific faults. * * @param e * the execution exception. * @return an execution exception to be rethrown. */ public ExecutionException handleError(ExecutionException e) { // find the root cause of this exception Throwable cause = e.getCause(); if (cause instanceof VMWareException) { cause = ((VMWareException) cause).getCause(); } // log the error and return a new exception that uses the fault // message from the VMWare MethodFault as the main message. if (cause instanceof MethodFault) { String faultMessage = VMwareUtils.getFaultMessage((MethodFault) cause); logError(cause, "vmware.support.method.fault", cause.getClass(), faultMessage); return new ExecutionException(cause); } return e; } /** * Unmount the datastore from the host or hosts in the cluster * * @param host host to unmount the datastore from. * @param cluster cluster to unmount the datastore from. if not null, use cluster's hosts * @param datastore the datastore to unmount */ public void unmountVmfsDatastore(HostSystem host, ClusterComputeResource cluster, final Datastore datastore) { setStorageIOControl(datastore, false); List<HostSystem> hosts = cluster == null ? Lists.newArrayList(host) : Lists.newArrayList(cluster.getHosts()); executeOnHosts(hosts, new HostSystemCallback() { @Override public void exec(HostSystem host) { if (VMwareUtils.isDatastoreMountedOnHost(datastore, host)) { unmountVmfsDatastore(host, datastore); } } }); } /** * Detach the volume from the host or hosts in the cluster. Detach needs to be called on every host * that is part of a cluster. Passing in a cluster value signifies that we're dealing with a shared * export, so iterate through all the host that is part of the cluster and explicitly detach the lun * on every host. * * @param host host to detach the volume. * @param cluster cluster to detach the volume. if not null, use the cluster's hosts * @param volume the volume to detach */ public void detachLuns(HostSystem host, ClusterComputeResource cluster, BlockObjectRestRep volume) { // cluster is only set during shared exports. List<HostSystem> hosts = cluster == null ? Lists.newArrayList(host) : Lists.newArrayList(cluster.getHosts()); for (HostSystem hs : hosts) { // Get disk for every host before detaching to have them in sync. // Pass in null cluster since we only want to find the specific disk to each host // as they are processed. Passing in a cluster value forces find disk on all host // that are part of the cluster. Once a host has detach the storage, find disk fails // so we can't find disk on all host as we iterate through all the host. final HostScsiDisk disk = findScsiDisk(hs, null, volume); executeOnHosts(Lists.newArrayList(hs), new HostSystemCallback() { @Override public void exec(HostSystem host) { detachLuns(host, Collections.singletonList(disk)); } }); } } }