/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.utils.attrmatchers;
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 java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.util.ConnectivityUtil;
import com.emc.storageos.volumecontroller.AttributeMatcher;
import com.google.common.base.Joiner;
/**
* VPlexHighAvailabilityMatcher ensures a storage pool is on a storage system
* that is associated with a VPlex storage storage system
*/
public class VPlexHighAvailabilityMatcher extends AttributeMatcher {
// Logger reference.
private static final Logger _logger = LoggerFactory
.getLogger(VPlexHighAvailabilityMatcher.class);
/**
* {@inheritDoc}
*/
@Override
public List<StoragePool> matchStoragePoolsWithAttributeOn(List<StoragePool> allPools, Map<String, Object> attributeMap,
StringBuffer errorMessage) {
_logger.info("Pools Matching ha attribute Started:{}", Joiner.on("\t").join(getNativeGuidFromPools(allPools)));
List<StoragePool> matchedPools = new ArrayList<StoragePool>();
// Get the varrays to match.
@SuppressWarnings("unchecked")
Set<String> matchVarrays = (Set<String>) attributeMap.get(Attributes.varrays.toString());
// Get the HA type.
String haType = (String) attributeMap.get(Attributes.high_availability_type
.toString());
// Get HA varray Id.
String haVarrayId = (String) attributeMap.get(Attributes.high_availability_varray
.toString());
if (haVarrayId != null) {
URI haVarrayURI = URI.create(haVarrayId);
if (NullColumnValueGetter.isNullURI(haVarrayURI)) {
haVarrayId = null;
}
}
// Get HA Virtual Pool
VirtualPool haVpool = null;
List<StoragePool> haVpoolPoolList = null;
String haVpoolId = (String) attributeMap.get(Attributes.high_availability_vpool
.toString());
if (haVpoolId != null) {
URI haCosURI = URI.create(haVpoolId);
if (NullColumnValueGetter.isNullURI(haCosURI)) {
haVpoolId = null;
} else {
haVpool = _objectCache.queryObject(VirtualPool.class, URI.create(haVpoolId));
haVpoolPoolList = VirtualPool.getValidStoragePools(haVpool, _objectCache.getDbClient(), true);
}
}
// Iterate over the pools and add those to the matched list that match.
Map<URI, List<String>> systemVPlexMap = new HashMap<URI, List<String>>();
Map<String, List<URI>> vplexVarrayMap = new HashMap<String, List<URI>>();
Iterator<StoragePool> allPoolsIter = allPools.iterator();
while (allPoolsIter.hasNext()) {
StoragePool storagePool = allPoolsIter.next();
List<String> vplexSystemsForPool = null;
URI poolSystemURI = storagePool.getStorageDevice();
if (systemVPlexMap.containsKey(poolSystemURI)) {
vplexSystemsForPool = systemVPlexMap.get(poolSystemURI);
} else {
vplexSystemsForPool = getVPlexStorageSystemsForStorageSystem(_objectCache.getDbClient(),
poolSystemURI, matchVarrays);
systemVPlexMap.put(poolSystemURI, vplexSystemsForPool);
}
// Only pools connected to a VPlex system potentially match.
if (vplexSystemsForPool.isEmpty()) {
continue;
}
// For local HA, the pool must only be connected to a VPlex.
if (VirtualPool.HighAvailabilityType.vplex_local.toString().equals(haType)) {
matchedPools.add(storagePool);
continue;
}
// Otherwise, must be distributed. Loop over the
// VPlex systems for the pool to make sure one of
// the systems satisfies the distributed HA CoS
// attributes.
for (String vplexSystemId : vplexSystemsForPool) {
List<URI> vplexVarrays = null;
if (vplexVarrayMap.containsKey(vplexSystemId)) {
vplexVarrays = vplexVarrayMap.get(vplexSystemId);
} else {
vplexVarrays = ConnectivityUtil
.getVPlexSystemVarrays(_objectCache.getDbClient(), URI.create(vplexSystemId));
vplexVarrayMap.put(vplexSystemId, vplexVarrays);
}
// If there are not multiple varrays for the VPlex,
// it cannot support distributed HA. Move on to the
// next VPlex.
if (vplexVarrays.size() < 2) {
continue;
}
// There are multiple varrays for the VPlex
// so we know it can support distributed HA.
if ((haVarrayId == null) && (haVpoolId == null)) {
// No specific HA varray or CoS was specified, the
// pool matches.
matchedPools.add(storagePool);
break;
} else if (haVpoolId == null) {
// Only an HA varray was specified. If the
// VPlex is connected to the HA varray, the
// pool is a match.
if (vplexVarrays.contains(URI.create(haVarrayId))) {
matchedPools.add(storagePool);
break;
}
} else if (haVarrayId == null) {
// Only an HA vpool was specified. There must be
// a pool in the VPlex that satisfies the HA vpool.
boolean poolAdded = false;
for (URI varrayURI : vplexVarrays) {
if (varrayHasPoolMatchingHaVpool(varrayURI.toString(),
haVpoolPoolList)) {
matchedPools.add(storagePool);
poolAdded = true;
break;
}
}
if (poolAdded) {
break;
}
} else if ((vplexVarrays.contains(URI.create(haVarrayId))) &&
(varrayHasPoolMatchingHaVpool(haVarrayId, haVpoolPoolList))) {
// Both and HA varray and vpool are specified.
// The VPlex must be connected to the HA varray
// and have a pool matching the HA vpool.
matchedPools.add(storagePool);
break;
}
}
}
_logger.info("Pools Matching ha attribute Matcher Ended:{}",
Joiner.on("\t").join(getNativeGuidFromPools(matchedPools)));
if (CollectionUtils.isEmpty(matchedPools)) {
errorMessage.append("No matching stoarge pool found for VPLEX high availability. ");
_logger.error(errorMessage.toString());
}
return matchedPools;
}
/**
* Gets a list of the VPlex storage systems for the passed system in the
* passed virtual arrays or any virtual array if none are passed.
*
* @param dbClient Reference to a DB client.
* @param systemURI Reference to a storage system.
* @param matchVarrays the virtual arrays to match or null.
*
* @return A list of the VPlex storage system ids.
*/
public static List<String> getVPlexStorageSystemsForStorageSystem(DbClient dbClient,
URI systemURI, Set<String> matchVarrays) {
List<String> vplexStorageSystemIds = new ArrayList<String>();
Set<URI> vplexSystemURIs = ConnectivityUtil
.getVPlexSystemsAssociatedWithArray(dbClient, systemURI, matchVarrays, null);
for (URI uri : vplexSystemURIs) {
vplexStorageSystemIds.add(uri.toString());
}
return vplexStorageSystemIds;
}
/**
* Determine if the varray with the passed id has a storage pool that
* satisfies the HA CoS.
*
* @param nhId The id of a varray.
* @param haCosPoolList The pool list for the HA CoS.
*
* @return true if the varray has a storage pool that matches the HA
* CoS, false otherwise.
*/
private boolean varrayHasPoolMatchingHaVpool(String nhId,
List<StoragePool> haCosPoolList) {
for (StoragePool haCosPool : haCosPoolList) {
StringSet poolNHs = haCosPool.getTaggedVirtualArrays();
if (poolNHs != null && poolNHs.contains(nhId)) {
return true;
}
}
return false;
}
@Override
protected boolean isAttributeOn(Map<String, Object> attributeMap) {
return (null != attributeMap && (VirtualPool.HighAvailabilityType.vplex_distributed
.toString().equals(
attributeMap.get(Attributes.high_availability_type.toString())) || VirtualPool.HighAvailabilityType.vplex_local
.toString().equals(
attributeMap.get(Attributes.high_availability_type.toString()))));
}
}