/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.util;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
/**
* Performs conversions from Vplex Volumes to corresponding SRDF Volumes and vice-versa.
*/
public class VPlexSrdfUtil {
private VPlexSrdfUtil() {
// All methods are static, no need to make an instance.
}
/**
* Returns the srdf underlying volume if there is one, otherwise null.
* Assumes both legs of vplex cannot be srdf protected.
* @param dbClient -- dbClient handle
* @param vplexVolume -- Vplex volume object.
* @return -- Srdf volume if present, or null
*/
static public Volume getSrdfVolumeFromVplexVolume(DbClient dbClient, Volume vplexVolume) {
if (null != vplexVolume.getAssociatedVolumes()) {
List<URI> volumeUriList = new ArrayList<>();
for (String associatedVolumeId : vplexVolume.getAssociatedVolumes()) {
volumeUriList.add(URI.create(associatedVolumeId));
}
Iterator<Volume> volumes = dbClient.queryIterativeObjects(Volume.class, volumeUriList, true);
while (volumes.hasNext()) {
Volume assocVolume = volumes.next();
if (assocVolume == null || assocVolume.getInactive()) {
continue;
}
if (assocVolume.checkForSRDF()) {
return assocVolume;
}
}
}
return null;
}
/**
* Returns the Vplex volume that is covering an SRDF volume.
* @param dbClient - dbclient handle
* @param srdfVolume - SRDF Volume object
* @return - Vplex volume fronting SRDF volume, or null
*/
static public Volume getVplexVolumeFromSrdfVolume(DbClient dbClient, Volume srdfVolume) {
return Volume.fetchVplexVolume(dbClient, srdfVolume);
}
/**
* Given an SRDF or VPLEX volume, will always return the SRDF volume.
* If vplex it's the corresponding srdf volume.
* @param dbClient
* @param id - URI of volume
* @return - URI of SRDF volume
*/
static public URI getSrdfIdFromVolumeId(DbClient dbClient, URI id) {
if (id == null) {
return null;
}
Volume volume = dbClient.queryObject(Volume.class, id);
if (volume == null || !volume.isVPlexVolume(dbClient)) {
return id;
}
Volume srdfVolume = getSrdfVolumeFromVplexVolume(dbClient, volume);
return (srdfVolume == null ? id : srdfVolume.getId());
}
/**
* Returns the vplex front volume ids for the srdf targets if they have a vplex volume,
* otherwise returns the original srdf target id
* @param dbClient - DbClient handle
* @param srdfVolume - An Srdf volume having targets
* @return String set of volume ids for either vplex/srdf volume or srdf volume in target list
*/
static public StringSet getSrdfOrVplexTargets(DbClient dbClient, Volume srdfVolume) {
StringSet targets = new StringSet();
for (String targetVolumeId : srdfVolume.getSrdfTargets()) {
URI srdfTargetUri = URI.create(targetVolumeId);
URI vplexTargetUri = Volume.fetchVplexVolume(dbClient, srdfTargetUri);
if (vplexTargetUri != null) {
targets.add(vplexTargetUri.toString());
} else {
targets.add(srdfTargetUri.toString());
}
}
return targets;
}
/**
* Given a list of Vplex Volume URIs, will filter out any that front SRDF targets.
* @param dbClient -- database client
* @param vplexVolumeUris -- list of URIS for Vplex volumes
* @return -- filtered list of Vplex volume URIs, or empty list if all filtered away
*/
public static List<URI> filterOutVplexSrdfTargets(DbClient dbClient, List<URI> vplexVolumeUris) {
List<URI> returnedVolumes = new ArrayList<URI>();
returnedVolumes.addAll(vplexVolumeUris);
List<URI> vplexSrdfTargets = returnVplexSrdfTargets(dbClient, vplexVolumeUris);
returnedVolumes.removeAll(vplexSrdfTargets);
return returnedVolumes;
}
/**
* Given a list of Vplex Volume URIs, return any that front SRDF targets.
* @param dbClient -- database client
* @param vplexVolumeURIs -- list of URIS for Vplex volumes
* @param setCGOnVplexVolume -- if true, sets the consistency group of the Vplex volumes
* to the CG of the underlying RDF volume, and only returns volumes that have CG set.
* It also makes sure that VPLEX is in the cg Requested Types.
* @return -- filtered list of Vplex volume URIs, or empty list if all filtered away
*/
public static List<URI> returnVplexSrdfTargets(DbClient dbClient,
List<URI> vplexVolumeURIs) {
List<URI> returnedVolumes = new ArrayList<URI>();
for (URI vplexURI : vplexVolumeURIs) {
Volume vplexVolume = dbClient.queryObject(Volume.class, vplexURI);
if (vplexVolume == null) {
continue;
}
Volume srdfVolume = getSrdfVolumeFromVplexVolume(dbClient, vplexVolume);
// See if SRDF target
if (srdfVolume != null && !NullColumnValueGetter.isNullNamedURI(srdfVolume.getSrdfParent())) {
// Virtual volume in front of SRDF target to return list
returnedVolumes.add(vplexVolume.getId());
}
}
return returnedVolumes;
}
/**
* Given a list of Vplex volume URIs, returns a map of VPlexVolume to corresonding SRDF backend volume.
* @param dbClient database client handle
* @param vplexVolumeURIs -- List of vplex volume URIs
* @return Map<Volume, Volume> of vplex to srdf volumes
*/
public static Map<Volume, Volume> makeVplexToSrdfVolumeMap(DbClient dbClient, List<URI> vplexVolumeURIs) {
Map<Volume, Volume> vplexToSrdfVolumeMap = new HashMap<Volume, Volume>();
for (URI vplexVolumeURI : vplexVolumeURIs) {
Volume vplexVolume = dbClient.queryObject(Volume.class, vplexVolumeURI);
if (vplexVolume != null) {
Volume srdfVolume = getSrdfVolumeFromVplexVolume(dbClient, vplexVolume);
if (srdfVolume != null) {
vplexToSrdfVolumeMap.put(vplexVolume, srdfVolume);
}
}
}
return vplexToSrdfVolumeMap;
}
}