/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.export;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.cim.CIMObjectPath;
import javax.wbem.CloseableIterator;
import javax.wbem.client.WBEMClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.ExportGroup.ExportGroupType;
import com.emc.storageos.db.client.model.Host;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StringMap;
import com.emc.storageos.db.client.util.CommonTransformerFunctions;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.google.common.collect.Collections2;
/*
* Helper class to provide common functions for array affinity discovery
*/
public class ArrayAffinityDiscoveryUtils {
private static final Logger _log = LoggerFactory.getLogger(ArrayAffinityDiscoveryUtils.class);
public static final List<String> HOST_PROPERTIES = Arrays.asList("preferredPools", "label");
/**
* update preferredPools for a host
*
* @param Host host to be update
* @param systemIds IDs of the systems
* @param dbClient DbClient
* @param poolToTypeMap new preferred pools on the system
* @return true if host's preferred pools have been changed
*/
public static boolean updatePreferredPools(Host host, Set<String> systemIds, DbClient dbClient, Map<String, String> poolToTypeMap) {
StringMap existingPreferredPools = host.getPreferredPools();
List<String> poolsToRemove = new ArrayList<String>();
// find out pools on the system were preferred, but not anymore
if (!existingPreferredPools.isEmpty()) {
Collection<URI> poolURIs = Collections2.transform(existingPreferredPools.keySet(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
List<StoragePool> pools = dbClient.queryObject(StoragePool.class, poolURIs);
for (StoragePool pool : pools) {
if (systemIds.contains(pool.getStorageDevice().toString())) {
String poolIdStr = pool.getId().toString();
if (!poolToTypeMap.containsKey(poolIdStr)) {
poolsToRemove.add(poolIdStr);
}
}
}
}
boolean needUpdateHost = false;
for (String pool : poolsToRemove) {
existingPreferredPools.remove(pool);
needUpdateHost = true;
}
if (!poolToTypeMap.isEmpty()) {
existingPreferredPools.putAll(poolToTypeMap);
needUpdateHost = true;
}
return needUpdateHost;
}
/*
* Get storage pool URI if for the given volume
*
* @param client WBEMClient
* @param volumePath CIMObjectPath
* @return URI of storage pool
*/
public static URI getStoragePool(CIMObjectPath volumePath, WBEMClient client, DbClient dbClient) {
URI poolURI = null;
CloseableIterator<CIMObjectPath> iterator = null;
try {
if (volumePath != null) {
iterator = client.referenceNames(volumePath, SmisConstants.CIM_ALLOCATED_FROM_STORAGEPOOL, null);
if (iterator.hasNext()) {
CIMObjectPath allocatedFromStoragePoolPath = iterator.next();
CIMObjectPath poolPath = (CIMObjectPath) allocatedFromStoragePoolPath.getKeyValue(SmisConstants.ANTECEDENT);
String nativeGuid = NativeGUIDGenerator.generateNativeGuidForPool(poolPath);
// use NativeGuid to lookup Pools in DB
List<StoragePool> pools = CustomQueryUtility.getActiveStoragePoolByNativeGuid(dbClient, nativeGuid);
if (pools != null && !pools.isEmpty()) {
poolURI = pools.get(0).getId();
}
}
}
} catch (Exception e) {
_log.error("Unable to get storage pool for volume {}", volumePath, e);
} finally {
if (iterator != null) {
iterator.close();
}
}
return poolURI;
}
/**
* Add pool Id and export type to preferred pool map
* If a host has at least one shared volume in given pool, the pool is shared (cluster type). If a host has only exclusive volumes in the pool,
* the pool is not shared (Host type)
*
* @param preferredPools preferred pool to export type map
* @param pool String of pool Id
* @param type type of export
*/
public static void addPoolToPreferredPoolMap(Map<String, String> preferredPoolToExportTypeMap, String pool, String type) {
String oldType = preferredPoolToExportTypeMap.get(pool);
if (oldType == null || (!oldType.equals(type) && type.equals(ExportGroupType.Cluster.name()))) {
preferredPoolToExportTypeMap.put(pool, type);
}
}
/**
* Check if volume with given path is an unmanaged volume
*
* @param voumePath path of the volume
* @param dbClinet DbClient
* @return boolean true if it is an unmanaged volume
*/
public static boolean isUnmanagedVolume(CIMObjectPath volumePath, DbClient dbClient) {
String systemName = volumePath.getKey(SmisConstants.CP_SYSTEM_NAME).getValue().toString();
systemName = systemName.replaceAll(Constants.SMIS80_DELIMITER_REGEX, Constants.PLUS);
String id = volumePath.getKey(SmisConstants.CP_DEVICE_ID).getValue().toString();
String nativeGuid = NativeGUIDGenerator.generateNativeGuidForVolumeOrBlockSnapShot(systemName.toUpperCase(), id);
URIQueryResultList result = new URIQueryResultList();
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getVolumeNativeGuidConstraint(nativeGuid), result);
if (result.iterator().hasNext()) {
return false;
}
return true;
}
}