/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.cim.UnsignedInteger32; import javax.wbem.CloseableIterator; import javax.wbem.client.EnumerateResponse; import javax.wbem.client.WBEMClient; import com.emc.storageos.volumecontroller.impl.plugins.SMICommunicationInterface; 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.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; public class StorageVolumeViewProcessor extends StorageProcessor { private static final String SVUSAGE = "SVUsage"; private Logger _logger = LoggerFactory.getLogger(StorageVolumeViewProcessor.class); private DbClient _dbClient; private List<Volume> _updateVolumes = null; private List<Object> _args; private List<BlockSnapshot> _updateSnapShots; private List<BlockMirror> _updateMirrors; private static final int BATCH_SIZE = 200; private PartitionManager _partitionManager; List<CIMObjectPath> _metaVolumeViewPaths = null; 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; WBEMClient client = SMICommunicationInterface.getCIMClient(keyMap); _dbClient = (DbClient) keyMap.get(Constants.dbClient); _updateVolumes = new ArrayList<Volume>(); _updateSnapShots = new ArrayList<BlockSnapshot>(); _updateMirrors = new ArrayList<BlockMirror>(); CloseableIterator<CIMInstance> volumeInstances = null; try { _metaVolumeViewPaths = (List<CIMObjectPath>) keyMap.get(Constants.META_VOLUMES_VIEWS); if (_metaVolumeViewPaths == null) { _metaVolumeViewPaths = new ArrayList<CIMObjectPath>(); keyMap.put(Constants.META_VOLUMES_VIEWS, _metaVolumeViewPaths); } // create empty place holder list for meta volume paths (cannot define this in xml) List<CIMObjectPath> metaVolumePaths = (List<CIMObjectPath>) keyMap.get(Constants.META_VOLUMES); if (metaVolumePaths == null) { keyMap.put(Constants.META_VOLUMES, new ArrayList<CIMObjectPath>()); } CIMObjectPath storagePoolPath = getObjectPathfromCIMArgument(_args); volumeInstances = volumeInstanceChunks.getResponses(); processVolumes(volumeInstances, keyMap); while (!volumeInstanceChunks.isEnd()) { _logger.info("Processing Next Volume Chunk of size {}", BATCH_SIZE); volumeInstanceChunks = client.getInstancesWithPath(storagePoolPath, volumeInstanceChunks.getContext(), new UnsignedInteger32(BATCH_SIZE)); processVolumes(volumeInstanceChunks.getResponses(), keyMap); } // if list empty, this method returns back immediately. // partition size might not be used in this context, as batch size < partition size. // TODO metering might need some extra work to push volumes in batches, hence not changing this method // signature _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(); } } } private void processVolumes(CloseableIterator<CIMInstance> volumeInstances, Map<String, Object> keyMap) throws IOException { List<CIMObjectPath> metaVolumes = new ArrayList<>(); while (volumeInstances.hasNext()) { CIMInstance volumeViewInstance = volumeInstances.next(); String nativeGuid = getVolumeViewNativeGuid(volumeViewInstance.getObjectPath(), keyMap); if (isSnapShot(volumeViewInstance)) { BlockSnapshot snapShot = checkSnapShotExistsInDB(nativeGuid, _dbClient); if (null == snapShot || snapShot.getInactive()) { _logger.debug("Skipping Snapshot, as its not being managed in Bourne"); continue; } updateBlockSnapShot(volumeViewInstance, snapShot, keyMap); if (_updateSnapShots.size() > BATCH_SIZE) { _partitionManager.updateInBatches(_updateSnapShots, getPartitionSize(keyMap), _dbClient, BLOCK_SNAPSHOT); _updateSnapShots.clear(); } } else if (isMirror(volumeViewInstance)) { BlockMirror mirror = checkBlockMirrorExistsInDB(nativeGuid, _dbClient); if (null == mirror || mirror.getInactive()) { _logger.debug("Skipping Mirror, as its not being managed in Bourne"); continue; } updateBlockMirror(volumeViewInstance, mirror, keyMap); 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(volumeViewInstance, 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(volumeViewInstance.getObjectPath()); _logger.info("Found meta volume in vipr with missing data: {}, name: {}", volumeViewInstance.getObjectPath(), storageVolume.getLabel()); } } if (_updateVolumes.size() > BATCH_SIZE) { _partitionManager.updateInBatches(_updateVolumes, getPartitionSize(keyMap), _dbClient, VOLUME); _updateVolumes.clear(); } } // Add meta volumes to the keyMap try { if (metaVolumes != null && !metaVolumes.isEmpty()) { _metaVolumeViewPaths.addAll(metaVolumes); _logger.info("Added {} meta volumes.", metaVolumes.size()); } } catch (Exception ex) { _logger.error("Processing meta volumes.", ex); } } private boolean isComposite(CIMInstance volumeViewInstance) { String isComposite = getCIMPropertyValue(volumeViewInstance, EMC_IS_META_VOLUME); return isComposite.equalsIgnoreCase("true"); } private boolean isMirror(CIMInstance volumeViewInstance) { String usage = getCIMPropertyValue(volumeViewInstance, SVUSAGE); // 8 refers to Mirror return usage.equalsIgnoreCase(EIGHT); } private boolean isSnapShot(CIMInstance volumeInstance) { String usage = getCIMPropertyValue(volumeInstance, SVUSAGE); // 12 refers to Snapshot return usage.equalsIgnoreCase(TWELVE); } private void updateBlockSnapShot(CIMInstance volumeInstance, BlockSnapshot snapShot, Map<String, Object> keyMap) { snapShot.setAllocatedCapacity(Long.parseLong(getCIMPropertyValue( volumeInstance, EMC_ALLOCATED_CAPACITY))); snapShot.setProvisionedCapacity(returnProvisionedCapacity( volumeInstance, keyMap)); _updateSnapShots.add(snapShot); } private void updateBlockMirror(CIMInstance volumeInstance, BlockMirror mirror, Map<String, Object> keyMap) { mirror.setAllocatedCapacity(Long.parseLong(getCIMPropertyValue( volumeInstance, EMC_ALLOCATED_CAPACITY))); mirror.setProvisionedCapacity(returnProvisionedCapacity(volumeInstance, keyMap)); _updateMirrors.add(mirror); } private void updateStorageVolume(CIMInstance volumeInstance, Volume storageVolume, Map<String, Object> keyMap) throws IOException { storageVolume.setAllocatedCapacity(Long.parseLong(getCIMPropertyValue( volumeInstance, EMC_ALLOCATED_CAPACITY))); storageVolume.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) && !storageVolume.getIsComposite()) { storageVolume.setIsComposite(true); _logger.info("Set volume {} to composite (meta volume)", storageVolume.getId()); } _updateVolumes.add(storageVolume); } @Override protected void setPrerequisiteObjects(List<Object> inputArgs) throws BaseCollectionException { _args = inputArgs; } }