/*
* Copyright (c) 2012-2015 iWave Software LLC
* All Rights Reserved
*/
package com.emc.sa.service.vipr.block;
import static com.emc.sa.service.ServiceParams.CONSISTENCY_GROUP;
import static com.emc.sa.service.ServiceParams.HLU;
import static com.emc.sa.service.ServiceParams.HOST;
import static com.emc.sa.service.ServiceParams.MAX_PATHS;
import static com.emc.sa.service.ServiceParams.MIN_PATHS;
import static com.emc.sa.service.ServiceParams.NAME;
import static com.emc.sa.service.ServiceParams.NUMBER_OF_VOLUMES;
import static com.emc.sa.service.ServiceParams.PATHS_PER_INITIATOR;
import static com.emc.sa.service.ServiceParams.PROJECT;
import static com.emc.sa.service.ServiceParams.SIZE_IN_GB;
import static com.emc.sa.service.ServiceParams.VIRTUAL_ARRAY;
import static com.emc.sa.service.ServiceParams.VIRTUAL_POOL;
import static com.emc.sa.service.vipr.ViPRExecutionUtils.addAffectedResource;
import static com.emc.sa.service.vipr.ViPRExecutionUtils.addAffectedResources;
import static com.emc.sa.service.vipr.ViPRExecutionUtils.addRollback;
import static com.emc.sa.service.vipr.ViPRExecutionUtils.execute;
import static com.emc.sa.util.ResourceType.BLOCK_SNAPSHOT;
import static com.emc.sa.util.ResourceType.VOLUME;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.emc.sa.engine.ExecutionContext;
import com.emc.sa.engine.ExecutionException;
import com.emc.sa.engine.ExecutionUtils;
import com.emc.sa.engine.bind.Param;
import com.emc.sa.machinetags.KnownMachineTags;
import com.emc.sa.machinetags.MachineTagUtils;
import com.emc.sa.service.vipr.ViPRExecutionUtils;
import com.emc.sa.service.vipr.application.tasks.GetBlockSnapshotSession;
import com.emc.sa.service.vipr.application.tasks.GetBlockSnapshotSessionList;
import com.emc.sa.service.vipr.application.tasks.GetBlockSnapshotSet;
import com.emc.sa.service.vipr.application.tasks.GetFullCopyList;
import com.emc.sa.service.vipr.block.tasks.AddClusterToExport;
import com.emc.sa.service.vipr.block.tasks.AddHostAndVolumeToExportNoWait;
import com.emc.sa.service.vipr.block.tasks.AddHostToExport;
import com.emc.sa.service.vipr.block.tasks.AddJournalCapacity;
import com.emc.sa.service.vipr.block.tasks.AddVolumesToConsistencyGroup;
import com.emc.sa.service.vipr.block.tasks.AddVolumesToExport;
import com.emc.sa.service.vipr.block.tasks.AdjustExportPaths;
import com.emc.sa.service.vipr.block.tasks.CreateBlockVolume;
import com.emc.sa.service.vipr.block.tasks.CreateBlockVolumeByName;
import com.emc.sa.service.vipr.block.tasks.CreateContinuousCopy;
import com.emc.sa.service.vipr.block.tasks.CreateExport;
import com.emc.sa.service.vipr.block.tasks.CreateExportNoWait;
import com.emc.sa.service.vipr.block.tasks.CreateFullCopy;
import com.emc.sa.service.vipr.block.tasks.CreateMultipleBlockVolumes;
import com.emc.sa.service.vipr.block.tasks.CreateSnapshotFullCopy;
import com.emc.sa.service.vipr.block.tasks.DeactivateBlockExport;
import com.emc.sa.service.vipr.block.tasks.DeactivateBlockSnapshot;
import com.emc.sa.service.vipr.block.tasks.DeactivateBlockSnapshotSession;
import com.emc.sa.service.vipr.block.tasks.DeactivateContinuousCopy;
import com.emc.sa.service.vipr.block.tasks.DeactivateVolume;
import com.emc.sa.service.vipr.block.tasks.DeactivateVolumes;
import com.emc.sa.service.vipr.block.tasks.DetachFullCopy;
import com.emc.sa.service.vipr.block.tasks.ExpandVolume;
import com.emc.sa.service.vipr.block.tasks.FindBlockVolumeHlus;
import com.emc.sa.service.vipr.block.tasks.FindExportByCluster;
import com.emc.sa.service.vipr.block.tasks.FindExportByHost;
import com.emc.sa.service.vipr.block.tasks.FindExportByName;
import com.emc.sa.service.vipr.block.tasks.FindExportsContainingCluster;
import com.emc.sa.service.vipr.block.tasks.FindExportsContainingHost;
import com.emc.sa.service.vipr.block.tasks.FindVirtualArrayInitiators;
import com.emc.sa.service.vipr.block.tasks.GetActiveContinuousCopiesForVolume;
import com.emc.sa.service.vipr.block.tasks.GetActiveFullCopiesForVolume;
import com.emc.sa.service.vipr.block.tasks.GetActiveSnapshotSessionsForVolume;
import com.emc.sa.service.vipr.block.tasks.GetActiveSnapshotsForVolume;
import com.emc.sa.service.vipr.block.tasks.GetBlockConsistencyGroup;
import com.emc.sa.service.vipr.block.tasks.GetBlockContinuousCopies;
import com.emc.sa.service.vipr.block.tasks.GetBlockExport;
import com.emc.sa.service.vipr.block.tasks.GetBlockExports;
import com.emc.sa.service.vipr.block.tasks.GetBlockResource;
import com.emc.sa.service.vipr.block.tasks.GetBlockSnapshot;
import com.emc.sa.service.vipr.block.tasks.GetBlockSnapshots;
import com.emc.sa.service.vipr.block.tasks.GetBlockVolume;
import com.emc.sa.service.vipr.block.tasks.GetBlockVolumeByWWN;
import com.emc.sa.service.vipr.block.tasks.GetBlockVolumes;
import com.emc.sa.service.vipr.block.tasks.GetExportsForBlockObject;
import com.emc.sa.service.vipr.block.tasks.GetProject;
import com.emc.sa.service.vipr.block.tasks.GetTenant;
import com.emc.sa.service.vipr.block.tasks.GetVolumeByName;
import com.emc.sa.service.vipr.block.tasks.PauseContinuousCopy;
import com.emc.sa.service.vipr.block.tasks.RemoveBlockResourcesFromExport;
import com.emc.sa.service.vipr.block.tasks.RestoreFromFullCopy;
import com.emc.sa.service.vipr.block.tasks.ResynchronizeBlockSnapshot;
import com.emc.sa.service.vipr.block.tasks.ResynchronizeFullCopy;
import com.emc.sa.service.vipr.block.tasks.StartBlockSnapshot;
import com.emc.sa.service.vipr.block.tasks.StartFullCopy;
import com.emc.sa.service.vipr.block.tasks.SwapCGContinuousCopies;
import com.emc.sa.service.vipr.block.tasks.SwapContinuousCopies;
import com.emc.sa.service.vipr.block.tasks.VerifyVolumeDependencies;
import com.emc.sa.service.vipr.tasks.GetActionableEvents;
import com.emc.sa.service.vipr.tasks.GetCluster;
import com.emc.sa.service.vipr.tasks.GetHost;
import com.emc.sa.service.vipr.tasks.GetStorageSystem;
import com.emc.sa.service.vipr.tasks.GetVirtualArray;
import com.emc.sa.util.DiskSizeConversionUtils;
import com.emc.sa.util.ResourceType;
import com.emc.storageos.coordinator.client.model.Constants;
import com.emc.storageos.db.client.model.BlockConsistencyGroup;
import com.emc.storageos.db.client.model.Cluster;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.DiscoveredDataObject;
import com.emc.storageos.db.client.model.Host;
import com.emc.storageos.db.client.model.HostInterface.Protocol;
import com.emc.storageos.db.client.model.Initiator;
import com.emc.storageos.db.client.model.StorageProvider;
import com.emc.storageos.db.client.model.Volume.ReplicationState;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.model.NamedRelatedResourceRep;
import com.emc.storageos.model.RelatedResourceRep;
import com.emc.storageos.model.VirtualArrayRelatedResourceRep;
import com.emc.storageos.model.block.BlockConsistencyGroupRestRep;
import com.emc.storageos.model.block.BlockMirrorRestRep;
import com.emc.storageos.model.block.BlockObjectRestRep;
import com.emc.storageos.model.block.BlockSnapshotRestRep;
import com.emc.storageos.model.block.BlockSnapshotSessionRestRep;
import com.emc.storageos.model.block.NamedVolumesList;
import com.emc.storageos.model.block.VolumeDeleteTypeEnum;
import com.emc.storageos.model.block.VolumeRestRep;
import com.emc.storageos.model.block.VolumeRestRep.FullCopyRestRep;
import com.emc.storageos.model.block.export.ExportBlockParam;
import com.emc.storageos.model.block.export.ExportGroupRestRep;
import com.emc.storageos.model.block.export.ITLRestRep;
import com.emc.storageos.model.block.export.InitiatorPathParam;
import com.emc.storageos.model.project.ProjectRestRep;
import com.emc.storageos.model.systems.StorageSystemRestRep;
import com.emc.storageos.model.tenant.TenantOrgRestRep;
import com.emc.storageos.model.varray.VirtualArrayRestRep;
import com.emc.storageos.svcs.errorhandling.resources.ServiceCode;
import com.emc.vipr.client.Task;
import com.emc.vipr.client.Tasks;
import com.emc.vipr.client.ViPRCoreClient;
import com.emc.vipr.client.core.filters.BlockVolumeBootVolumeFilter;
import com.emc.vipr.client.core.filters.ExportClusterFilter;
import com.emc.vipr.client.core.filters.ExportHostFilter;
import com.emc.vipr.client.core.util.ResourceUtils;
import com.emc.vipr.client.exceptions.ServiceErrorException;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import com.google.common.collect.Table.Cell;
public class BlockStorageUtils {
private static final Logger log = Logger.getLogger(BlockStorageUtils.class);
public static final String COPY_NATIVE = "native";
public static final String COPY_RP = "rp";
public static final String COPY_SRDF = "srdf";
public static final String UNDERSCORE = "_";
public static boolean isHost(URI id) {
return StringUtils.startsWith(id.toString(), "urn:storageos:Host");
}
public static boolean isCluster(URI id) {
return StringUtils.startsWith(id.toString(), "urn:storageos:Cluster");
}
public static Host getHost(URI hostId) {
if (NullColumnValueGetter.isNullURI(hostId)) {
return null;
}
return execute(new GetHost(hostId));
}
public static void checkEvents(DataObject resource) {
execute(new GetActionableEvents(resource));
}
public static Cluster getCluster(URI clusterId) {
if (NullColumnValueGetter.isNullURI(clusterId)) {
return null;
}
return execute(new GetCluster(clusterId));
}
public static String getHostOrClusterId(URI hostOrClusterId) {
String id = null;
if (hostOrClusterId != null) {
id = hostOrClusterId.toString();
if (BlockStorageUtils.isHost(hostOrClusterId)) {
Host host = BlockStorageUtils.getHost(hostOrClusterId);
if (host.getCluster() != null) {
Cluster cluster = BlockStorageUtils.getCluster(host.getCluster());
if (cluster != null) {
id = cluster.getId().toString();
}
}
}
}
return id;
}
public static BlockObjectRestRep getVolume(URI volumeId) {
return getBlockResource(volumeId);
}
public static StorageSystemRestRep getStorageSystem(URI storageSystemId) {
return execute(new GetStorageSystem(storageSystemId));
}
public static BlockSnapshotRestRep getSnapshot(URI snapshotId) {
return execute(new GetBlockSnapshot(snapshotId));
}
public static BlockObjectRestRep getBlockResource(URI resourceId) {
return execute(new GetBlockResource(resourceId));
}
public static BlockConsistencyGroupRestRep getBlockConsistencyGroup(URI resourceId) {
return execute(new GetBlockConsistencyGroup(resourceId));
}
public static VirtualArrayRestRep getVirtualArray(URI id) {
return execute(new GetVirtualArray(id));
}
private static List<VolumeRestRep> getVolumes(List<URI> volumeIds) {
return execute(new GetBlockVolumes(volumeIds));
}
private static List<BlockSnapshotRestRep> getBlockSnapshots(List<URI> uris) {
return execute(new GetBlockSnapshots(uris));
}
private static List<BlockMirrorRestRep> getBlockContinuousCopies(List<URI> uris, URI parentId) {
return execute(new GetBlockContinuousCopies(uris, parentId));
}
/**
* Verify that list of volume doesn't contain any dependencies (snapshot, full copies, continuous copy)
*
* @param volumeIds of the volumes to validate dependencies
*/
public static void verifyVolumeDependencies(List<URI> volumeIds, URI projectId) {
List<URI> allBlockResources = Lists.newArrayList(volumeIds);
for (URI volumeId : volumeIds) {
BlockObjectRestRep volume = getVolume(volumeId);
allBlockResources.addAll(getSrdfTargetVolumes(volume));
allBlockResources.addAll(getRpTargetVolumes(volume));
}
execute(new VerifyVolumeDependencies(allBlockResources, projectId));
}
/**
* Return true of false if a given volume is a VMFS datastore.
*
* @param blockObject to validate
* @return true or false if the volume is a VMFS Datastore
*/
public static boolean isVolumeVMFSDatastore(BlockObjectRestRep blockObject) {
if (blockObject != null) {
Set<String> volumeTags = blockObject.getTags();
if (volumeTags != null) {
Map<String, String> parsedTags = MachineTagUtils.parseMachineTags(volumeTags);
for (String tag : parsedTags.keySet()) {
if (tag != null && tag.startsWith(KnownMachineTags.getVmfsDatastoreTagName())) {
return true;
}
}
}
}
return false;
}
/**
* Return true of false if a given volume is a boot volume for an OS.
*
* @param blockObject to validate
* @return true or false if the volume is a boot volume
*/
public static boolean isVolumeBootVolume(BlockObjectRestRep blockObject) {
return BlockVolumeBootVolumeFilter.isVolumeBootVolume(blockObject);
}
/**
* Return true of false if a given volume is mounted.
*
* @param blockObject to validate
* @return true or false if the volume is mounted
*/
public static boolean isVolumeMounted(BlockObjectRestRep blockObject) {
if (blockObject != null) {
Set<String> volumeTags = blockObject.getTags();
if (volumeTags != null) {
Map<String, String> parsedTags = MachineTagUtils.parseMachineTags(volumeTags);
for (String tag : parsedTags.keySet()) {
if (tag != null && tag.startsWith(KnownMachineTags.getHostMountPointTagName())) {
return true;
}
}
}
}
return false;
}
/**
* Retrieve a list of block resources based on the resource ids provided. This will gather
* the appropriate resources based on the resource type of the ids provided.
*
* @param resourceIds of the resources to retrieve.
* @return list of block resources
*/
public static List<BlockObjectRestRep> getBlockResources(List<URI> resourceIds) {
return getBlockResources(resourceIds, null);
}
/**
* Retrieve a list of block resources based on the resource ids provided. This will gather
* the appropriate resources based on the resource type of the ids provided.
*
* @param resourceIds of the resources to retrieve.
* @param parentId of a continuous copy. This will be null for all other resource types.
* @return list of block resources
*/
public static List<BlockObjectRestRep> getBlockResources(List<URI> resourceIds, URI parentId) {
List<BlockObjectRestRep> blockResources = Lists.newArrayList();
List<URI> blockVolumes = new ArrayList<URI>();
List<URI> blockSnapshots = new ArrayList<URI>();
List<URI> blockContinuousCopies = new ArrayList<URI>();
for (URI resourceId : resourceIds) {
ResourceType volumeType = ResourceType.fromResourceId(resourceId.toString());
switch (volumeType) {
case VOLUME:
blockVolumes.add(resourceId);
break;
case BLOCK_SNAPSHOT:
blockSnapshots.add(resourceId);
break;
case BLOCK_CONTINUOUS_COPY:
blockContinuousCopies.add(resourceId);
break;
default:
break;
}
}
if (!blockVolumes.isEmpty()) {
blockResources.addAll(getVolumes(blockVolumes));
}
if (!blockSnapshots.isEmpty()) {
blockResources.addAll(getBlockSnapshots(blockSnapshots));
}
if (!blockContinuousCopies.isEmpty()) {
blockResources.addAll(getBlockContinuousCopies(blockContinuousCopies, parentId));
}
return blockResources;
}
public static VolumeRestRep getVolumeByWWN(String volumeWWN) {
return execute(new GetBlockVolumeByWWN(volumeWWN));
}
public static List<VolumeRestRep> getVolumeByName(String name) {
return execute(new GetVolumeByName(name));
}
public static ProjectRestRep getProject(URI projectId) {
return execute(new GetProject(projectId));
}
public static TenantOrgRestRep getTenant(URI tenantId) {
return execute(new GetTenant(tenantId));
}
public static ExportGroupRestRep getExport(URI exportId) {
return execute(new GetBlockExport(exportId));
}
public static List<ExportGroupRestRep> getExports(List<URI> exportIds) {
return execute(new GetBlockExports(exportIds));
}
public static ExportGroupRestRep findExportByHost(Host host, URI projectId, URI varrayId, URI volume) {
return execute(new FindExportByHost(host.getId(), projectId, varrayId, volume));
}
public static ExportGroupRestRep findExportByCluster(Cluster cluster, URI projectId, URI varrayId, URI volume) {
return execute(new FindExportByCluster(cluster.getId(), projectId, varrayId, volume));
}
public static List<ExportGroupRestRep> findExportsContainingCluster(URI cluster, URI projectId, URI varrayId) {
return execute(new FindExportsContainingCluster(cluster, projectId, varrayId));
}
public static List<ExportGroupRestRep> findExportsContainingHost(URI host, URI projectId, URI varrayId) {
return execute(new FindExportsContainingHost(host, projectId, varrayId));
}
public static ExportGroupRestRep findExportsByName(String name, URI projectId, URI varrayId) {
return execute(new FindExportByName(name, projectId, varrayId));
}
public static URI adjustExportPaths(URI vArray, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator,
URI storageSystemId, URI id, List<InitiatorPathParam> addedPaths, List<InitiatorPathParam> removedPaths,
boolean suspendWait) {
Task<ExportGroupRestRep> task = execute(new AdjustExportPaths(vArray, minPaths, maxPaths, pathsPerInitiator,
storageSystemId, id, addedPaths, removedPaths, suspendWait));
URI exportId = task.getResourceId();
addAffectedResource(exportId);
return exportId;
}
public static List<URI> addJournalCapacity(URI projectId, URI virtualArrayId, URI virtualPoolId, double sizeInGb, Integer count,
URI consistencyGroupId, String copyName) {
String volumeSize = gbToVolumeSize(sizeInGb);
Tasks<VolumeRestRep> tasks = execute(new AddJournalCapacity(virtualPoolId, virtualArrayId, projectId, volumeSize,
count, consistencyGroupId, copyName));
List<URI> volumeIds = Lists.newArrayList();
for (Task<VolumeRestRep> task : tasks.getTasks()) {
URI volumeId = task.getResourceId();
addAffectedResource(volumeId);
volumeIds.add(volumeId);
}
return volumeIds;
}
public static List<URI> createMultipleVolumes(List<? extends CreateBlockVolumeHelper> helpers) {
Tasks<VolumeRestRep> tasks = execute(new CreateMultipleBlockVolumes(helpers));
List<URI> volumeIds = Lists.newArrayList();
for (Task<VolumeRestRep> task : tasks.getTasks()) {
URI volumeId = task.getResourceId();
addAffectedResource(volumeId);
volumeIds.add(volumeId);
}
addRollback(new DeactivateVolumes(volumeIds, VolumeDeleteTypeEnum.FULL));
return volumeIds;
}
public static List<URI> createVolumes(URI projectId, URI virtualArrayId, URI virtualPoolId,
String baseVolumeName, double sizeInGb, Integer count, URI consistencyGroupId, URI computeResource) {
String volumeSize = gbToVolumeSize(sizeInGb);
Tasks<VolumeRestRep> tasks = execute(new CreateBlockVolume(virtualPoolId, virtualArrayId, projectId, volumeSize,
count, baseVolumeName, consistencyGroupId, computeResource));
List<URI> volumeIds = Lists.newArrayList();
for (Task<VolumeRestRep> task : tasks.getTasks()) {
URI volumeId = task.getResourceId();
addRollback(new DeactivateVolume(volumeId, VolumeDeleteTypeEnum.FULL));
addAffectedResource(volumeId);
volumeIds.add(volumeId);
}
return volumeIds;
}
public static Task<VolumeRestRep> createVolumesByName(URI projectId, URI virtualArrayId, URI virtualPoolId,
double sizeInGb, URI consistencyGroupId, String volumeName) {
String volumeSize = gbToVolumeSize(sizeInGb);
return execute(new CreateBlockVolumeByName(projectId, virtualArrayId,
virtualPoolId, volumeSize, consistencyGroupId, volumeName));
}
public static void expandVolumes(Collection<URI> volumeIds, double newSizeInGB) {
for (URI volumeId : volumeIds) {
expandVolume(volumeId, newSizeInGB);
}
}
public static void expandVolume(URI volumeId, double newSizeInGB) {
String newSize = gbToVolumeSize(newSizeInGB);
Task<VolumeRestRep> task = execute(new ExpandVolume(volumeId, newSize));
addAffectedResource(task);
}
public static URI createHostExport(URI projectId, URI virtualArrayId, List<URI> volumeIds, Integer hlu, Host host,
Map<URI, Integer> volumeHlus, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator) {
String exportName = host.getHostName();
URI exportId = createHostExport(exportName, projectId, virtualArrayId, volumeIds, hlu, host, volumeHlus, minPaths, maxPaths,
pathsPerInitiator);
return exportId;
}
public static URI createHostExport(String name, URI projectId, URI virtualArrayId, List<URI> volumeIds, Integer hlu, Host host,
Map<URI, Integer> volumeHlus, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator) {
String exportName = name != null ? name : host.getHostName();
Task<ExportGroupRestRep> task = execute(new CreateExport(exportName, virtualArrayId, projectId, volumeIds, hlu,
host.getHostName(), host.getId(), null, volumeHlus, minPaths, maxPaths, pathsPerInitiator));
URI exportId = task.getResourceId();
addRollback(new DeactivateBlockExport(exportId));
addAffectedResource(exportId);
return exportId;
}
public static Task<ExportGroupRestRep> createHostExportNoWait(String exportName, URI projectId,
URI virtualArrayId, List<URI> volumeIds, Integer hlu, Host host) {
return execute(new CreateExportNoWait(exportName == null ? host.getHostName() : exportName,
virtualArrayId, projectId, volumeIds, hlu, host.getHostName(), host.getId(), null));
}
public static URI createClusterExport(URI projectId, URI virtualArrayId, List<URI> volumeIds, Integer hlu, Cluster cluster,
Map<URI, Integer> volumeHlus, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator) {
String exportName = cluster.getLabel();
URI exportId = createClusterExport(exportName, projectId, virtualArrayId, volumeIds, hlu, cluster, volumeHlus, minPaths, maxPaths,
pathsPerInitiator);
return exportId;
}
public static URI createClusterExport(String name, URI projectId, URI virtualArrayId, List<URI> volumeIds, Integer hlu,
Cluster cluster, Map<URI, Integer> volumeHlus, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator) {
String exportName = name != null ? name : cluster.getLabel();
Task<ExportGroupRestRep> task = execute(new CreateExport(exportName, virtualArrayId, projectId, volumeIds, hlu,
cluster.getLabel(), null, cluster.getId(), volumeHlus, minPaths, maxPaths, pathsPerInitiator));
URI exportId = task.getResourceId();
addRollback(new DeactivateBlockExport(exportId));
addAffectedResource(exportId);
return exportId;
}
public static void addVolumesToExport(Collection<URI> volumeIds, Integer hlu, URI exportId, Map<URI, Integer> volumeHlus,
Integer minPaths, Integer maxPaths, Integer pathsPerInitiator) {
Task<ExportGroupRestRep> task = execute(new AddVolumesToExport(exportId, volumeIds, hlu, volumeHlus, minPaths, maxPaths,
pathsPerInitiator));
addRollback(new RemoveBlockResourcesFromExport(exportId, volumeIds));
addAffectedResource(task);
}
public static void addHostToExport(URI exportId, URI host, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator) {
Task<ExportGroupRestRep> task = execute(new AddHostToExport(exportId, host, minPaths, maxPaths, pathsPerInitiator));
addRollback(new DeactivateBlockExport(exportId));
addAffectedResource(task);
}
public static Task<ExportGroupRestRep> addHostAndVolumeToExportNoWait(URI exportId, URI host, URI volumeId, Integer hlu) {
return execute(new AddHostAndVolumeToExportNoWait(exportId, host, volumeId, hlu));
}
public static void addClusterToExport(URI exportId, URI cluster, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator) {
Task<ExportGroupRestRep> task = execute(new AddClusterToExport(exportId, cluster, minPaths, maxPaths, pathsPerInitiator));
addRollback(new DeactivateBlockExport(exportId));
addAffectedResource(task);
}
public static List<ITLRestRep> getExportsForBlockObject(URI blockObjectId) {
return execute(new GetExportsForBlockObject(blockObjectId));
}
/** build map of export id to set of volumes in that export */
protected static Map<URI, Set<URI>> getExportToVolumesMap(List<URI> volumeIds) {
Map<URI, Set<URI>> exportToVolumesMap = Maps.newHashMap();
for (URI volumeId : volumeIds) {
for (ITLRestRep export : getExportsForBlockObject(volumeId)) {
Set<URI> volumesInExport = exportToVolumesMap.get(export.getExport().getId());
if (volumesInExport == null) {
volumesInExport = Sets.newHashSet(volumeId);
}
else {
volumesInExport.add(volumeId);
}
exportToVolumesMap.put(export.getExport().getId(), volumesInExport);
}
}
return exportToVolumesMap;
}
public static void removeBlockResourcesFromExports(Map<URI, Set<URI>> exportToVolumesMap) {
for (Map.Entry<URI, Set<URI>> entry : exportToVolumesMap.entrySet()) {
// Check to see if the export returned is an internal export; one used by internal orchestrations only.
ExportGroupRestRep export = getExport(entry.getKey());
if (ResourceUtils.isNotInternal(export)) {
removeBlockResourcesFromExport(entry.getValue(), entry.getKey());
}
}
}
public static void removeBlockResourcesFromExports(Collection<URI> blockResourceIds) {
Map<URI, Set<URI>> resourcesInExport = Maps.newHashMap();
for (URI blockResourceId : blockResourceIds) {
List<ITLRestRep> exports = getExportsForBlockObject(blockResourceId);
for (ITLRestRep export : exports) {
URI exportId = export.getExport().getId();
if (resourcesInExport.containsKey(exportId)) {
resourcesInExport.get(exportId).add(blockResourceId);
}
else {
resourcesInExport.put(exportId, Sets.newHashSet(blockResourceId));
}
}
}
removeBlockResourcesFromExports(resourcesInExport);
}
public static void removeBlockResourceFromExport(URI resourceId, URI exportId) {
removeBlockResourcesFromExport(Collections.singletonList(resourceId), exportId);
}
public static void removeBlockResourcesFromExport(Collection<URI> resourceId, URI exportId) {
Task<ExportGroupRestRep> task = execute(new RemoveBlockResourcesFromExport(exportId, resourceId));
addAffectedResource(task);
removeExportIfEmpty(exportId);
}
static final int MAX_RETRY_COUNT = 30;
static final int RETRY_DELAY_MSEC = 60000;
public static void removeExportIfEmpty(URI exportId) {
boolean retryNeeded = false;
int retryCount = 0;
do {
retryNeeded = false;
ExportGroupRestRep export = getExport(exportId);
if (ResourceUtils.isActive(export) && export.getVolumes().isEmpty()) {
try {
log.info(String.format("Attampting deletion of ExportGroup %s (%s)", export.getGeneratedName(), export.getId()));
Task<ExportGroupRestRep> response = execute(new DeactivateBlockExport(exportId));
addAffectedResource(response);
} catch (ExecutionException e) {
if (e.getCause() instanceof ServiceErrorException) {
ServiceErrorException svcexp = (ServiceErrorException) e.getCause();
if (retryCount++ < MAX_RETRY_COUNT
&& ServiceCode.toServiceCode(svcexp.getCode()) == ServiceCode.API_TASK_EXECUTION_IN_PROGRESS) {
log.info(String.format("ExportGroup %s deletion waiting on pending task execution", export.getId()));
retryNeeded = true;
try {
Thread.sleep(RETRY_DELAY_MSEC);
} catch (InterruptedException ex) {
log.debug("Sleep interrupted");
}
} else {
throw e;
}
}
}
}
} while (retryNeeded);
}
public static List<URI> getActiveSnapshots(URI volumeId) {
if (ResourceType.isType(BLOCK_SNAPSHOT, volumeId)) {
return Collections.emptyList();
}
return ResourceUtils.ids(execute(new GetActiveSnapshotsForVolume(volumeId)));
}
public static List<URI> getActiveSnapshotSessions(URI volumeId) {
if (ResourceType.isType(BLOCK_SNAPSHOT, volumeId)) {
return Collections.emptyList();
}
return ResourceUtils.ids(execute(new GetActiveSnapshotSessionsForVolume(volumeId)));
}
public static void removeSnapshotsForVolume(URI volumeId, VolumeDeleteTypeEnum type) {
List<URI> snapshotIds = getActiveSnapshots(volumeId);
// For ViPR-only delete of exported snapshots, we don't want to
// try to unexport the snapshots. The controller will clean up any
// export groups/masks if the snapshot is exported.
if (VolumeDeleteTypeEnum.VIPR_ONLY != type) {
removeBlockResourcesFromExports(snapshotIds);
}
removeSnapshots(snapshotIds, type);
}
public static void removeSnapshots(Collection<URI> snapshotIds, VolumeDeleteTypeEnum type) {
for (URI snapshotId : snapshotIds) {
removeSnapshot(snapshotId, type);
}
}
public static void removeSnapshot(URI snapshotId, VolumeDeleteTypeEnum type) {
Tasks<BlockSnapshotRestRep> task = execute(new DeactivateBlockSnapshot(snapshotId, type));
addAffectedResources(task);
}
public static void removeSnapshotSessionsForVolume(URI volumeId, VolumeDeleteTypeEnum type) {
List<URI> snapshotSessionIds = getActiveSnapshotSessions(volumeId);
removeSnapshotSessions(snapshotSessionIds, type);
}
public static void removeSnapshotSessions(Collection<URI> snapshotSessionIds, VolumeDeleteTypeEnum type) {
for (URI snapshotSessionId : snapshotSessionIds) {
removeSnapshotSession(snapshotSessionId, type);
}
}
public static void removeSnapshotSession(URI snapshotSessionId, VolumeDeleteTypeEnum type) {
Tasks<BlockSnapshotSessionRestRep> task = execute(new DeactivateBlockSnapshotSession(snapshotSessionId, type));
addAffectedResources(task);
}
public static void resynchronizeBlockSnapshots(Collection<URI> fullCopyIds) {
for (URI fullCopyId : fullCopyIds) {
resynchronizeBlockSnaptshot(fullCopyId);
}
}
public static void resynchronizeBlockSnaptshot(URI fullCopyId) {
execute(new ResynchronizeBlockSnapshot(fullCopyId));
}
public static List<URI> getActiveContinuousCopies(URI volumeId) {
return ResourceUtils.ids(execute(new GetActiveContinuousCopiesForVolume(volumeId)));
}
public static void removeContinuousCopiesForVolume(URI volumeId, VolumeDeleteTypeEnum type) {
if (!ResourceType.isType(BLOCK_SNAPSHOT, volumeId)) {
Collection<URI> continuousCopyIds = getActiveContinuousCopies(volumeId);
removeContinuousCopiesForVolume(volumeId, continuousCopyIds, type);
}
}
public static void removeContinuousCopiesForVolume(URI volumeId, Collection<URI> continuousCopyIds, VolumeDeleteTypeEnum type) {
if (VolumeDeleteTypeEnum.VIPR_ONLY != type) {
removeBlockResourcesFromExports(continuousCopyIds);
}
for (URI continuousCopyId : continuousCopyIds) {
removeContinuousCopy(volumeId, continuousCopyId, type);
}
}
private static void removeContinuousCopy(URI volumeId, URI continuousCopyId, VolumeDeleteTypeEnum type) {
if (VolumeDeleteTypeEnum.VIPR_ONLY != type) {
BlockObjectRestRep obj = getVolume(volumeId);
if (obj instanceof VolumeRestRep) {
VolumeRestRep volume = (VolumeRestRep) obj;
if (!StringUtils.equalsIgnoreCase(volume.getSystemType(), DiscoveredDataObject.Type.vplex.name())) {
execute(new PauseContinuousCopy(volumeId, continuousCopyId, COPY_NATIVE));
}
}
}
Tasks<VolumeRestRep> tasks = execute(new DeactivateContinuousCopy(volumeId, continuousCopyId, COPY_NATIVE, type));
addAffectedResources(tasks);
}
public static List<URI> getActiveFullCopies(URI volumeId) {
return ResourceUtils.ids(execute(new GetActiveFullCopiesForVolume(volumeId)));
}
public static void removeFullCopiesForVolume(URI volumeId, Collection<URI> vols, VolumeDeleteTypeEnum type) {
if (!ResourceType.isType(BLOCK_SNAPSHOT, volumeId)) {
List<URI> fullCopiesIds = getActiveFullCopies(volumeId);
vols.removeAll(fullCopiesIds);
removeFullCopies(fullCopiesIds, type);
}
}
public static void removeFullCopies(Collection<URI> fullCopyIds, VolumeDeleteTypeEnum type) {
for (URI fullCopyId : fullCopyIds) {
removeFullCopy(fullCopyId, type);
}
}
public static void removeFullCopy(URI fullCopyId, VolumeDeleteTypeEnum type) {
if (VolumeDeleteTypeEnum.VIPR_ONLY != type) {
detachFullCopy(fullCopyId);
}
removeBlockResources(Collections.singletonList(fullCopyId), type);
}
public static void detachFullCopies(Collection<URI> fullCopyIds) {
for (URI fullCopyId : fullCopyIds) {
detachFullCopy(fullCopyId);
}
}
public static void detachFullCopy(URI fullCopyId) {
execute(new DetachFullCopy(fullCopyId));
}
public static void restoreFromFullCopy(URI fullCopyId) {
execute(new RestoreFromFullCopy(fullCopyId));
}
public static Map<URI, Integer> findBlockVolumeHLUs(Collection<URI> volumeIds) {
List<ITLRestRep> bulkResponse = execute(new FindBlockVolumeHlus(volumeIds));
Map<URI, Integer> volumeHLUs = Maps.newHashMap();
for (ITLRestRep export : bulkResponse) {
ExportGroupRestRep exportGroup = getExport(export.getExport().getId());
if (!exportGroup.getInternal()) {
volumeHLUs.put(export.getBlockObject().getId(), export.getHlu());
}
}
return volumeHLUs;
}
public static void resynchronizeFullCopies(Collection<URI> fullCopyIds) {
for (URI fullCopyId : fullCopyIds) {
resynchronizeFullCopy(fullCopyId);
}
}
public static void resynchronizeFullCopy(URI fullCopyId) {
execute(new ResynchronizeFullCopy(fullCopyId));
}
public static void removeBlockResources(Collection<URI> blockResourceIds, VolumeDeleteTypeEnum type) {
List<URI> allBlockResources = Lists.newArrayList(blockResourceIds);
for (URI volumeId : blockResourceIds) {
BlockObjectRestRep volume = getVolume(volumeId);
allBlockResources.addAll(getSrdfTargetVolumes(volume));
}
// For ViPR-only delete of exported volumes, we don't want to
// try to unexport the volumes. The controller will clean up any
// export groups/masks if the volume is exported.
if (VolumeDeleteTypeEnum.VIPR_ONLY != type) {
removeBlockResourcesFromExports(allBlockResources);
}
for (URI volumeId : allBlockResources) {
if (canRemoveReplicas(volumeId)) {
removeSnapshotsForVolume(volumeId, type);
removeSnapshotSessionsForVolume(volumeId, type);
removeContinuousCopiesForVolume(volumeId, type);
removeFullCopiesForVolume(volumeId, blockResourceIds, type);
} else {
unexportReplicas(volumeId, blockResourceIds, type);
}
}
deactivateBlockResources(blockResourceIds, type);
}
public static void unexportReplicas(URI volumeId, Collection<URI> blockResourceIds, VolumeDeleteTypeEnum type) {
if (VolumeDeleteTypeEnum.VIPR_ONLY != type) {
List<URI> snapshotIds = getActiveSnapshots(volumeId);
removeBlockResourcesFromExports(snapshotIds);
if (!ResourceType.isType(BLOCK_SNAPSHOT, volumeId)) {
Collection<URI> continuousCopyIds = getActiveContinuousCopies(volumeId);
removeBlockResourcesFromExports(continuousCopyIds);
}
List<URI> fullCopyIds = getActiveFullCopies(volumeId);
removeBlockResourcesFromExports(fullCopyIds);
}
}
public static boolean canRemoveReplicas(URI blockResourceId) {
ResourceType volumeType = ResourceType.fromResourceId(blockResourceId.toString());
if (volumeType == ResourceType.VOLUME) {
VolumeRestRep volume = (VolumeRestRep) getVolume(blockResourceId);
return !(isVmaxConsistencyVolume(volume) ||
(isVplexVolume(volume, volume.getSystemType()) && isSrdfConsistencyVolume(volume)));
}
return true;
}
private static void deactivateBlockResources(Collection<URI> blockResourceIds, VolumeDeleteTypeEnum type) {
List<URI> volumes = Lists.newArrayList();
List<URI> fullCopies = Lists.newArrayList();
for (URI blockResourceId : blockResourceIds) {
if (ResourceType.isType(VOLUME, blockResourceId)) {
if (isFullCopyAttached(blockResourceId)) {
fullCopies.add(blockResourceId);
}
volumes.add(blockResourceId);
}
else if (ResourceType.isType(BLOCK_SNAPSHOT, blockResourceId)) {
deactivateSnapshot(blockResourceId, type);
}
}
if (VolumeDeleteTypeEnum.VIPR_ONLY != type) {
detachFullCopies(fullCopies);
}
deactivateVolumes(volumes, type);
}
public static boolean isFullCopyAttached(URI id) {
BlockObjectRestRep obj = getVolume(id);
if (obj instanceof VolumeRestRep) {
VolumeRestRep volume = (VolumeRestRep) obj;
if (volume.getProtection() != null) {
FullCopyRestRep fullCopy = volume.getProtection().getFullCopyRep();
if (fullCopy != null &&
fullCopy.getAssociatedSourceVolume() != null &&
fullCopy.getReplicaState() != null &&
!fullCopy.getReplicaState().equals(ReplicationState.DETACHED.name())) {
return true;
}
}
}
return false;
}
public static void deactivateVolumes(List<URI> volumeIds, VolumeDeleteTypeEnum type) {
if (CollectionUtils.isNotEmpty(volumeIds)) {
Tasks<VolumeRestRep> tasks = execute(new DeactivateVolumes(volumeIds, type));
addAffectedResources(tasks);
}
}
private static void deactivateSnapshot(URI snapshotId, VolumeDeleteTypeEnum type) {
Tasks<BlockSnapshotRestRep> tasks = execute(new DeactivateBlockSnapshot(snapshotId, type));
addAffectedResources(tasks);
}
public static List<URI> getSrdfTargetVolumes(BlockObjectRestRep blockObject) {
List<URI> targetVolumes = Lists.newArrayList();
if (blockObject instanceof VolumeRestRep) {
VolumeRestRep volume = (VolumeRestRep) blockObject;
if (volume.getProtection() != null && volume.getProtection().getSrdfRep() != null) {
for (VirtualArrayRelatedResourceRep targetVolume : volume.getProtection().getSrdfRep().getSRDFTargetVolumes()) {
targetVolumes.add(targetVolume.getId());
}
}
}
return targetVolumes;
}
/**
* Return a list of target RP volume for a given block object
*
* @param blockObject to retrieve target from
* @return a list of RP target volumes for specified block object
*/
public static List<URI> getRpTargetVolumes(BlockObjectRestRep blockObject) {
List<URI> targetVolumes = Lists.newArrayList();
if (blockObject instanceof VolumeRestRep) {
VolumeRestRep volume = (VolumeRestRep) blockObject;
if (volume.getProtection() != null && volume.getProtection().getRpRep() != null) {
for (VirtualArrayRelatedResourceRep targetVolume : volume.getProtection().getRpRep().getRpTargets()) {
targetVolumes.add(targetVolume.getId());
}
}
}
return targetVolumes;
}
public static void removeVolumes(List<URI> volumeIds) {
removeBlockResources(volumeIds, VolumeDeleteTypeEnum.FULL);
}
public static void unexportVolumes(List<URI> volumeIds) {
removeBlockResourcesFromExports(volumeIds);
}
public static Set<Initiator> findInitiatorsInVirtualArray(URI virtualArray, Collection<Initiator> initiators,
Protocol protocol) {
return findInitiatorsInVirtualArrays(Arrays.asList(virtualArray), initiators, protocol);
}
public static Set<Initiator> findInitiatorsInVirtualArrays(Collection<URI> virtualArrays,
Collection<Initiator> initiators, Protocol protocol) {
Set<Initiator> results = Sets.newHashSet();
Collection<Initiator> filteredInitiators = filterInitiatorsByType(initiators, protocol);
if (!filteredInitiators.isEmpty()) {
for (URI virtualArray : virtualArrays) {
results.addAll(execute(new FindVirtualArrayInitiators(virtualArray, filteredInitiators)));
}
}
return results;
}
public static Set<URI> getVolumeVirtualArrays(Collection<? extends BlockObjectRestRep> volumes) {
Set<URI> virtualArrays = Sets.newHashSet();
virtualArrays.addAll(Collections2.transform(volumes, new Function<BlockObjectRestRep, URI>() {
@Override
public URI apply(BlockObjectRestRep input) {
return input.getVirtualArray().getId();
}
}));
return virtualArrays;
}
public static Collection<ExportGroupRestRep> filterExportsByType(Collection<ExportGroupRestRep> exportGroups, final URI hostOrCluster) {
return Collections2.filter(exportGroups, new Predicate<ExportGroupRestRep>() {
@Override
public boolean apply(ExportGroupRestRep input) {
if (BlockStorageUtils.isCluster(hostOrCluster)) {
return input.getType().equals(ExportClusterFilter.CLUSTER_EXPORT_TYPE);
} else {
return input.getType().equals(ExportHostFilter.EXCLUSIVE_EXPORT_TYPE) ||
(input.getType().equals(ExportHostFilter.HOST_EXPORT_TYPE));
}
}
});
}
public static Collection<Initiator> filterInitiatorsByType(Collection<Initiator> initiators, final Protocol protocol) {
return Collections2.filter(initiators, new Predicate<Initiator>() {
@Override
public boolean apply(Initiator input) {
return StringUtils.equals(protocol.name(), input.getProtocol());
}
});
}
public static Collection<String> getPortNames(Collection<Initiator> initiators) {
return Collections2.transform(initiators, new Function<Initiator, String>() {
@Override
public String apply(Initiator input) {
return input.getInitiatorPort();
}
});
}
public static String gbToVolumeSize(double sizeInGB) {
// Always use size in bytes, VMAX does not like size in GB
return String.valueOf(DiskSizeConversionUtils.gbToBytes(sizeInGB));
}
public static Tasks<VolumeRestRep> createFullCopy(URI volumeId, String name, Integer count) {
int countValue = (count != null) ? count : 1;
Tasks<VolumeRestRep> copies = execute(new CreateFullCopy(volumeId, name, countValue));
addAffectedResources(copies);
return copies;
}
public static Tasks<BlockSnapshotRestRep> createSnapshotFullCopy(URI snapshotId, String name, Integer count) {
int countValue = (count != null) ? count : 1;
Tasks<BlockSnapshotRestRep> copyTasks = ViPRExecutionUtils.execute(new CreateSnapshotFullCopy(snapshotId, name, countValue));
addAffectedResources(copyTasks);
return copyTasks;
}
public static Tasks<VolumeRestRep> createContinuousCopy(URI volumeId, String name, Integer count) {
int countValue = (count != null) ? count : 1;
Tasks<VolumeRestRep> copies = execute(new CreateContinuousCopy(volumeId, name, countValue, COPY_NATIVE));
addAffectedResources(copies);
return copies;
}
public static Tasks<VolumeRestRep> createContinuousCopy(URI volumeId, String name, Integer count, String type, URI copyId) {
int countValue = (count != null) ? count : 1;
Tasks<VolumeRestRep> copies = execute(new CreateContinuousCopy(volumeId, name, countValue, type, copyId));
addAffectedResources(copies);
return copies;
}
public static void startSnapshot(URI snapshotId) {
Task<BlockSnapshotRestRep> task = execute(new StartBlockSnapshot(snapshotId));
addAffectedResource(task);
}
public static void startFullCopy(URI fullCopyId) {
Tasks<VolumeRestRep> task = execute(new StartFullCopy(fullCopyId));
addAffectedResources(task);
}
public static Tasks<VolumeRestRep> swapContinuousCopy(URI targetVolumeId, String type) {
Tasks<VolumeRestRep> copies = execute(new SwapContinuousCopies(targetVolumeId, type));
addAffectedResources(copies);
return copies;
}
public static Tasks<BlockConsistencyGroupRestRep> swapCGContinuousCopy(URI protectionSource, URI protectionTarget, String type) {
Tasks<BlockConsistencyGroupRestRep> copies = execute(new SwapCGContinuousCopies(protectionSource, protectionTarget, type));
addAffectedResources(copies);
return copies;
}
public static Task<BlockConsistencyGroupRestRep> addVolumesToConsistencyGroup(URI consistencyGroupId, List<URI> volumeIds) {
Task<BlockConsistencyGroupRestRep> task = execute(new AddVolumesToConsistencyGroup(consistencyGroupId, volumeIds));
addAffectedResource(task);
return task;
}
/**
* Finds the exports (itl) for the given initiators.
*
* @param exports
* the list of all exports (itl)
* @param initiators
* the initiators.
* @return the exports for the initiators.
*/
public static List<ITLRestRep> getExportsForInitiators(Collection<ITLRestRep> exports,
Collection<Initiator> initiators) {
Set<String> initiatorPorts = Sets.newHashSet(getPortNames(initiators));
List<ITLRestRep> results = Lists.newArrayList();
for (ITLRestRep export : exports) {
if ((export.getInitiator() != null) && initiatorPorts.contains(export.getInitiator().getPort())) {
results.add(export);
}
}
return results;
}
public static Set<String> getTargetPortsForExports(Collection<ITLRestRep> exports) {
Set<String> targetPorts = Sets.newTreeSet();
for (ITLRestRep export : exports) {
if (export.getStoragePort() != null && StringUtils.isNotBlank(export.getStoragePort().getPort())) {
targetPorts.add(export.getStoragePort().getPort());
}
}
return targetPorts;
}
public static boolean isVolumeInExportGroup(ExportGroupRestRep exportGroup, URI volumeId) {
if (volumeId == null) {
return false;
}
for (ExportBlockParam param : exportGroup.getVolumes()) {
if (param.getId().equals(volumeId)) {
return true;
}
}
return false;
}
public static boolean isEmptyExport(ExportGroupRestRep exportGroup) {
boolean hasVolumes = exportGroup.getVolumes() != null && !exportGroup.getVolumes().isEmpty();
boolean hasInitiators = exportGroup.getInitiators() != null && !exportGroup.getInitiators().isEmpty();
return !hasInitiators && !hasVolumes;
}
/**
* Get the project id off a {@link BlockObjectRestRep}
*/
public static <T extends BlockObjectRestRep> URI getProjectId(T resource) {
if (resource instanceof BlockSnapshotRestRep) {
return ((BlockSnapshotRestRep) resource).getProject().getId();
}
else if (resource instanceof VolumeRestRep) {
return ((VolumeRestRep) resource).getProject().getId();
}
else if (resource instanceof BlockMirrorRestRep) {
return ((BlockMirrorRestRep) resource).getProject().getId();
}
throw new IllegalStateException(ExecutionUtils.getMessage("illegalState.projectNotFound", resource.getId()));
}
/**
* Get the virtual array id off a {@link BlockObjectRestRep}
*/
public static URI getVirtualArrayId(BlockObjectRestRep resource) {
if (resource instanceof VolumeRestRep) {
return ((VolumeRestRep) resource).getVirtualArray().getId();
}
else if (resource instanceof BlockSnapshotRestRep) {
return ((BlockSnapshotRestRep) resource).getVirtualArray().getId();
}
else if (resource instanceof BlockMirrorRestRep) {
return ((BlockMirrorRestRep) resource).getVirtualArray().getId();
}
throw new IllegalStateException(ExecutionUtils.getMessage("illegalState.varrayNotFound", resource.getId()));
}
public static String getFailoverType(BlockObjectRestRep blockObject) {
if (blockObject instanceof VolumeRestRep) {
VolumeRestRep volume = (VolumeRestRep) blockObject;
if (volume.getProtection() != null && volume.getProtection().getRpRep() != null) {
VolumeRestRep.RecoverPointRestRep rp = volume.getProtection().getRpRep();
if (StringUtils.equals("TARGET", rp.getPersonality())) {
return "rp";
}
}
else if (volume.getProtection() != null && volume.getProtection().getSrdfRep() != null) {
VolumeRestRep.SRDFRestRep srdf = volume.getProtection().getSrdfRep();
if (srdf.getAssociatedSourceVolume() != null ||
(srdf.getSRDFTargetVolumes() != null && !srdf.getSRDFTargetVolumes().isEmpty())) {
return "srdf";
}
}
}
return null;
}
public interface Params {
@Override
public String toString();
public Map<String, Object> getParams();
}
/**
* Stores the virtual pool, virtual array, project and consistency group,
* values for volume create services.
*/
public static class VolumeParams implements Params {
@Param(VIRTUAL_POOL)
public URI virtualPool;
@Param(VIRTUAL_ARRAY)
public URI virtualArray;
@Param(PROJECT)
public URI project;
@Param(value = CONSISTENCY_GROUP, required = false)
public URI consistencyGroup;
@Override
public String toString() {
return "Virtual Pool=" + virtualPool + ", Virtual Array=" + virtualArray + ", Project=" + project
+ ", Consistency Group=" + consistencyGroup;
}
@Override
public Map<String, Object> getParams() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(VIRTUAL_POOL, virtualPool);
map.put(VIRTUAL_ARRAY, virtualArray);
map.put(PROJECT, project);
map.put(CONSISTENCY_GROUP, consistencyGroup);
return map;
}
}
/**
* Stores the host and HLU values for volume create for host services.
*/
public static class HostVolumeParams extends VolumeParams {
@Param(HOST)
public URI hostId;
@Param(value = HLU, required = false)
public Integer hlu;
@Param(value = MIN_PATHS, required = false)
protected Integer minPaths;
@Param(value = MAX_PATHS, required = false)
protected Integer maxPaths;
@Param(value = PATHS_PER_INITIATOR, required = false)
protected Integer pathsPerInitiator;
@Override
public String toString() {
String parent = super.toString();
return parent + ", Host Id=" + hostId + ", HLU=" + hlu + ", MIN_PATHS=" + minPaths + ", MAX_PATHS="
+ maxPaths + ", PATHS_PER_INITIATOR=" + pathsPerInitiator;
}
@Override
public Map<String, Object> getParams() {
Map<String, Object> map = new HashMap<String, Object>();
map.putAll(super.getParams());
map.put(HOST, hostId);
map.put(HLU, hlu);
map.put(MIN_PATHS, minPaths);
map.put(MAX_PATHS, maxPaths);
map.put(PATHS_PER_INITIATOR, pathsPerInitiator);
return map;
}
}
/**
* Stores the name, size, and count of volumes for multi-volume create services.
*/
public static class VolumeTable {
@Param(NAME)
protected String nameParam;
@Param(SIZE_IN_GB)
protected Double sizeInGb;
@Param(value = NUMBER_OF_VOLUMES, required = false)
protected Integer count;
@Override
public String toString() {
return "Volume=" + nameParam + ", size=" + sizeInGb + ", count=" + count;
}
public Map<String, Object> getParams() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(NAME, nameParam);
map.put(SIZE_IN_GB, sizeInGb);
map.put(NUMBER_OF_VOLUMES, count);
return map;
}
}
/**
* Helper method for creating a list of all the params for the createBlockVolumesHelper.
*
* @param table volume table
* @param params for volume creation
* @return map of all params
*/
public static Map<String, Object> createParam(VolumeTable table, Params params) {
Map<String, Object> map = new HashMap<String, Object>();
map.putAll(table.getParams());
map.putAll(params.getParams());
return map;
}
/**
* Get source volume for vplexVolume by checking HA volumes with matching varrays
*
* @param vplexVolume vplex volume to use
* @return source volume
*/
private static VolumeRestRep getSourceVolume(VolumeRestRep vplexVolume) {
if (vplexVolume.getHaVolumes() != null && !vplexVolume.getHaVolumes().isEmpty()) {
URI vplexVolumeVarray = vplexVolume.getVirtualArray().getId();
for (RelatedResourceRep haVolume : vplexVolume.getHaVolumes()) {
VolumeRestRep volume = execute(new GetBlockVolume(haVolume.getId()));
if (volume != null && volume.getVirtualArray().getId().equals(vplexVolumeVarray)) {
return volume;
}
}
}
return null;
}
public static Table<URI, String, VolumeRestRep> getReplicationGroupVolumes(List<NamedRelatedResourceRep> volumeUris) {
// Group volumes by storage system and replication group
Table<URI, String, VolumeRestRep> storageRgToVolumes = HashBasedTable.create();
for (NamedRelatedResourceRep volumeUri : volumeUris) {
VolumeRestRep vplexVolume = null;
VolumeRestRep volume = execute(new GetBlockVolume(volumeUri.getId()));
boolean isVPlex = volume.getSystemType().equals("vplex");
if (isVPlex) {
vplexVolume = volume;
volume = getSourceVolume(volume);
}
String rgName = BlockStorageUtils.stripRPTargetFromReplicationGroup(volume.getReplicationGroupInstance());
URI storage = volume.getStorageController();
if (!storageRgToVolumes.contains(storage, rgName)) {
if (isVPlex) {
storageRgToVolumes.put(storage, rgName, vplexVolume);
} else {
storageRgToVolumes.put(storage, rgName, volume);
}
}
}
return storageRgToVolumes;
}
public static Table<URI, String, BlockSnapshotRestRep> getReplicationGroupSnapshots(List<NamedRelatedResourceRep> volumeUris) {
Table<URI, String, BlockSnapshotRestRep> storageRgToVolumes = HashBasedTable.create();
for (NamedRelatedResourceRep volumeUri : volumeUris) {
BlockSnapshotRestRep snapshot = execute(new GetBlockSnapshot(volumeUri.getId()));
VolumeRestRep volume = execute(new GetBlockVolume(snapshot.getParent().getId()));
String rgName = volume.getReplicationGroupInstance();
URI storage = volume.getStorageController();
if (!storageRgToVolumes.contains(storage, rgName)) {
storageRgToVolumes.put(storage, rgName, snapshot);
}
}
return storageRgToVolumes;
}
public static Table<URI, String, BlockSnapshotSessionRestRep> getReplicationGroupSnapshotSessions(
List<NamedRelatedResourceRep> volumeUris) {
Table<URI, String, BlockSnapshotSessionRestRep> storageRgToVolumes = HashBasedTable.create();
for (NamedRelatedResourceRep volumeUri : volumeUris) {
BlockSnapshotSessionRestRep snapshotSession = execute(new GetBlockSnapshotSession(volumeUri.getId()));
String rgName = snapshotSession.getReplicationGroupInstance();
URI storage = snapshotSession.getStorageController();
if (!storageRgToVolumes.contains(storage, rgName)) {
storageRgToVolumes.put(storage, rgName, snapshotSession);
}
}
return storageRgToVolumes;
}
public static List<URI> getSingleVolumePerSubGroupAndStorageSystem(NamedVolumesList volList, List<String> subGroups) {
List<URI> volumeIds = Lists.newArrayList();
Table<URI, String, VolumeRestRep> results = getReplicationGroupVolumes(volList.getVolumes());
for (Cell<URI, String, VolumeRestRep> cell : results.cellSet()) {
if (subGroups.contains(cell.getColumnKey())) {
volumeIds.add(cell.getValue().getId());
}
}
return volumeIds;
}
public static List<URI> getSingleSnapshotPerSubGroupAndStorageSystem(URI applicationId, String copySet, List<String> subGroups) {
List<URI> snapshotIds = Lists.newArrayList();
Table<URI, String, BlockSnapshotRestRep> results = getReplicationGroupSnapshots(execute(
new GetBlockSnapshotSet(applicationId, copySet)).getSnapList());
for (Cell<URI, String, BlockSnapshotRestRep> cell : results.cellSet()) {
if (subGroups.contains(BlockStorageUtils.stripRPTargetFromReplicationGroup(cell.getColumnKey()))) {
snapshotIds.add(cell.getValue().getId());
}
}
return snapshotIds;
}
public static List<URI> getSingleSnapshotSessionPerSubGroupAndStorageSystem(URI applicationId, String copySet, List<String> subGroups) {
List<URI> snapshotSessionIds = Lists.newArrayList();
Table<URI, String, BlockSnapshotSessionRestRep> results = getReplicationGroupSnapshotSessions(execute(
new GetBlockSnapshotSessionList(applicationId, copySet)).getSnapSessionRelatedResourceList());
for (Cell<URI, String, BlockSnapshotSessionRestRep> cell : results.cellSet()) {
String stripped = BlockStorageUtils.stripRPTargetFromReplicationGroup(cell.getColumnKey());
if (subGroups.contains(stripped)) {
snapshotSessionIds.add(cell.getValue().getId());
}
}
return snapshotSessionIds;
}
public static Table<URI, String, VolumeRestRep> getReplicationGroupFullCopies(
List<NamedRelatedResourceRep> volumeUris) {
// Group volumes by storage system and replication group
Table<URI, String, VolumeRestRep> storageRgToVolumes = HashBasedTable.create();
List<URI> parentVolIds = Lists.newArrayList();
for (NamedRelatedResourceRep volumeUri : volumeUris) {
VolumeRestRep volume = execute(new GetBlockVolume(volumeUri.getId()));
if (volume != null && volume.getProtection() != null && volume.getProtection().getFullCopyRep() != null
&& volume.getProtection().getFullCopyRep().getAssociatedSourceVolume() != null) {
parentVolIds.add(volume.getProtection().getFullCopyRep().getAssociatedSourceVolume().getId());
}
List<VolumeRestRep> parentVolumes = execute(new GetBlockVolumes(parentVolIds));
if (parentVolumes != null && !parentVolumes.isEmpty()) {
for (VolumeRestRep parentVolume : parentVolumes) {
String rgName = stripRPTargetFromReplicationGroup(parentVolume.getReplicationGroupInstance());
URI storage = parentVolume.getStorageController();
if (!storageRgToVolumes.contains(storage, rgName)) {
storageRgToVolumes.put(storage, rgName, volume);
}
}
}
}
return storageRgToVolumes;
}
public static List<URI> getSingleFullCopyPerSubGroupAndStorageSystem(URI applicationId, String copySet,
List<String> subGroups) {
List<URI> fullCopyIds = Lists.newArrayList();
Table<URI, String, VolumeRestRep> results = getReplicationGroupFullCopies(
execute(new GetFullCopyList(applicationId, copySet)).getVolumes());
for (Cell<URI, String, VolumeRestRep> cell : results.cellSet()) {
if (subGroups.contains(cell.getColumnKey())) {
fullCopyIds.add(cell.getValue().getId());
}
}
return fullCopyIds;
}
public static List<URI> getAllFullCopyVolumes(URI applicationId, String copySet, List<String> subGroups) {
List<URI> fullCopyIds = Lists.newArrayList();
List<NamedRelatedResourceRep> fullCopies = execute(new GetFullCopyList(applicationId, copySet)).getVolumes();
for (NamedRelatedResourceRep fullCopy : fullCopies) {
fullCopyIds.add(fullCopy.getId());
}
return fullCopyIds;
}
public static boolean isVplexVolume(VolumeRestRep volume, String storageSystemType) {
return (volume.getHaVolumes() != null && !volume.getHaVolumes().isEmpty())
|| (storageSystemType != null && storageSystemType.equals(StorageProvider.InterfaceType.vplex.name()));
}
public static boolean isVplexOrRPVolume(String volumeId) {
if (volumeId == null) {
return false;
}
VolumeRestRep volume = execute(new GetBlockVolume(volumeId));
if (volume == null) {
return false;
}
if (volume.getProtection() != null && volume.getProtection().getRpRep() != null) {
return true;
}
return isVplexVolume(volume, volume.getSystemType());
}
public static String stripRPTargetFromReplicationGroup(String group) {
String[] parts = StringUtils.split(group, '-');
if (parts.length > 1 && parts[parts.length - 1].equals("RPTARGET")) {
return StringUtils.join(parts, '-', 0, parts.length - 1);
} else {
return group;
}
}
public static Set<String> stripRPTargetFromReplicationGroup(Collection<String> groups) {
Set<String> stripped = new HashSet<String>();
for (String group : groups) {
stripped.add(stripRPTargetFromReplicationGroup(group));
}
return stripped;
}
public static boolean isRPVolume(VolumeRestRep volume) {
return (volume.getProtection() != null && volume.getProtection().getRpRep() != null);
}
public static boolean isRPSourceVolume(VolumeRestRep volume) {
if (isRPVolume(volume)
&& volume.getProtection().getRpRep().getPersonality() != null
&& volume.getProtection().getRpRep().getPersonality().equalsIgnoreCase("SOURCE")) {
return true;
}
return false;
}
/**
* returns true if the passed in volume is a RP target volume
*
* @param vol
* @return
*/
public static boolean isRPTargetVolume(VolumeRestRep volume) {
if (isRPVolume(volume)
&& volume.getProtection().getRpRep().getPersonality() != null
&& volume.getProtection().getRpRep().getPersonality().equalsIgnoreCase("TARGET")) {
return true;
}
return false;
}
/**
* gets the vplex primary/source backing volume for a vplex virtual volume
*
* @param client
* @param vplexVolume
* @return
*/
public static VolumeRestRep getVPlexSourceVolume(ViPRCoreClient client, VolumeRestRep vplexVolume) {
if (vplexVolume.getHaVolumes() != null && !vplexVolume.getHaVolumes().isEmpty()) {
URI vplexVolumeVarray = vplexVolume.getVirtualArray().getId();
for (RelatedResourceRep haVolume : vplexVolume.getHaVolumes()) {
VolumeRestRep volume = client.blockVolumes().get(haVolume.getId());
if (volume != null && volume.getVirtualArray().getId().equals(vplexVolumeVarray)) {
return volume;
}
}
}
return null;
}
public static NamedVolumesList getVolumesBySite(ViPRCoreClient client, String virtualArrayId, URI applicationId) {
boolean isTarget = false;
URI virtualArray = null;
if (virtualArrayId != null && StringUtils.split(virtualArrayId, ':')[0].equals("tgt")) {
virtualArray = URI.create(StringUtils.substringAfter(virtualArrayId, ":"));
isTarget = true;
} else {
isTarget = false;
}
NamedVolumesList applicationVolumes = client.application().getVolumeByApplication(applicationId);
NamedVolumesList volumesToUse = new NamedVolumesList();
for (NamedRelatedResourceRep volumeId : applicationVolumes.getVolumes()) {
VolumeRestRep parentVolume = client.blockVolumes().get(volumeId);
if (isTarget) {
if (isRPTargetVolume(parentVolume) && parentVolume.getVirtualArray().getId().equals(virtualArray)) {
volumesToUse.getVolumes().add(volumeId);
}
} else {
if (!BlockStorageUtils.isRPVolume(parentVolume) || BlockStorageUtils.isRPSourceVolume(parentVolume)) {
volumesToUse.getVolumes().add(volumeId);
}
}
}
return volumesToUse;
}
public static boolean isVmaxConsistencyVolume(VolumeRestRep volume ) {
return volume.getConsistencyGroup() != null &&
(volume.getSystemType().equalsIgnoreCase(DiscoveredDataObject.Type.vmax.name()) ||
volume.getSystemType().equalsIgnoreCase(DiscoveredDataObject.Type.vmax3.name()));
}
public static boolean isSrdfConsistencyVolume(VolumeRestRep volume) {
if (volume.getConsistencyGroup() == null) {
return false;
}
BlockConsistencyGroupRestRep group = getBlockConsistencyGroup(volume.getConsistencyGroup().getId());
return group != null && group.getTypes().contains(BlockConsistencyGroup.Types.SRDF.name());
}
public static void checkVolumeLimit(ViPRCoreClient client, URI project) {
ExecutionContext context = ExecutionUtils.currentContext();
long limit = context.getResourceLimit(Constants.RESOURCE_LIMIT_PROJECT_VOLUMES);
int numOfVolumes = client.blockVolumes().countByProject(project);
// Show alert in case of approaching 90% of the limit
if (numOfVolumes >= limit * Constants.RESOURCE_LIMIT_ALERT_RATE) {
context.logWarn("alert.createVolume.exceedingResourceLimit", numOfVolumes, limit);
}
}
/**
* Utility method that determines if the given volume is already expanded based on
* a desired expansion size.
* @param volume the volume to inspect
* @param sizeInGb the desired volume expand size
* @return true if the volume is already expanded, false otherwise
*/
public static boolean isVolumeExpanded(VolumeRestRep volume, Double sizeInGb) {
return (Double.parseDouble(volume.getCapacity()) >= sizeInGb);
}
/**
* Returns the viprcli command for adding a tag to a block volume
*
* @param blockObjectId the id of the block object
* @param tagName the tag name
* @param tagValue the tag value
* @return viprcli command
*/
public static String getVolumeTagCommand(URI blockObjectId, String tagName, String tagValue) {
BlockObjectRestRep blockObject = getBlockResource(blockObjectId);
URI projectId = getProjectId(blockObject);
ProjectRestRep project = getProject(projectId);
TenantOrgRestRep tenant = getTenant(project.getTenant().getId());
return ExecutionUtils.getMessage("viprcli.volume.tag", blockObject.getName(), tenant.getName(), project.getName(),
tagName, tagValue);
}
}