/**
* Copyright (c) 2012-2015 EMC Corporation
* All Rights Reserved
*
* This software contains the intellectual property of EMC Corporation
* or is licensed to EMC Corporation from third parties. Use of this
* software and the intellectual property contained therein is expressly
* limited to the terms and conditions of the License Agreement under which
* it is provided by or on behalf of EMC.
*/
package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import javax.wbem.CloseableIterator;
import javax.wbem.client.EnumerateResponse;
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.model.BlockMirror;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.plugins.BaseCollectionException;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.plugins.common.PartitionManager;
import com.emc.storageos.plugins.common.domainmodel.Operation;
import com.emc.storageos.volumecontroller.impl.smis.CIMPropertyFactory;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.emc.storageos.volumecontroller.impl.smis.SmisUtils;
/*
* Get volume info from StorageVolume instance
*
* Based on StorageVolumeViewProcessor
*/
public class StorageVolumeProcessor extends StorageProcessor {
private static final Logger _logger = LoggerFactory.getLogger(StorageVolumeProcessor.class);
private static final String USAGE = "Usage";
private static final String EMC_IS_COMPOSITE = "EMCIsComposite";
private DbClient _dbClient;
private Map<String, Object> _keyMap;
private List<Volume> _updateVolumes = null;
private List<BlockSnapshot> _updateSnapShots = null;
private List<BlockMirror> _updateMirrors = null;
private static final int BATCH_SIZE = 200;
private PartitionManager _partitionManager;
private Map<String, String> _volumeToSpaceConsumedMap = null;
private List<CIMObjectPath> _metaVolumePaths = null;
private boolean _isVMAX3 = false;
public void setPartitionManager(PartitionManager partitionManager) {
_partitionManager = partitionManager;
}
@Override
public void processResult(
Operation operation, Object resultObj, Map<String, Object> keyMap)
throws BaseCollectionException {
EnumerateResponse<CIMInstance> volumeInstanceChunks = (EnumerateResponse<CIMInstance>) resultObj;
_dbClient = (DbClient) keyMap.get(Constants.dbClient);
_keyMap = keyMap;
_updateVolumes = new ArrayList<Volume>();
_updateSnapShots = new ArrayList<BlockSnapshot>();
_updateMirrors = new ArrayList<BlockMirror>();
CloseableIterator<CIMInstance> volumeInstances = null;
try {
// create empty place holder list for meta volume paths (cannot define this in xml)
_metaVolumePaths = (List<CIMObjectPath>) keyMap.get(Constants.META_VOLUMES);
if (_metaVolumePaths == null) {
keyMap.put(Constants.META_VOLUMES, new ArrayList<CIMObjectPath>());
}
_volumeToSpaceConsumedMap = (Map<String, String>) keyMap.get(Constants.VOLUME_SPACE_CONSUMED_MAP);
CIMObjectPath storagePoolPath = getObjectPathfromCIMArgument(_args);
_isVMAX3 = storagePoolPath.getObjectName().equals(StoragePool.PoolClassNames.Symm_SRPStoragePool.name());
processResultbyChunk(resultObj, keyMap);
_partitionManager.updateInBatches(_updateVolumes, getPartitionSize(keyMap), _dbClient,
VOLUME);
_partitionManager.updateInBatches(_updateSnapShots, getPartitionSize(keyMap),
_dbClient, BLOCK_SNAPSHOT);
_partitionManager.updateInBatches(_updateMirrors, getPartitionSize(keyMap), _dbClient,
BLOCK_MIRROR);
} catch (Exception e) {
_logger.error("Processing Volumes and Snapshots failed", e);
} finally {
_updateVolumes = null;
_updateSnapShots = null;
_updateMirrors = null;
if (null != volumeInstances) {
volumeInstances.close();
}
}
}
@Override
protected int processInstances(Iterator<CIMInstance> instances, WBEMClient client) {
int count = 0;
List<CIMObjectPath> metaVolumes = new ArrayList<>();
while (instances.hasNext()) {
try {
count++;
CIMInstance volumeInstance = instances.next();
String nativeGuid = getVolumeNativeGuid(volumeInstance.getObjectPath());
if (isSnapShot(volumeInstance)) {
BlockSnapshot snapShot = checkSnapShotExistsInDB(nativeGuid, _dbClient);
if (null == snapShot || snapShot.getInactive()) {
_logger.debug("Skipping Snapshot, as its not being managed in ViPR");
continue;
}
updateBlockSnapShot(volumeInstance, snapShot, _keyMap);
if (_updateSnapShots.size() > BATCH_SIZE) {
_partitionManager.updateInBatches(_updateSnapShots, getPartitionSize(_keyMap),
_dbClient, BLOCK_SNAPSHOT);
_updateSnapShots.clear();
}
} else if (isMirror(volumeInstance)) {
BlockMirror mirror = checkBlockMirrorExistsInDB(nativeGuid, _dbClient);
if (null == mirror || mirror.getInactive()) {
_logger.debug("Skipping Mirror, as its not being managed in Bourne");
continue;
}
CIMInstance syncObject = getSyncElement(volumeInstance, client);
updateBlockMirror(volumeInstance, mirror, _keyMap, syncObject);
if (_updateMirrors.size() > BATCH_SIZE) {
_partitionManager.updateInBatches(_updateMirrors, getPartitionSize(_keyMap),
_dbClient, BLOCK_MIRROR);
_updateMirrors.clear();
}
} else {
Volume storageVolume = checkStorageVolumeExistsInDB(nativeGuid, _dbClient);
if (null == storageVolume || storageVolume.getInactive()) {
continue;
}
_logger.debug("Volume managed by Bourne :" + storageVolume.getNativeGuid());
updateStorageVolume(volumeInstance, storageVolume, _keyMap);
// Check if this is a meta volume and if we need to set missing meta volume related properties.
// This is applicable for meta volumes discovered as unmanaged volumes and ingested prior to vipr controller 2.2 .
if (storageVolume.getIsComposite()
&& (storageVolume.getCompositionType() == null || storageVolume.getCompositionType().isEmpty())) {
// meta volume is missing meta related data. Need to discover this data and set in the volume.
metaVolumes.add(volumeInstance.getObjectPath());
_logger.info("Found meta volume in vipr with missing data: {}, name: {}",
volumeInstance.getObjectPath(), storageVolume.getLabel());
}
}
if (_updateVolumes.size() > BATCH_SIZE) {
_partitionManager.updateInBatches(_updateVolumes, getPartitionSize(_keyMap),
_dbClient, VOLUME);
_updateVolumes.clear();
}
} catch (Exception e) {
_logger.error("Processing volume instance.", e);
}
}
// Add meta volumes to the keyMap
if (metaVolumes != null && !metaVolumes.isEmpty()) {
_metaVolumePaths.addAll(metaVolumes);
_logger.info("Added {} meta volumes.", metaVolumes.size());
}
return count;
}
private boolean isComposite(CIMInstance volumeViewInstance) {
String isComposite = getCIMPropertyValue(volumeViewInstance, EMC_IS_COMPOSITE);
return isComposite.equalsIgnoreCase("true");
}
private boolean isMirror(CIMInstance volumeViewInstance) {
String usage = getCIMPropertyValue(volumeViewInstance, USAGE);
// 8 refers to Mirror
return usage.equalsIgnoreCase(EIGHT);
}
private boolean isSnapShot(CIMInstance volumeInstance) {
String usage = getCIMPropertyValue(volumeInstance, USAGE);
// 12 refers to Snapshot
return usage.equalsIgnoreCase(TWELVE);
}
private void
updateBlockSnapShot(CIMInstance volumeInstance, BlockSnapshot snapShot, Map<String, Object> keyMap) {
String spaceConsumed = getAllocatedCapacity(volumeInstance, _volumeToSpaceConsumedMap, _isVMAX3);
if (spaceConsumed != null) {
snapShot.setAllocatedCapacity(Long.parseLong(spaceConsumed));
}
snapShot.setProvisionedCapacity(returnProvisionedCapacity(
volumeInstance, keyMap));
_updateSnapShots.add(snapShot);
}
private void updateBlockMirror(CIMInstance volumeInstance, BlockMirror mirror, Map<String, Object> keyMap, CIMInstance syncObject) {
String spaceConsumed = getAllocatedCapacity(volumeInstance, _volumeToSpaceConsumedMap, _isVMAX3);
if (spaceConsumed != null) {
mirror.setAllocatedCapacity(Long.parseLong(spaceConsumed));
}
if (null != syncObject) {
mirror.setSyncState(CIMPropertyFactory.getPropertyValue(syncObject, SmisConstants.CP_SYNC_STATE));
}
mirror.setProvisionedCapacity(returnProvisionedCapacity(volumeInstance,
keyMap));
mirror.setCompressionRatio(SmisUtils.getCompressionRatioForVolume(volumeInstance));
_updateMirrors.add(mirror);
}
private void updateStorageVolume(CIMInstance volumeInstance, Volume volume, Map<String, Object> keyMap) {
String spaceConsumed = getAllocatedCapacity(volumeInstance, _volumeToSpaceConsumedMap, _isVMAX3);
if (spaceConsumed != null) {
volume.setAllocatedCapacity(Long.parseLong(spaceConsumed));
}
volume.setProvisionedCapacity(returnProvisionedCapacity(
volumeInstance, keyMap));
// If meta volume was ingested prior to upgrade to 2.2 it won't have
// 'isComposite' set. We need to check
// cim instance here to see if the volume is meta volume and set it in
// the volume instance.
if (isComposite(volumeInstance) && !volume.getIsComposite()) {
volume.setIsComposite(true);
_logger.info("Set volume {} to composite (meta volume)",
volume.getId());
}
volume.setCompressionRatio(SmisUtils.getCompressionRatioForVolume(volumeInstance));
_updateVolumes.add(volume);
}
}