/*
* Copyright (c) 2008-2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.ibm.xiv;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.cim.CIMInstance;
import javax.cim.UnsignedInteger16;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.model.DiscoveredDataObject;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StoragePool.PoolClassNames;
import com.emc.storageos.db.client.model.StoragePool.PoolServiceType;
import com.emc.storageos.db.client.model.StoragePool.SupportedDriveTypeValues;
import com.emc.storageos.db.client.model.StoragePool.SupportedResourceTypes;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StorageSystem.SupportedProvisioningTypes;
import com.emc.storageos.plugins.AccessProfile;
import com.emc.storageos.plugins.BaseCollectionException;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.plugins.common.domainmodel.Operation;
import com.emc.storageos.volumecontroller.impl.ControllerUtils;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
import com.emc.storageos.volumecontroller.impl.StoragePoolAssociationHelper;
import com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.PoolProcessor;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.emc.storageos.volumecontroller.impl.smis.SmisUtils;
import com.emc.storageos.volumecontroller.impl.utils.DiscoveryUtils;
import com.emc.storageos.volumecontroller.impl.utils.ImplicitPoolMatcher;
/**
* Processor responsible for handling Provider response data and creates
* StoragePools.
*/
public class XIVStoragePoolProcessor extends PoolProcessor {
private Logger _logger = LoggerFactory
.getLogger(XIVStoragePoolProcessor.class);
private static final String HARD_SIZE = "HardSize";
private static final String SOFT_SIZE = "SoftSize";
private static final String POOL_ID = "PoolID";
private static final String OPERATIONAL_STATUS = "OperationalStatus";
private static final String TWO = "2";
private static final String IBM_SUBSCRIBEDCAPACITY = "VirtualSpaceConsumed";
private DbClient _dbClient = null;
private AccessProfile _profile = null;
private List<StoragePool> _newPoolList = null;
private List<StoragePool> _updatePoolList = null;
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public void processResult(Operation operation, Object resultObj,
Map<String, Object> keyMap) throws BaseCollectionException {
final Iterator<CIMInstance> it = (Iterator<CIMInstance>) resultObj;
_profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE);
try {
_newPoolList = new ArrayList<StoragePool>();
_updatePoolList = new ArrayList<StoragePool>();
_dbClient = (DbClient) keyMap.get(Constants.dbClient);
StorageSystem device = getStorageSystem(_dbClient,
_profile.getSystemId());
if (SupportedProvisioningTypes.NONE.name().equalsIgnoreCase(
device.getSupportedProvisioningType())) {
_logger.info("Storage System doesn't support volume creations :"
+ device.getLabel());
return;
}
Set<String> protocols = (Set<String>) keyMap
.get(Constants.PROTOCOLS);
Map<URI, StoragePool> poolsToMatchWithVpool = new HashMap<URI, StoragePool>();
while (it.hasNext()) {
CIMInstance poolInstance = it.next();
try {
addPath(keyMap, operation.getResult(),
poolInstance.getObjectPath());
String hardSizeStr = getCIMPropertyValue(poolInstance,
HARD_SIZE);
long hardSize = Long.parseLong(hardSizeStr);
String softSizeStr = getCIMPropertyValue(poolInstance,
SOFT_SIZE);
long softSize = Long.parseLong(softSizeStr);
SupportedResourceTypes type = SupportedResourceTypes.THICK_ONLY;
if (hardSize < softSize) {
type = SupportedResourceTypes.THIN_ONLY;
}
createStoragePool(_dbClient, device, poolInstance,
PoolClassNames.IBMTSDS_VirtualPool.name(),
type.name(), protocols, poolsToMatchWithVpool,
_newPoolList, _updatePoolList);
} catch (Exception e) {
_logger.warn(
"StoragePool Discovery failed for {}",
getCIMPropertyValue(poolInstance,
Constants.INSTANCEID), getMessage(e));
}
}
// set the pools whose properties got changed.
keyMap.put(Constants.MODIFIED_STORAGEPOOLS, poolsToMatchWithVpool);
_dbClient.createObject(_newPoolList);
_dbClient.updateAndReindexObject(_updatePoolList);
// find the pools not visible in this discovery
List<StoragePool> discoveredPools = new ArrayList<StoragePool>(_newPoolList);
discoveredPools.addAll(_updatePoolList);
List<StoragePool> notVisiblePools = DiscoveryUtils.checkStoragePoolsNotVisible(discoveredPools, _dbClient, device.getId());
for (StoragePool notVisiblePool : notVisiblePools) {
poolsToMatchWithVpool.put(notVisiblePool.getId(), notVisiblePool);
}
// If any storage ports on the storage system are in a transport
// zone, there is an implicit connection to the transport zone
// varray. We need to add these implicit varray
// connections for the new storage pool.
StoragePoolAssociationHelper.setStoragePoolVarrays(device.getId(),
_newPoolList, _dbClient);
} catch (Exception e) {
_logger.error("StoragePool Discovery failed", e);
} finally {
_newPoolList = null;
_updatePoolList = null;
}
}
/*
* Determine operational status of pool
* READY, if any of the status value is 2 (OK).
* otherwise NOTREADY
*/
protected String determineOperationalStatus(CIMInstance poolInstance) {
String operationalStatus = StoragePool.PoolOperationalStatus.NOTREADY.name();
try {
UnsignedInteger16[] opStatus = (UnsignedInteger16[]) poolInstance
.getPropertyValue(OPERATIONAL_STATUS);
for (UnsignedInteger16 status : opStatus) {
if (status.compareTo(new UnsignedInteger16(TWO)) == 0) {
operationalStatus = StoragePool.PoolOperationalStatus.READY
.name();
}
}
} catch (Exception ex) {
_logger.error("Discovering Pool Operational Status failed : {}-->",
getCIMPropertyValue(poolInstance, Constants.INSTANCEID), ex);
}
return operationalStatus;
}
/**
* Create StoragePool, if not present already, else only update the properties
*
* @param dbClient
* @param device
* @param poolInstance
* @param poolClassName
* @param supportedVolumeTypes
* @param protocols
* @param poolsToMatchWithVpool
* @param newPoolList
* @param updatePoolList
* @throws URISyntaxException
* @throws IOException
*/
private void createStoragePool(DbClient dbClient, StorageSystem device,
CIMInstance poolInstance, String poolClassName,
String supportedVolumeTypes, Set<String> protocols,
Map<URI, StoragePool> poolsToMatchWithVpool, List<StoragePool> newPoolList,
List<StoragePool> updatePoolList) throws URISyntaxException,
IOException {
boolean newPool = false;
boolean modifiedPool = false; // indicates whether to add to modified pools list or not
String nativeId = getCIMPropertyValue(poolInstance, POOL_ID);
String poolName = getCIMPropertyValue(poolInstance, SmisConstants.CP_ELEMENT_NAME);
StoragePool pool = checkStoragePoolExistsInDB(nativeId, dbClient, device);
if (null == pool) {
newPool = true;
pool = new StoragePool();
pool.setId(URIUtil.createId(StoragePool.class));
pool.setPoolClassName(poolClassName);
pool.setNativeId(nativeId);
pool.setStorageDevice(device.getId());
pool.setPoolServiceType(PoolServiceType.block.toString());
String poolNativeGuid = NativeGUIDGenerator.generateNativeGuid(dbClient, pool);
pool.setNativeGuid(poolNativeGuid);
pool.setLabel(poolNativeGuid);
// setting default values on Pool Creation
pool.setMaximumThickVolumeSize(0L);
pool.setMinimumThickVolumeSize(0L);
pool.setMaximumThinVolumeSize(0L);
pool.setMinimumThinVolumeSize(0L);
_logger.info(String
.format("Maximum default limits for volume capacity in storage pool: %s %n max thin volume capacity: %s, max thick volume capacity: %s ",
pool.getId(), pool.getMaximumThinVolumeSize(), pool.getMaximumThickVolumeSize()));
pool.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.COMPATIBLE.name());
Set<String> diskDrives = new HashSet<String>();
if (device.getModel().equalsIgnoreCase("A14")) {
// Gen2 2810/2812 use SATA
diskDrives.add(SupportedDriveTypeValues.SATA.name());
}
else {
// Gen3 2810/2812 114 or 214
diskDrives.add(SupportedDriveTypeValues.SAS.name());
}
pool.addDriveTypes(diskDrives);
}
String subscribedCapacity = getCIMPropertyValue(poolInstance, IBM_SUBSCRIBEDCAPACITY);
if (null != subscribedCapacity) {
pool.setSubscribedCapacity(ControllerUtils.convertBytesToKBytes(subscribedCapacity));
}
pool.setFreeCapacity(SmisUtils.getFreeCapacity(poolInstance));
pool.setTotalCapacity(SmisUtils.getTotalCapacity(poolInstance));
pool.setPoolName(poolName);
String operationalStatus = determineOperationalStatus(poolInstance);
if (!newPool
&& (ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getOperationalStatus(), operationalStatus) ||
ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getProtocols(), protocols) ||
ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getSupportedResourceTypes(), supportedVolumeTypes))
||
ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getDiscoveryStatus(),
DiscoveredDataObject.DiscoveryStatus.VISIBLE.name())) {
modifiedPool = true;
}
pool.addProtocols(protocols);
pool.setOperationalStatus(operationalStatus);
pool.setSupportedResourceTypes(supportedVolumeTypes);
pool.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.VISIBLE.name());
if (newPool) {
newPoolList.add(pool);
// add new pools to modified pools list to consider them for implicit pool matching.
poolsToMatchWithVpool.put(pool.getId(), pool);
}
else {
updatePoolList.add(pool);
// add to modified pool list if pool's property which is required for vPool matcher, has changed.
// No need to check whether the pool is already there in the list here
// because this processor is the first to discover pools.
if (modifiedPool) {
poolsToMatchWithVpool.put(pool.getId(), pool);
}
}
}
}