/*
* Copyright (c) 2012-2015 iWave Software LLC
* All Rights Reserved
*/
package com.emc.sa.asset.providers;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import com.emc.sa.machinetags.KnownMachineTags;
import com.emc.sa.service.vipr.block.BlockStorageUtils;
import com.emc.sa.util.ResourceType;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.Volume.PersonalityTypes;
import com.emc.storageos.model.DiscoveredSystemObjectRestRep;
import com.emc.storageos.model.application.VolumeGroupRestRep;
import com.emc.storageos.model.block.BlockConsistencyGroupRestRep;
import com.emc.storageos.model.block.BlockObjectRestRep;
import com.emc.storageos.model.block.BlockSnapshotRestRep;
import com.emc.storageos.model.block.VolumeRestRep;
import com.emc.storageos.model.block.VolumeRestRep.RecoverPointRestRep;
import com.emc.storageos.model.block.export.ExportBlockParam;
import com.emc.storageos.model.block.export.ExportGroupRestRep;
import com.emc.storageos.model.host.HostRestRep;
import com.emc.storageos.model.systems.StorageSystemConnectivityRestRep;
import com.emc.storageos.model.systems.StorageSystemRestRep;
import com.emc.storageos.model.vpool.BlockVirtualPoolRestRep;
import com.emc.vipr.client.ViPRCoreClient;
import com.emc.vipr.client.core.util.VirtualPoolUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class BlockProviderUtils {
public static final String VPLEX_DISTRIBUTED = "VPLEX_DISTRIBUTED";
public static List<? extends BlockObjectRestRep> getBlockResources(ViPRCoreClient viprClient, URI tenantId, URI hostOrClusterId,
boolean onlyMounted) {
List<URI> hostIds = buildHostIdsList(viprClient, hostOrClusterId, onlyMounted);
List<BlockObjectRestRep> volumes = Lists.newArrayList();
for (BlockObjectRestRep volume : getExportedBlockResources(viprClient, tenantId, hostOrClusterId)) {
boolean isMounted = isMounted(hostIds, volume);
if (onlyMounted && isMounted) {
volumes.add(volume);
}
else if (!onlyMounted && !isMounted) {
volumes.add(volume);
}
}
return volumes;
}
public static List<VolumeRestRep> getBlockVolumes(ViPRCoreClient viprClient, URI tenantId, URI hostOrClusterId,
boolean onlyMounted) {
List<URI> hostIds = buildHostIdsList(viprClient, hostOrClusterId, onlyMounted);
List<VolumeRestRep> volumes = Lists.newArrayList();
for (VolumeRestRep volume : getExportedBlockVolumes(viprClient, tenantId, hostOrClusterId)) {
boolean isMounted = isMounted(hostIds, volume);
if (onlyMounted && isMounted) {
volumes.add(volume);
}
else if (!onlyMounted && !isMounted) {
volumes.add(volume);
}
}
return volumes;
}
/**
* Method to return all volumes associated with a specific datastore
*
* @param viprClient
* @param tenantId
* @param hostOrClusterId
* @param datastore name
*
* @return list of volumes associated with specified datastore
*/
public static List<VolumeRestRep> getBlockVolumesForDatastore(ViPRCoreClient viprClient, URI tenantId, URI hostOrClusterId,
String datastore) {
List<URI> hostIds = buildHostIdsList(viprClient, hostOrClusterId, true);
List<VolumeRestRep> volumes = Lists.newArrayList();
for (VolumeRestRep volume : getExportedBlockVolumes(viprClient, tenantId, hostOrClusterId)) {
for (URI hostId : hostIds) {
String ds = KnownMachineTags.getBlockVolumeVMFSDatastore(hostId, volume);
if (StringUtils.isNotBlank(ds) && ds.equals(datastore)) {
volumes.add(volume);
}
}
}
return volumes;
}
protected static List<URI> buildHostIdsList(ViPRCoreClient viprClient, URI hostOrClusterId, boolean onlyMounted) {
List<URI> hostIds = Lists.newArrayList();
if (onlyMounted) {
// we're looking for volumes mounted on this host/cluster
hostIds.add(hostOrClusterId);
}
else {
// we're looking for volumes that are not mounted on this host/cluster
hostIds.addAll(HostProvider.getHostIds(viprClient, hostOrClusterId));
// Add Cluster ID to the end of the list of host ids
URI clusterId = getClusterId(viprClient, hostOrClusterId);
if (clusterId != null) {
hostIds.add(clusterId);
}
}
return hostIds;
}
protected static URI getClusterId(ViPRCoreClient viprClient, URI hostOrClusterId) {
if (BlockStorageUtils.isCluster(hostOrClusterId)) {
// if the id is a cluster id we can just add it
return hostOrClusterId;
}
else {
// if the id is not a cluster id we need to get the cluster id from the host and add that
HostRestRep host = viprClient.hosts().get(hostOrClusterId);
if (host.getCluster() != null) {
return host.getCluster().getId();
}
}
return null;
}
public static List<? extends BlockObjectRestRep> getExportedBlockResources(ViPRCoreClient client, URI tenantId, URI hostOrClusterId) {
List<ExportGroupRestRep> exports = getExportsForHostOrCluster(client, tenantId, hostOrClusterId);
Set<URI> volumeIds = getExportedResourceIds(exports, ResourceType.VOLUME);
Set<URI> snapshotIds = getExportedResourceIds(exports, ResourceType.BLOCK_SNAPSHOT);
List<BlockObjectRestRep> resources = new ArrayList<>();
resources.addAll(client.blockVolumes().getByIds(volumeIds));
resources.addAll(client.blockSnapshots().getByIds(snapshotIds));
return resources;
}
public static List<VolumeRestRep> getExportedBlockVolumes(ViPRCoreClient client, URI tenantId, URI hostOrClusterId) {
List<ExportGroupRestRep> exports = getExportsForHostOrCluster(client, tenantId, hostOrClusterId);
Set<URI> volumeIds = getExportedResourceIds(exports, ResourceType.VOLUME);
return client.blockVolumes().getByIds(volumeIds);
}
public static List<ExportGroupRestRep> getExportsForHostOrCluster(ViPRCoreClient client, URI tenantId, URI hostOrClusterId) {
if (BlockStorageUtils.isHost(hostOrClusterId)) {
// Limit results to host exports for this host (there may be cluster exports as well)
List<ExportGroupRestRep> exports = client.blockExports().findContainingHost(hostOrClusterId, null, null);
return new ArrayList<ExportGroupRestRep>(BlockStorageUtils.filterExportsByType(exports, hostOrClusterId));
} else {
return client.blockExports().findByCluster(hostOrClusterId, null, null);
}
}
public static Set<URI> getExportedResourceIds(Collection<ExportGroupRestRep> exports, ResourceType type) {
Set<URI> ids = new HashSet<>();
for (ExportGroupRestRep export : exports) {
// export volumes can be volumes or snapshots
for (ExportBlockParam resource : export.getVolumes()) {
if (ResourceType.isType(type, resource.getId())) {
ids.add(resource.getId());
}
}
}
return ids;
}
public static boolean isMounted(Collection<URI> hostIds, BlockObjectRestRep volume) {
for (URI hostId : hostIds) {
if (isMounted(hostId, volume)) {
return true;
}
}
return false;
}
public static boolean isMounted(URI hostId, BlockObjectRestRep volume) {
String mountPoint = KnownMachineTags.getBlockVolumeMountPoint(hostId, volume);
if (StringUtils.isNotBlank(mountPoint)) {
return true;
}
String datastore = KnownMachineTags.getBlockVolumeVMFSDatastore(hostId, volume);
return StringUtils.isNotBlank(datastore);
}
public static boolean isLocalMirrorSupported(BlockVirtualPoolRestRep virtualPool) {
boolean supported = (virtualPool.getProtection() != null) &&
(virtualPool.getProtection().getContinuousCopies() != null) &&
(virtualPool.getProtection().getContinuousCopies().getMaxMirrors() > 0);
if (virtualPool.getHighAvailability() != null &&
VirtualPoolUtils.isVplexDistributed(virtualPool.getHighAvailability().getType()) &&
virtualPool.getProtection() != null &&
virtualPool.getProtection().getContinuousCopies() != null) {
supported = ((virtualPool.getProtection().getContinuousCopies().getMaxMirrors() > 0 &&
virtualPool.getProtection().getContinuousCopies().getVpool() != null) ||
(virtualPool.getProtection().getContinuousCopies().getHaMaxMirrors() != null &&
virtualPool.getProtection().getContinuousCopies().getHaMaxMirrors() > 0 &&
virtualPool.getProtection().getContinuousCopies().getHaVpool() != null));
}
return supported;
}
public static boolean isLocalSnapshotSupported(BlockVirtualPoolRestRep virtualPool) {
if (virtualPool == null) {
return false;
}
return (virtualPool.getProtection() != null) &&
(virtualPool.getProtection().getSnapshots() != null) &&
(virtualPool.getProtection().getSnapshots().getMaxSnapshots() > 0);
}
public static boolean isRemoteSnapshotSupported(VolumeRestRep volume) {
return getVolumeRPRep(volume) != null;
}
public static boolean isMetadataVolume(VolumeRestRep volume) {
PersonalityTypes personality = getVolumePersonality(volume);
return personality != null && PersonalityTypes.METADATA.equals(personality);
}
public static boolean isRPSourceVolume(VolumeRestRep volume) {
PersonalityTypes personality = getVolumePersonality(volume);
return personality != null && PersonalityTypes.SOURCE.equals(personality);
}
public static boolean isRPTargetVolume(VolumeRestRep volume) {
PersonalityTypes personality = getVolumePersonality(volume);
return personality != null && PersonalityTypes.TARGET.equals(personality);
}
public static boolean isSnapshotSessionSupportedForVolume(VolumeRestRep volume) {
return ((volume.getSupportsSnapshotSessions() != null) && volume.getSupportsSnapshotSessions());
}
public static boolean isSnapshotSessionSupportedForCG(BlockConsistencyGroupRestRep cg) {
return ((cg.getSupportsSnapshotSessions() != null) && cg.getSupportsSnapshotSessions());
}
public static boolean isSnapshotRPBookmark(BlockSnapshotRestRep snapshot) {
return snapshot.getTechnologyType() != null && snapshot.getTechnologyType().equals(BlockSnapshot.TechnologyType.RP.name());
}
public static RecoverPointRestRep getVolumeRPRep(VolumeRestRep volume) {
if (volume.getProtection() != null &&
volume.getProtection().getRpRep() != null) {
return volume.getProtection().getRpRep();
}
return null;
}
public static PersonalityTypes getVolumePersonality(VolumeRestRep volume) {
RecoverPointRestRep rp = getVolumeRPRep(volume);
if (rp != null && rp.getPersonality() != null) {
return PersonalityTypes.valueOf(rp.getPersonality());
}
return null;
}
public static boolean isVpoolProtectedByVarray(BlockVirtualPoolRestRep vpool, URI targetVArray) {
return targetVArray != null && isVplexDistributedVPool(vpool) && targetVArray.equals(getHAVarrayId(vpool));
}
public static boolean isVplexDistributedVPool(BlockVirtualPoolRestRep vpool) {
return vpool != null && VPLEX_DISTRIBUTED.equalsIgnoreCase(getHAType(vpool));
}
public static boolean isSRDFTargetVolume(BlockObjectRestRep blockObj) {
if (blockObj instanceof VolumeRestRep) {
VolumeRestRep volume = (VolumeRestRep) blockObj;
return volume.getProtection() != null &&
volume.getProtection().getSrdfRep() != null &&
volume.getProtection().getSrdfRep().getPersonality().equals(PersonalityTypes.TARGET.toString());
}
return false;
}
public static URI getHAVarrayId(BlockVirtualPoolRestRep volumeVpool) {
if (volumeVpool != null &&
volumeVpool.getHighAvailability() != null &&
volumeVpool.getHighAvailability().getHaVirtualArrayVirtualPool() != null &&
volumeVpool.getHighAvailability().getHaVirtualArrayVirtualPool().getVirtualArray() != null) {
return volumeVpool.getHighAvailability().getHaVirtualArrayVirtualPool().getVirtualArray();
}
return null;
}
public static String getHAType(BlockVirtualPoolRestRep volumeVpool) {
if (volumeVpool != null &&
volumeVpool.getHighAvailability() != null &&
volumeVpool.getHighAvailability().getType() != null) {
return volumeVpool.getHighAvailability().getType();
}
return StringUtils.EMPTY;
}
public static boolean isVplex(StorageSystemRestRep storageSystem) {
return StringUtils.equals(storageSystem.getSystemType(), "vplex");
}
public static boolean isVplex(StorageSystemConnectivityRestRep connectivity) {
for (String connectionType : connectivity.getConnectionTypes()) {
if (StringUtils.equals(connectionType, "vplex")) {
return true;
}
}
return false;
}
public static boolean isVnxBlock(StorageSystemRestRep storageSystem) {
return StringUtils.equals(storageSystem.getSystemType(), "vnxblock");
}
public static boolean isVmax(StorageSystemRestRep storageSystem) {
return StringUtils.equals(storageSystem.getSystemType(), "vmax");
}
public static boolean isRegistered(DiscoveredSystemObjectRestRep system) {
return (system != null) && "REGISTERED".equals(system.getRegistrationStatus());
}
public static Map<URI, String> volumeNameMap(List<VolumeRestRep> volumes) {
Map<URI, String> volumeNameMap = Maps.newHashMap();
for (VolumeRestRep volume : volumes) {
volumeNameMap.put(volume.getId(), volume.getName());
}
return volumeNameMap;
}
public static boolean isSupportedVPool(BlockVirtualPoolRestRep vpool) {
return vpool != null && vpool.getMultiVolumeConsistent() != null && vpool.getMultiVolumeConsistent();
}
public static boolean isType(URI uri, String name) {
return uri.toString().startsWith("urn:storageos:" + name);
}
/**
* returns the list of application sub groups for an application
*
* @param viprClient
* @param applicationId
* @return
*/
public static Set<String> getApplicationReplicationGroupNames(ViPRCoreClient viprClient, URI applicationId) {
VolumeGroupRestRep application = viprClient.application().getApplication(applicationId);
Set<String> visibleGroups = new HashSet<String>();
Set<String> groupNames = application.getReplicationGroupNames();
for (String grp : groupNames) {
if (!isRPTargetReplicationGroup(grp)) {
visibleGroups.add(grp);
}
}
return visibleGroups;
}
/**
* returns true if the replication group is a RP Target replication group
*
* @param group
* @return
*/
public static boolean isRPTargetReplicationGroup(String group) {
if (group != null) {
String[] parts = StringUtils.split(group, '-');
if (parts.length > 1 && parts[parts.length - 1].equals("RPTARGET")) {
return true;
}
}
return false;
}
/**
* returns true if the volume is a RP source or target volume
*
* @param vol
* @return
*/
public static boolean isVolumeRP(VolumeRestRep vol) {
if (vol.getProtection() != null && vol.getProtection().getRpRep() != null) {
return true;
}
return false;
}
/**
* return true if the volume is a vplex volume
*
* @param vol
* @return
*/
public static boolean isVolumeVPLEX(VolumeRestRep vol) {
if (vol.getHaVolumes() != null && !vol.getHaVolumes().isEmpty()) {
return true;
}
return false;
}
}