/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.detailedDiscovery; import java.io.IOException; import java.net.URI; 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.CIMDataType; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.cim.CIMProperty; import javax.cim.UnsignedInteger32; 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.URIUtil; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.model.BlockMirror; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.Initiator; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.StringSetMap; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedExportMask; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.SupportedVolumeCharacterstics; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.SupportedVolumeInformation; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.Types; import com.emc.storageos.db.client.util.NullColumnValueGetter; 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.PartitionManager; import com.emc.storageos.plugins.common.domainmodel.Operation; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.plugins.SMICommunicationInterface; import com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.StorageProcessor; import com.emc.storageos.volumecontroller.impl.smis.SmisConstants; import com.emc.storageos.volumecontroller.impl.smis.srdf.SRDFUtils; import com.emc.storageos.volumecontroller.impl.utils.DiscoveryUtils; import com.google.common.base.Joiner; import com.google.common.collect.Sets; import com.google.common.collect.Sets.SetView; /** * Processor used in updating information on preExisting Volumes * */ public class StorageVolumeInfoProcessor extends StorageProcessor { private final Logger _logger = LoggerFactory .getLogger(StorageVolumeInfoProcessor.class); private List<Object> _args; private DbClient _dbClient; private static final String SVUSAGE = "SVUsage"; private static final String USAGE = "Usage"; private static final String TWO = "2"; private static final String NINE = "9"; private static final String SEVEN = "7"; private static final String ELEVEN = "11"; private static final String TRUE = "true"; private static final String FALSE = "false"; private static final String UNMANAGED_VOLUME = "UnManagedVolume"; private static final String UNMANAGED_EXPORT_MASK = "UnManagedExportMask"; private static final String SVELEMENT_NAME = "SVElementName"; private static final String THINLY_PROVISIONED = "ThinlyProvisioned"; private AccessProfile _profile; private PartitionManager _partitionManager; List<UnManagedVolume> _unManagedVolumesInsert = null; List<UnManagedVolume> _unManagedVolumesUpdate = null; List<UnManagedExportMask> _unManagedExportMasksUpdate = null; List<CIMObjectPath> _metaVolumeViewPaths = null; List<CIMObjectPath> _metaVolumePaths = null; private Map<String, String> _volumeToSpaceConsumedMap = null; Set<URI> unManagedVolumesReturnedFromProvider = new HashSet<URI>(); public void setPartitionManager(PartitionManager partitionManager) { _partitionManager = partitionManager; } @Override public void processResult(Operation operation, Object resultObj, Map<String, Object> keyMap) throws BaseCollectionException { CloseableIterator<CIMInstance> volumeInstances = null; EnumerateResponse<CIMInstance> volumeInstanceChunks = null; CIMObjectPath storagePoolPath = null; WBEMClient client = null; try { _dbClient = (DbClient) keyMap.get(Constants.dbClient); client = SMICommunicationInterface.getCIMClient(keyMap); _profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE); Map<String, VolHostIOObject> exportedVolumes = (Map<String, VolHostIOObject>) keyMap .get(Constants.EXPORTED_VOLUMES); Set<String> existingVolumesInCG = (Set<String>) keyMap.get(Constants.VOLUMES_PART_OF_CG); @SuppressWarnings("unchecked") Map<String, RemoteMirrorObject> volumeToRAGroupMap = (Map<String, RemoteMirrorObject>) keyMap .get(Constants.UN_VOLUME_RAGROUP_MAP); @SuppressWarnings("unchecked") Map<String, LocalReplicaObject> volumeToLocalReplicaMap = (Map<String, LocalReplicaObject>) keyMap .get(Constants.UN_VOLUME_LOCAL_REPLICA_MAP); @SuppressWarnings("unchecked") Map<String, Map<String, String>> volumeToSyncAspectMap = (Map<String, Map<String, String>>) keyMap .get(Constants.SNAPSHOT_NAMES_SYNCHRONIZATION_ASPECT_MAP); @SuppressWarnings("unchecked") Map<String, Set<String>> duplicateSyncAspectElementNameMap = (Map<String, Set<String>>) keyMap .get(Constants.DUPLICATE_SYNC_ASPECT_ELEMENT_NAME_MAP); @SuppressWarnings("unchecked") Map<String, Set<String>> vmax2ThinPoolToBoundVolumesMap = (Map<String, Set<String>>) keyMap .get(Constants.VMAX2_THIN_POOL_TO_BOUND_VOLUMES); Set<String> boundVolumes = null; storagePoolPath = getObjectPathfromCIMArgument(_args); String poolNativeGuid = NativeGUIDGenerator.generateNativeGuidForPool(storagePoolPath); StoragePool pool = checkStoragePoolExistsInDB(poolNativeGuid, _dbClient); if (pool == null) { _logger.error( "Skipping unmanaged volume discovery as the storage pool with path {} doesn't exist in ViPR", storagePoolPath.toString()); return; } StorageSystem system = _dbClient.queryObject(StorageSystem.class, _profile.getSystemId()); _unManagedVolumesInsert = new ArrayList<UnManagedVolume>(); _unManagedVolumesUpdate = new ArrayList<UnManagedVolume>(); _unManagedExportMasksUpdate = new ArrayList<UnManagedExportMask>(); // get bound volumes list for VMAX2 Thin pools boundVolumes = vmax2ThinPoolToBoundVolumesMap.get(storagePoolPath.toString()); Set<String> poolSupportedSLONames = (Set<String>) keyMap.get(poolNativeGuid); _logger.debug("Pool Supporting SLO Names:{}", poolSupportedSLONames); _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) _metaVolumePaths = (List<CIMObjectPath>) keyMap.get(Constants.META_VOLUMES); if (_metaVolumePaths == null) { _metaVolumePaths = new ArrayList<CIMObjectPath>(); keyMap.put(Constants.META_VOLUMES, _metaVolumePaths); } _volumeToSpaceConsumedMap = (Map<String, String>) keyMap.get(Constants.VOLUME_SPACE_CONSUMED_MAP); // get VolumeInfo Object and inject Fast Policy Name. volumeInstanceChunks = (EnumerateResponse<CIMInstance>) resultObj; volumeInstances = volumeInstanceChunks.getResponses(); Set<URI> srdfEnabledTargetVPools = SRDFUtils.fetchSRDFTargetVirtualPools(_dbClient); processVolumes(volumeInstances, keyMap, operation, pool, system, exportedVolumes, existingVolumesInCG, volumeToRAGroupMap, volumeToLocalReplicaMap, volumeToSyncAspectMap, poolSupportedSLONames, boundVolumes, srdfEnabledTargetVPools, duplicateSyncAspectElementNameMap); 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, operation, pool, system, exportedVolumes, existingVolumesInCG, volumeToRAGroupMap, volumeToLocalReplicaMap, volumeToSyncAspectMap, poolSupportedSLONames, boundVolumes, srdfEnabledTargetVPools, duplicateSyncAspectElementNameMap); } if (null != _unManagedVolumesUpdate && !_unManagedVolumesUpdate.isEmpty()) { _partitionManager.updateAndReIndexInBatches(_unManagedVolumesUpdate, getPartitionSize(keyMap), _dbClient, UNMANAGED_VOLUME); } if (null != _unManagedVolumesInsert && !_unManagedVolumesInsert.isEmpty()) { _partitionManager.insertInBatches(_unManagedVolumesInsert, getPartitionSize(keyMap), _dbClient, UNMANAGED_VOLUME); } if (null != _unManagedExportMasksUpdate && !_unManagedExportMasksUpdate.isEmpty()) { _partitionManager.updateAndReIndexInBatches(_unManagedExportMasksUpdate, getPartitionSize(keyMap), _dbClient, UNMANAGED_EXPORT_MASK); } performStorageUnManagedVolumeBookKeeping(pool.getId()); } catch (Exception e) { _logger.error("Processing Storage Volume Information failed :", e); } finally { _unManagedVolumesInsert = null; _unManagedVolumesUpdate = null; if (null != volumeInstances) { volumeInstances.close(); } if (null != volumeInstanceChunks) { try { client.closeEnumeration(storagePoolPath, volumeInstanceChunks.getContext()); } catch (Exception e) { _logger.debug("Exception occurred while closing enumeration", e); } } } } /** * Process the volumes to find the unmanaged volumes and populate the volume * supported information. * * @param it * @param keyMap * @param operation * @param pool * @param system * @param exportedVolumes * @param volumesAndReplicas * @param existingVolumesInCG * @param volumeToRAGroupMap * @param poolSupportedSLONames * @param boundVolumes * @param srdfEnabledTargetVPools * @param duplicateSyncAspectElementNameMap */ private void processVolumes(Iterator<CIMInstance> it, Map<String, Object> keyMap, Operation operation, StoragePool pool, StorageSystem system, Map<String, VolHostIOObject> exportedVolumes, Set<String> existingVolumesInCG, Map<String, RemoteMirrorObject> volumeToRAGroupMap, Map<String, LocalReplicaObject> volumeToLocalReplicaMap, Map<String, Map<String, String>> volumeToSyncAspectMap, Set<String> poolSupportedSLONames, Set<String> boundVolumes, Set<URI> srdfEnabledTargetVPools, Map<String, Set<String>> duplicateSyncAspectElementNameMap) { List<CIMObjectPath> metaVolumes = new ArrayList<CIMObjectPath>(); List<CIMObjectPath> metaVolumeViews = new ArrayList<CIMObjectPath>(); while (it.hasNext()) { CIMInstance volumeViewInstance = null; try { volumeViewInstance = it.next(); String volumeNativeGuid = getVolumeViewNativeGuid(volumeViewInstance.getObjectPath(), keyMap); Volume volume = checkStorageVolumeExistsInDB(volumeNativeGuid, _dbClient); // don't delete UnManaged volume object for volumes ingested with NO Public access. // check for all 3 flags, just checking NO_PUBLIC_ACCESS/INTERNAL_OBJECT flag may // create UnManaged Volume object for VPLEX VMAX backend volume. if (null != volume) { _logger.debug("Skipping discovery, as this Volume {} is already being managed by ViPR.", volumeNativeGuid); continue; } // The discovered volume could also be a BlockSnapshot or a BlockMirror so // check for these as well. BlockSnapshot snap = DiscoveryUtils.checkBlockSnapshotExistsInDB(_dbClient, volumeNativeGuid); if (null != snap) { _logger.debug("Skipping discovery, as this discovered volume {} is already a managed BlockSnapshot in ViPR.", volumeNativeGuid); continue; } BlockMirror mirror = checkBlockMirrorExistsInDB(volumeNativeGuid, _dbClient); if (null != mirror) { _logger.debug("Skipping discovery, as this discovered volume {} is already a managed BlockMirror in ViPR.", volumeNativeGuid); continue; } // skip non-bound volumes for this pool if (boundVolumes != null) { String deviceId = null; if (system.getUsingSmis80()) { deviceId = volumeViewInstance.getObjectPath().getKey(DEVICE_ID).getValue().toString(); } else { deviceId = volumeViewInstance.getObjectPath().getKey(SVDEVICEID).getValue().toString(); } if (!boundVolumes.contains(deviceId)) { _logger.info("Skipping volume, as this Volume {} is not bound to this Thin Storage Pool {}", volumeNativeGuid, pool.getLabel()); continue; } } addPath(keyMap, operation.getResult(), volumeViewInstance.getObjectPath()); String unManagedVolumeNativeGuid = getUnManagedVolumeNativeGuid( volumeViewInstance.getObjectPath(), keyMap); UnManagedVolume unManagedVolume = checkUnManagedVolumeExistsInDB(unManagedVolumeNativeGuid, _dbClient); unManagedVolume = createUnManagedVolume(unManagedVolume, volumeViewInstance, unManagedVolumeNativeGuid, pool, system, volumeNativeGuid, exportedVolumes, existingVolumesInCG, volumeToRAGroupMap, volumeToLocalReplicaMap, volumeToSyncAspectMap, poolSupportedSLONames, keyMap, srdfEnabledTargetVPools, duplicateSyncAspectElementNameMap); // set up UnManagedExportMask information boolean nonRpExported = false; @SuppressWarnings("unchecked") Map<String, Set<UnManagedExportMask>> masksMap = (Map<String, Set<UnManagedExportMask>>) keyMap .get(Constants.UNMANAGED_EXPORT_MASKS_MAP); if (masksMap != null) { Set<UnManagedExportMask> uems = masksMap.get(unManagedVolume.getNativeGuid()); if (uems != null) { _logger.info("{} UnManagedExportMasks found in the keyMap for volume {}", uems.size(), unManagedVolume.getNativeGuid()); for (UnManagedExportMask uem : uems) { boolean backendMaskFound = false; _logger.info(" adding UnManagedExportMask {} to UnManagedVolume", uem.getMaskingViewPath()); unManagedVolume.getUnmanagedExportMasks().add(uem.getId().toString()); uem.getUnmanagedVolumeUris().add(unManagedVolume.getId().toString()); if (!_unManagedExportMasksUpdate.contains(uem)) { _unManagedExportMasksUpdate.add(uem); } // add the known initiators, too for (String initUri : uem.getKnownInitiatorUris()) { _logger.info(" adding known Initiator URI {} to UnManagedVolume", initUri); unManagedVolume.getInitiatorUris().add(initUri); Initiator init = _dbClient.queryObject(Initiator.class, URI.create(initUri)); unManagedVolume.getInitiatorNetworkIds().add(init.getInitiatorPort()); } // log this info for debugging for (String path : uem.getUnmanagedInitiatorNetworkIds()) { _logger.info(" UnManagedExportMask has this initiator unknown to ViPR: {}", path); } // Check if this volume is in an RP mask, and mark it as an RP // volume if it is. Object o = keyMap.get(Constants.UNMANAGED_RECOVERPOINT_MASKS_SET); if (o != null) { Set<String> unmanagedRecoverPointMasks = (Set<String>) o; if (!unmanagedRecoverPointMasks.isEmpty()) { if (unmanagedRecoverPointMasks.contains(uem.getId().toString())) { _logger.info("unmanaged volume {} is an RP volume", unManagedVolume.getLabel()); unManagedVolume.putVolumeCharacterstics( SupportedVolumeCharacterstics.IS_RECOVERPOINT_ENABLED.toString(), "true"); backendMaskFound = true; } } } // check if this volume is in a vplex backend mask // and mark it as such if it is o = keyMap.get(Constants.UNMANAGED_VPLEX_BACKEND_MASKS_SET); if (o != null) { Set<String> unmanagedVplexBackendMasks = (Set<String>) o; if (!unmanagedVplexBackendMasks.isEmpty()) { if (unmanagedVplexBackendMasks.contains(uem.getId().toString())) { _logger.info("unmanaged volume {} is a vplex backend volume", unManagedVolume.getLabel()); unManagedVolume.putVolumeCharacterstics( SupportedVolumeCharacterstics.IS_VPLEX_BACKEND_VOLUME.toString(), "true"); } } } if (!backendMaskFound) { nonRpExported = true; } } } } // If this mask isn't RP, then this volume is exported to a host/cluster/initiator or VPLEX. Mark // this as a convenience to ingest features. if (nonRpExported) { _logger.info("unmanaged volume {} is exported to something other than RP. Marking IS_NONRP_EXPORTED.", unManagedVolume.getLabel()); unManagedVolume.putVolumeCharacterstics( SupportedVolumeCharacterstics.IS_NONRP_EXPORTED.toString(), "true"); } else { _logger.info( "unmanaged volume {} is not exported OR not exported to something other than RP. Not marking IS_NONRP_EXPORTED.", unManagedVolume.getLabel()); unManagedVolume.putVolumeCharacterstics( SupportedVolumeCharacterstics.IS_NONRP_EXPORTED.toString(), "false"); } _logger.debug( "Going to check if the volume is meta: {}, volume meta property: {}", volumeViewInstance.getObjectPath(), unManagedVolume.getVolumeCharacterstics().get( SupportedVolumeCharacterstics.IS_METAVOLUME.toString())); // Check if the volume is meta volume and add it to the meta // volume list String isMetaVolume = unManagedVolume.getVolumeCharacterstics().get( SupportedVolumeCharacterstics.IS_METAVOLUME.toString()); if (null != isMetaVolume && Boolean.valueOf(isMetaVolume)) { if (keyMap.containsKey(Constants.IS_NEW_SMIS_PROVIDER) && Boolean.valueOf(keyMap.get(Constants.IS_NEW_SMIS_PROVIDER).toString())) { metaVolumes.add(volumeViewInstance.getObjectPath()); } else { metaVolumeViews.add(volumeViewInstance.getObjectPath()); } _logger.info("Found meta volume: {}, name: {}", volumeViewInstance.getObjectPath(), unManagedVolume.getLabel()); } // if volumes size reaches 200 , then dump to Db. if (_unManagedVolumesInsert.size() > BATCH_SIZE) { _partitionManager.insertInBatches(_unManagedVolumesInsert, BATCH_SIZE, _dbClient, UNMANAGED_VOLUME); _unManagedVolumesInsert.clear(); } if (_unManagedVolumesUpdate.size() > BATCH_SIZE) { _partitionManager.updateAndReIndexInBatches(_unManagedVolumesUpdate, BATCH_SIZE, _dbClient, UNMANAGED_VOLUME); _unManagedVolumesUpdate.clear(); } if (_unManagedExportMasksUpdate.size() > BATCH_SIZE) { _partitionManager.updateAndReIndexInBatches(_unManagedExportMasksUpdate, BATCH_SIZE, _dbClient, UNMANAGED_EXPORT_MASK); _unManagedExportMasksUpdate.clear(); } unManagedVolumesReturnedFromProvider.add(unManagedVolume.getId()); } catch (Exception ex) { _logger.error("Processing UnManaged Storage Volume {} ", volumeViewInstance.getObjectPath(), ex); } } // Add meta volumes to the keyMap try { if (metaVolumes != null && !metaVolumes.isEmpty()) { _metaVolumePaths.addAll(metaVolumes); _logger.info("Added {} meta volumes.", metaVolumes.size()); } if (metaVolumeViews != null && !metaVolumeViews.isEmpty()) { _metaVolumeViewPaths.addAll(metaVolumeViews); _logger.info("Added {} meta volume views.", metaVolumeViews.size()); } } catch (Exception ex) { _logger.error("Processing UnManaged meta volumes.", ex); } } /** * This method translates volume view cim object path to storage volume * path. Can be used as an alternative to smi-s call to get storage volume * path for volume view, in case there is feasible performance penalty for * using smi-s call for each meta volume view. * * Example: from: //10.247.99.71/root/emc:Symm_VolumeView.SPInstanceID= * "SYMMETRIX+000195701573+C+0005",SVCreationClassName="Symm_StorageVolume", * SVDeviceID * ="004A5",SVSystemCreationClassName="Symm_StorageSystem",SVSystemName * ="SYMMETRIX+000195701573"; }; * * to: //10.247.99.71/root/emc:Symm_StorageVolume.CreationClassName= * "Symm_StorageVolume" * ,DeviceID="004A5",SystemCreationClassName="Symm_StorageSystem", * SystemName="SYMMETRIX+000195701573" * * @param volumeViewPath * @return storageVolume path */ public static CIMObjectPath translateToStorageVolumePath(CIMObjectPath volumeViewPath) { String creationClassName = volumeViewPath.getKey(SVCREATIONCLASSNAME).getValue().toString(); String systemCreationClassName = volumeViewPath.getKey(SVSYSTEMCREATIONCLASSNAME).getValue() .toString(); ; String systemName = volumeViewPath.getKey(SVSYSTEMNAME).getValue().toString(); String id = volumeViewPath.getKey(SVDEVICEID).getValue().toString(); String host = volumeViewPath.getHost(); String namespace = volumeViewPath.getNamespace(); String objectTypeName = creationClassName; CIMProperty[] volumeKeys = { new CIMProperty<String>(SmisConstants.CP_CREATION_CLASS_NAME, CIMDataType.STRING_T, creationClassName, true, false, null), new CIMProperty<String>(SmisConstants.CP_DEVICE_ID, CIMDataType.STRING_T, id, true, false, null), new CIMProperty<String>(SmisConstants.CP_SYSTEM_CREATION_CLASS_NAME, CIMDataType.STRING_T, systemCreationClassName, true, false, null), new CIMProperty<String>(SmisConstants.CP_SYSTEM_NAME, CIMDataType.STRING_T, systemName, true, false, null), }; return new CIMObjectPath(null, host, null, namespace, objectTypeName, volumeKeys); } /** * This method cleans up UnManaged Volumes in DB, which had been deleted * manually from the Array 1. Get All UnManagedVolumes from DB 2. Store URIs * of unmanaged volumes returned from the Provider in * unManagedVolumesBookKeepingList. 3. If unmanaged volume is found only in * DB, but not in unManagedVolumesBookKeepingList, then set unmanaged volume * to inactive. * * DB | Provider * * x,y,z | y,z.a [a --> new entry has been added but indexes didn't get * added yet into DB] * * x--> will be set to inactive * * * * @param storagePoolUri * @throws IOException */ private void performStorageUnManagedVolumeBookKeeping(URI storagePoolUri) throws IOException { @SuppressWarnings("deprecation") List<URI> unManagedVolumesInDB = _dbClient.queryByConstraint(ContainmentConstraint.Factory .getPoolUnManagedVolumeConstraint(storagePoolUri)); Set<URI> unManagedVolumesInDBSet = new HashSet<URI>(unManagedVolumesInDB); SetView<URI> onlyAvailableinDB = Sets.difference(unManagedVolumesInDBSet, unManagedVolumesReturnedFromProvider); _logger.info("Diff :" + Joiner.on("\t").join(onlyAvailableinDB)); if (!onlyAvailableinDB.isEmpty()) { List<UnManagedVolume> unManagedVolumeTobeDeleted = new ArrayList<UnManagedVolume>(); Iterator<UnManagedVolume> unManagedVolumes = _dbClient.queryIterativeObjects( UnManagedVolume.class, new ArrayList<URI>(onlyAvailableinDB)); while (unManagedVolumes.hasNext()) { UnManagedVolume volume = unManagedVolumes.next(); if (null == volume || volume.getInactive()) { continue; } _logger.info("Setting unManagedVolume {} inactive", volume.getId()); volume.setStoragePoolUri(NullColumnValueGetter.getNullURI()); volume.setStorageSystemUri(NullColumnValueGetter.getNullURI()); volume.setInactive(true); unManagedVolumeTobeDeleted.add(volume); } if (!unManagedVolumeTobeDeleted.isEmpty()) { _partitionManager.updateAndReIndexInBatches(unManagedVolumeTobeDeleted, 1000, _dbClient, "UnManagedVolume"); } } } /** * create StorageVolume Info Object * * @param unManagedVolume * @param volumeInstance * @param unManagedVolumeNativeGuid * @param pool * @param system * @param volumeNativeGuid * @param exportedVolumes * @param existingVolumesInCG * @param volumeToRAGroupMap * @param volumeToLocalReplicaMap * @param volumeToSyncAspectMap * @param poolSupportedSLONames * @param keyMap * @param srdfEnabledTargetVPools * @param duplicateSyncAspectElementNameMap * @return */ private UnManagedVolume createUnManagedVolume(UnManagedVolume unManagedVolume, CIMInstance volumeInstance, String unManagedVolumeNativeGuid, StoragePool pool, StorageSystem system, String volumeNativeGuid, Map<String, VolHostIOObject> exportedVolumes, Set<String> existingVolumesInCG, Map<String, RemoteMirrorObject> volumeToRAGroupMap, Map<String, LocalReplicaObject> volumeToLocalReplicaMap, Map<String, Map<String, String>> volumeToSyncAspectMap, Set<String> poolSupportedSLONames, Map<String, Object> keyMap, Set<URI> srdfEnabledTargetVPools, Map<String, Set<String>> duplicateSyncAspectElementNameMap) { _logger.info("Create UnManagedVolume {}", unManagedVolumeNativeGuid); try { String volumeType = Types.REGULAR.toString(); StringSetMap unManagedVolumeInformation = null; Map<String, String> unManagedVolumeCharacteristics = null; boolean created = false; if (null == unManagedVolume) { unManagedVolume = new UnManagedVolume(); unManagedVolume.setId(URIUtil.createId(UnManagedVolume.class)); unManagedVolume.setNativeGuid(unManagedVolumeNativeGuid); unManagedVolume.setStorageSystemUri(system.getId()); created = true; unManagedVolumeInformation = new StringSetMap(); unManagedVolumeCharacteristics = new HashMap<String, String>(); } // reset the auto-tiering info for unmanaged volumes already present // in db // so that the tiering info is updated correctly later if (!created) { unManagedVolume.getVolumeInformation().put( SupportedVolumeInformation.AUTO_TIERING_POLICIES.toString(), ""); unManagedVolume.putVolumeCharacterstics( SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(), "false"); // reset local replica info unManagedVolume.putVolumeCharacterstics(SupportedVolumeCharacterstics.IS_FULL_COPY.name(), FALSE); unManagedVolume.putVolumeCharacterstics(SupportedVolumeCharacterstics.IS_LOCAL_MIRROR.name(), FALSE); unManagedVolume.putVolumeCharacterstics(SupportedVolumeCharacterstics.IS_SNAP_SHOT.name(), FALSE); unManagedVolume.putVolumeCharacterstics(SupportedVolumeCharacterstics.HAS_REPLICAS.name(), FALSE); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.REPLICA_STATE.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.SYNC_STATE.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.SYNC_TYPE.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.SYNCHRONIZED_INSTANCE.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.NEEDS_COPY_TO_TARGET.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.TECHNOLOGY_TYPE.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.SETTINGS_INSTANCE.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.FULL_COPIES.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.MIRRORS.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.SNAPSHOTS.name(), new StringSet()); unManagedVolume.getVolumeInformation().put(SupportedVolumeInformation.SNAPSHOT_SESSIONS.name(), new StringSet()); unManagedVolumeInformation = unManagedVolume.getVolumeInformation(); unManagedVolumeCharacteristics = unManagedVolume.getVolumeCharacterstics(); } if (null != system) { StringSet systemTypes = new StringSet(); systemTypes.add(system.getSystemType()); unManagedVolumeInformation .put(SupportedVolumeInformation.SYSTEM_TYPE.toString(), systemTypes); } if (exportedVolumes != null && exportedVolumes.containsKey(volumeNativeGuid)) { VolHostIOObject obj = exportedVolumes.get(volumeNativeGuid); if (null != obj) { StringSet bwValues = new StringSet(); bwValues.add(obj.getHostIoBw()); if (unManagedVolumeInformation.get(SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH .toString()) == null) { unManagedVolumeInformation.put( SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString(), bwValues); } else { unManagedVolumeInformation.get( SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString()).replace( bwValues); } StringSet iopsVal = new StringSet(); iopsVal.add(obj.getHostIops()); if (unManagedVolumeInformation .get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString()) == null) { unManagedVolumeInformation.put( SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString(), iopsVal); } else { unManagedVolumeInformation .get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString()).replace(iopsVal); } } unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_VOLUME_EXPORTED.toString(), TRUE); } else { unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_VOLUME_EXPORTED.toString(), FALSE); StringSet bwValues = new StringSet(); bwValues.add("0"); if (unManagedVolumeInformation.get(SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH .toString()) == null) { unManagedVolumeInformation.put( SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString(), bwValues); } else { unManagedVolumeInformation.get( SupportedVolumeInformation.EMC_MAXIMUM_IO_BANDWIDTH.toString()).replace(bwValues); } StringSet iopsVal = new StringSet(); iopsVal.add("0"); if (unManagedVolumeInformation.get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString()) == null) { unManagedVolumeInformation.put(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString(), iopsVal); } else { unManagedVolumeInformation.get(SupportedVolumeInformation.EMC_MAXIMUM_IOPS.toString()) .replace(iopsVal); } } // Set Export Mask HLUs @SuppressWarnings("unchecked") Map<String, StringSet> volumeToExportMasksHLUMap = (Map<String, StringSet>) keyMap.get(Constants.UN_VOLUME_EXPORT_MASK_HLUS_MAP); if (volumeToExportMasksHLUMap != null && volumeToExportMasksHLUMap.containsKey(unManagedVolumeNativeGuid)) { unManagedVolumeInformation.put(SupportedVolumeInformation.HLU_TO_EXPORT_MASK_NAME_MAP.toString(), volumeToExportMasksHLUMap.get(unManagedVolumeNativeGuid)); // replace() does not work } // Set SLOName only for VMAX3 exported volumes if (system.checkIfVmax3()) { // If there are no slonames defined for a pool or no slo // set for a volume, update the tiering_enabled to false. if (poolSupportedSLONames.isEmpty() || !keyMap.containsKey(Constants.VOLUMES_WITH_SLOS)) { unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(), Boolean.FALSE.toString()); } else { Map<String, String> volumesWithSLO = (Map<String, String>) keyMap.get(Constants.VOLUMES_WITH_SLOS); if (volumesWithSLO.containsKey(volumeNativeGuid)) { String sloName = volumesWithSLO.get(volumeNativeGuid); _logger.debug("formattedSLOName: {}", sloName); updateSLOPolicies(poolSupportedSLONames, unManagedVolumeInformation, unManagedVolumeCharacteristics, sloName); } else { unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(), Boolean.FALSE.toString()); } } } if (existingVolumesInCG != null && existingVolumesInCG.contains(volumeNativeGuid)) { unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_VOLUME_ADDED_TO_CONSISTENCYGROUP.toString(), TRUE); } else { unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_VOLUME_ADDED_TO_CONSISTENCYGROUP.toString(), FALSE); } // Set the attributes for new smis version. Object raidLevelObj; String isNotIngestableReason; String isBound; String isThinlyProvisioned; String isMetaVolume; String allocCapacity; if (keyMap.containsKey(Constants.IS_NEW_SMIS_PROVIDER) && Boolean.valueOf(keyMap.get(Constants.IS_NEW_SMIS_PROVIDER).toString())) { unManagedVolume.setLabel(getCIMPropertyValue(volumeInstance, "ElementName")); raidLevelObj = volumeInstance.getPropertyValue(SupportedVolumeInformation.RAID_LEVEL .getAlternateKey()); isBound = getCIMPropertyValue(volumeInstance, SupportedVolumeCharacterstics.IS_BOUND.getAlterCharacterstic()); isNotIngestableReason = isVolumeIngestable(volumeInstance, isBound, USAGE, unManagedVolumeNativeGuid, duplicateSyncAspectElementNameMap); isThinlyProvisioned = getCIMPropertyValue(volumeInstance, THINLY_PROVISIONED); isMetaVolume = getCIMPropertyValue(volumeInstance, SupportedVolumeCharacterstics.IS_METAVOLUME.getAlterCharacterstic()); allocCapacity = getAllocatedCapacity(volumeInstance, _volumeToSpaceConsumedMap, system.checkIfVmax3()); } else { unManagedVolume.setLabel(getCIMPropertyValue(volumeInstance, SVELEMENT_NAME)); isBound = getCIMPropertyValue(volumeInstance, SupportedVolumeCharacterstics.IS_BOUND.getCharacterstic()); raidLevelObj = volumeInstance.getPropertyValue(SupportedVolumeInformation.RAID_LEVEL .getInfoKey()); isNotIngestableReason = isVolumeIngestable(volumeInstance, isBound, SVUSAGE, unManagedVolumeNativeGuid, duplicateSyncAspectElementNameMap); isThinlyProvisioned = getCIMPropertyValue(volumeInstance, EMC_THINLY_PROVISIONED); isMetaVolume = getCIMPropertyValue(volumeInstance, SupportedVolumeCharacterstics.IS_METAVOLUME.getCharacterstic()); allocCapacity = getCIMPropertyValue(volumeInstance, EMC_ALLOCATED_CAPACITY); } if (null != raidLevelObj) { StringSet raidLevels = new StringSet(); raidLevels.add(raidLevelObj.toString()); unManagedVolumeInformation.put(SupportedVolumeInformation.RAID_LEVEL.toString(), raidLevels); } if (null != isBound) { unManagedVolumeCharacteristics .put(SupportedVolumeCharacterstics.IS_BOUND.toString(), isBound); } if (null != isThinlyProvisioned) { unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_THINLY_PROVISIONED.toString(), isThinlyProvisioned); } if (null != isMetaVolume) { unManagedVolumeCharacteristics .put(SupportedVolumeCharacterstics.IS_METAVOLUME.toString(), isMetaVolume); } // only Volumes with Usage 2 can be ingestable, other volumes // [SAVE,VAULT...] apart from replicas have usage other than 2 // Volumes which are set EMCIsBound as false cannot be ingested if (isNotIngestableReason == null) { unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.IS_INGESTABLE.toString(), TRUE); } else { unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.IS_INGESTABLE.toString(), FALSE); unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.IS_NOT_INGESTABLE_REASON.toString(), isNotIngestableReason); } if (volumeToRAGroupMap.containsKey(unManagedVolume.getNativeGuid())) { RemoteMirrorObject rmObj = volumeToRAGroupMap.get(unManagedVolume.getNativeGuid()); _logger.info("Found RA Object {}", rmObj.toString()); if (RemoteMirrorObject.Types.SOURCE.toString().equalsIgnoreCase(rmObj.getType())) { _logger.info("Found Source, updating targets {}", rmObj.getTargetVolumenativeGuids()); // setting target Volumes if (unManagedVolumeInformation.get(SupportedVolumeInformation.REMOTE_MIRRORS.toString()) == null) { unManagedVolumeInformation.put(SupportedVolumeInformation.REMOTE_MIRRORS.toString(), rmObj.getTargetVolumenativeGuids()); } else { if (null == rmObj.getTargetVolumenativeGuids() || rmObj.getTargetVolumenativeGuids().isEmpty()) { unManagedVolumeInformation.get( SupportedVolumeInformation.REMOTE_MIRRORS.toString()).clear(); } else { unManagedVolumeInformation.get( SupportedVolumeInformation.REMOTE_MIRRORS.toString()).replace( rmObj.getTargetVolumenativeGuids()); } } volumeType = Types.SOURCE.toString(); } else if (RemoteMirrorObject.Types.TARGET.toString().equalsIgnoreCase(rmObj.getType())) { _logger.info("Found Target {}, updating copyMode {}, RA Group", unManagedVolume.getNativeGuid(), rmObj.getCopyMode()); // setting srdfParent StringSet parentVolume = new StringSet(); parentVolume.add(rmObj.getSourceVolumeNativeGuid()); unManagedVolumeInformation.put( SupportedVolumeInformation.REMOTE_MIRROR_SOURCE_VOLUME.toString(), parentVolume); // setting RAGroup StringSet raGroup = new StringSet(); // set Source array's RA group URI in Target volume if (rmObj.getTargetRaGroupUri() != null) { raGroup.add(rmObj.getTargetRaGroupUri().toString()); } else { _logger.warn("Source Array's RA Group is not populated. Check if Source array is discovered." + " Target: {}", unManagedVolume.getNativeGuid()); } volumeType = Types.TARGET.toString(); unManagedVolumeInformation.put( SupportedVolumeInformation.REMOTE_MIRROR_RDF_GROUP.toString(), raGroup); } // setting Copy Modes StringSet copyModes = new StringSet(); copyModes.add(rmObj.getCopyMode()); if (unManagedVolumeInformation.get(SupportedVolumeInformation.REMOTE_COPY_MODE.toString()) == null) { unManagedVolumeInformation.put(SupportedVolumeInformation.REMOTE_COPY_MODE.toString(), copyModes); } else { unManagedVolumeInformation.get(SupportedVolumeInformation.REMOTE_COPY_MODE.toString()) .replace(copyModes); } // setting Volume Type StringSet remoteVolumeType = new StringSet(); remoteVolumeType.add(rmObj.getType()); unManagedVolumeInformation.put(SupportedVolumeInformation.REMOTE_VOLUME_TYPE.toString(), remoteVolumeType); unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.REMOTE_MIRRORING.toString(), TRUE); } else { unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.REMOTE_MIRRORING.toString(), FALSE); } // handle clones, local mirrors and snapshots boolean isLocalReplica = false; if (volumeToLocalReplicaMap.containsKey(unManagedVolume.getNativeGuid())) { _logger.info("Found in localReplicaMap {}", unManagedVolume.getNativeGuid()); LocalReplicaObject lrObj = volumeToLocalReplicaMap .get(unManagedVolume.getNativeGuid()); isLocalReplica = lrObj.isReplica(); // setting targets StringSet fullCopies = lrObj.getFullCopies(); if (fullCopies != null && !fullCopies.isEmpty()) { unManagedVolumeInformation.put(SupportedVolumeInformation.FULL_COPIES.name(), fullCopies); } StringSet mirrors = lrObj.getMirrors(); if (mirrors != null && !mirrors.isEmpty()) { unManagedVolumeInformation.put(SupportedVolumeInformation.MIRRORS.name(), mirrors); } StringSet snapshots = lrObj.getSnapshots(); if (snapshots != null && !snapshots.isEmpty()) { unManagedVolumeInformation.put(SupportedVolumeInformation.SNAPSHOTS.name(), snapshots); } if (lrObj.hasReplica()) { // set the HAS_REPLICAS property unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.HAS_REPLICAS.name(), TRUE); } if (LocalReplicaObject.Types.FullCopy.equals(lrObj .getType())) { _logger.info("Found Clone {}", unManagedVolume.getNativeGuid()); // setting clone specific info unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.IS_FULL_COPY.name(), TRUE); StringSet sourceVolume = new StringSet(); sourceVolume.add(lrObj.getSourceNativeGuid()); unManagedVolumeInformation.put( SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME .name(), sourceVolume); StringSet isSyncActive = new StringSet(); isSyncActive.add(new Boolean(lrObj.isSyncActive()) .toString()); unManagedVolumeInformation.put( SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), isSyncActive); StringSet replicaState = new StringSet(); replicaState.add(lrObj.getReplicaState()); unManagedVolumeInformation.put( SupportedVolumeInformation.REPLICA_STATE .name(), replicaState); } else if (LocalReplicaObject.Types.BlockMirror.equals(lrObj .getType())) { _logger.info("Found Local Mirror {}", unManagedVolume.getNativeGuid()); // setting local mirror specific info unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.IS_LOCAL_MIRROR.name(), TRUE); StringSet sourceVolume = new StringSet(); sourceVolume.add(lrObj.getSourceNativeGuid()); unManagedVolumeInformation .put(SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME .name(), sourceVolume); StringSet syncState = new StringSet(); syncState.add(lrObj.getSyncState()); unManagedVolumeInformation.put( SupportedVolumeInformation.SYNC_STATE.name(), syncState); StringSet syncType = new StringSet(); syncType.add(lrObj.getSyncType()); unManagedVolumeInformation.put( SupportedVolumeInformation.SYNC_TYPE.name(), syncType); String syncedInst = lrObj.getSynchronizedInstance(); if (syncedInst != null) { StringSet synchronizedInstance = new StringSet(); synchronizedInstance.add(syncedInst); unManagedVolumeInformation.put( SupportedVolumeInformation.SYNCHRONIZED_INSTANCE .name(), synchronizedInstance); } } else if (LocalReplicaObject.Types.BlockSnapshot.equals(lrObj .getType())) { _logger.info("Found Snapshot {}", unManagedVolume.getNativeGuid()); // setting snapshot specific info unManagedVolumeCharacteristics.put(SupportedVolumeCharacterstics.IS_SNAP_SHOT.name(), TRUE); StringSet sourceVolume = new StringSet(); sourceVolume.add(lrObj.getSourceNativeGuid()); unManagedVolumeInformation .put(SupportedVolumeInformation.LOCAL_REPLICA_SOURCE_VOLUME .name(), sourceVolume); StringSet isSyncActive = new StringSet(); isSyncActive.add(new Boolean(lrObj.isSyncActive()) .toString()); unManagedVolumeInformation.put( SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), isSyncActive); StringSet needsCopyToTarget = new StringSet(); needsCopyToTarget.add(new Boolean(lrObj .isNeedsCopyToTarget()).toString()); unManagedVolumeInformation.put( SupportedVolumeInformation.NEEDS_COPY_TO_TARGET .name(), needsCopyToTarget); StringSet technologyType = new StringSet(); technologyType.add(lrObj.getTechnologyType()); unManagedVolumeInformation.put( SupportedVolumeInformation.TECHNOLOGY_TYPE .name(), technologyType); String settingsInst = lrObj.getSettingsInstance(); if (settingsInst != null) { StringSet settingsInstance = new StringSet(); settingsInstance.add(settingsInst); unManagedVolumeInformation.put( SupportedVolumeInformation.SETTINGS_INSTANCE .name(), settingsInstance); } } } // Array snapshot sessions for which the volume is the source. if (volumeToSyncAspectMap.containsKey(unManagedVolume.getNativeGuid())) { _logger.info("Found in SyncAspectMap {}", unManagedVolume.getNativeGuid()); StringSet syncAspectInfoForForVolume = new StringSet(); Map<String, String> syncAspectMap = volumeToSyncAspectMap.get(unManagedVolume.getNativeGuid()); for (String syncAspectKey : syncAspectMap.keySet()) { String syncAspectName = syncAspectKey.split(Constants.COLON)[1]; String syncAspectObjPath = syncAspectMap.get(syncAspectKey); String syncAspectInfo = syncAspectName + Constants.COLON + syncAspectObjPath; syncAspectInfoForForVolume.add(syncAspectInfo); } unManagedVolumeInformation.put(SupportedVolumeInformation.SNAPSHOT_SESSIONS.name(), syncAspectInfoForForVolume); } // set volume's isSyncActive if (!isLocalReplica) { StringSet isSyncActive = new StringSet(); isSyncActive.add(TRUE); unManagedVolumeInformation.put( SupportedVolumeInformation.IS_SYNC_ACTIVE.name(), isSyncActive); } if (null != pool) { unManagedVolume.setStoragePoolUri(pool.getId()); StringSet pools = new StringSet(); pools.add(pool.getId().toString()); unManagedVolumeInformation.put(SupportedVolumeInformation.STORAGE_POOL.toString(), pools); StringSet driveTypes = pool.getSupportedDriveTypes(); if (null != driveTypes) { unManagedVolumeInformation.put(SupportedVolumeInformation.DISK_TECHNOLOGY.toString(), driveTypes); } StringSet matchedVPools = DiscoveryUtils.getMatchedVirtualPoolsForPool(_dbClient, pool .getId(), unManagedVolumeCharacteristics .get(SupportedVolumeCharacterstics.IS_THINLY_PROVISIONED.toString()), srdfEnabledTargetVPools, null, volumeType, unManagedVolume); _logger.debug("Matched Pools : {}", Joiner.on("\t").join(matchedVPools)); if (null == matchedVPools || matchedVPools.isEmpty()) { // clear all existing supported vpools. unManagedVolume.getSupportedVpoolUris().clear(); } else { // replace with new StringSet unManagedVolume.getSupportedVpoolUris().replace(matchedVPools); _logger.info("Replaced Pools :" + Joiner.on("\t").join(unManagedVolume.getSupportedVpoolUris())); } } // set allocated capacity if (allocCapacity != null) { StringSet allocCapacitySet = new StringSet(); allocCapacitySet.add(allocCapacity); unManagedVolumeInformation.put(SupportedVolumeInformation.ALLOCATED_CAPACITY.toString(), allocCapacitySet); } StringSet provCapacity = new StringSet(); provCapacity.add(String.valueOf(returnProvisionedCapacity(volumeInstance, keyMap))); unManagedVolumeInformation.put(SupportedVolumeInformation.PROVISIONED_CAPACITY.toString(), provCapacity); injectVolumeInformation(unManagedVolume, volumeInstance, unManagedVolumeInformation); injectVolumeCharacterstics(unManagedVolume, volumeInstance, unManagedVolumeCharacteristics); unManagedVolume.getUnmanagedExportMasks().clear(); unManagedVolume.getInitiatorUris().clear(); unManagedVolume.getInitiatorNetworkIds().clear(); Object wwn = getCIMPropertyValue(volumeInstance, SmisConstants.CP_WWN_NAME_ALT); if (null == wwn) { wwn = getCIMPropertyValue(volumeInstance, SmisConstants.CP_WWN_NAME); } unManagedVolume.setWwn(String.valueOf(wwn)); if (created) { _unManagedVolumesInsert.add(unManagedVolume); } else { _unManagedVolumesUpdate.add(unManagedVolume); } } catch (Exception e) { _logger.error("Exception: ", e); } return unManagedVolume; } /** * Update the SLO policy Name for VMAX3 volumes. * * @param poolSupportedSLONames * - Pool Supported SLO Names * @param unManagedVolumeInformation * - UnManaged Volume Information * @param unManagedVolumeCharacteristics * - UnManaged Volume characteristics. * @param sgSLOName * - Volume supported SLO Name. */ private void updateSLOPolicies(Set<String> poolSupportedSLONames, StringSetMap unManagedVolumeInformation, Map<String, String> unManagedVolumeCharacteristics, String sgSLOName) { if (null != poolSupportedSLONames && !poolSupportedSLONames.isEmpty()) { StringSet sloNamesSet = new StringSet(); for (String poolSLOName : poolSupportedSLONames) { if (null != sgSLOName && poolSLOName.contains(sgSLOName)) { // This condition will filter out the pool SLO's which // contains Workload when sgSLOName contains // just SLO. if (!sgSLOName.contains(Constants.WORKLOAD) && poolSLOName.contains(Constants.WORKLOAD)) { continue; } sloNamesSet.add(poolSLOName); _logger.info("found a matching slo: {}", poolSLOName); break; } } if (!sloNamesSet.isEmpty()) { unManagedVolumeInformation.put(SupportedVolumeInformation.AUTO_TIERING_POLICIES.toString(), sloNamesSet); unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(), Boolean.TRUE.toString()); } else { _logger.warn("StorageGroup SLOName is not found in Pool settings."); unManagedVolumeCharacteristics.put( SupportedVolumeCharacterstics.IS_AUTO_TIERING_ENABLED.toString(), Boolean.FALSE.toString()); } } } /** * Only Volumes with Usage 2 can be ingested, other volumes apart from * replicas have usage other than 2. Volumes which are set EMCSVIsBound as * false cannot be ingested * * @param volumeInstance A reference to the CIM instance representing the volume. * @param isBound true if the volume is bound, false otherwise. * @param usageProp The name of the SMI-S usage property for the provider managing the volume. * @param unManagedVolumeNativeGuid The native GUID for the discovered unmanaged volume. * @param duplicateSyncAspectElementNameMap A map specifying the names that are used by multiple * synchronization aspects for the discovered unmanaged volumes. * * @return A string indicating why the volume in not ingestable, else null. */ private String isVolumeIngestable(CIMInstance volumeInstance, String isBound, String usageProp, String unManagedVolumeNativeGuid, Map<String, Set<String>> duplicateSyncAspectElementNameMap) { String usage = getCIMPropertyValue(volumeInstance, usageProp); if (!Boolean.valueOf(isBound)) { return "The volume is not ingestable because it is not bound and the controller only supports bound volumes"; } if (!(TWO.equalsIgnoreCase(usage) || NINE.equalsIgnoreCase(usage) || SEVEN.equalsIgnoreCase(usage) || ELEVEN.equalsIgnoreCase(usage) || USAGE_LOCAL_REPLICA_TARGET.equalsIgnoreCase(usage) || USAGE_DELTA_REPLICA_TARGET.equalsIgnoreCase(usage) || USGAE_LOCAL_REPLICA_SOURCE.equalsIgnoreCase(usage) || USAGE_LOCAL_REPLICA_SOURCE_OR_TARGET.equalsIgnoreCase(usage))) { return "The volume is not ingestable because it has a usage that is not supported by the controller"; } // ViPR currently requires array snapshots to have unique names. In most cases this // is the case. However, with the support of SnapVx for VMAX3, array snapshots can // have the same name, and they are distinguished by a unique generation identifier. // As such, any volume that has array snapshots using the same name cannot be ingested // into ViPR as the array snapshots are not supported in ViPR. If these array // snapshots have associated target volumes, then the associated target volumes would // not be ingestable and because they are not ingestable, the source volume would also // not be ingestable. Code in VolumeDiscoveryPostProcessor prevents these target volumes // from being ingested, and the general ingestion mechanism prevents a source from being // ingested if its replicas are not ingested. However if there are no associated target // volumes for these array snapshots, then there is nothing to prevent the source volume // from being ingested. Because these array snapshot sessions are not supported, they do // not appear in the list of snapshots(i.e., sync aspects) for the volume, and it would // just appear as a volume with no snapshots and it would be ingestable. This check // ensures the volume will not be ingestable if we discovered any array snapshots for // the unmanaged source volume that reuse a name. boolean hasUnsupportedSnapshotSessions = false; if (duplicateSyncAspectElementNameMap.containsKey(unManagedVolumeNativeGuid)) { Set<String> duplicateSyncAspectElementNames = duplicateSyncAspectElementNameMap.get(unManagedVolumeNativeGuid); if ((duplicateSyncAspectElementNames != null) && (!duplicateSyncAspectElementNames.isEmpty())) { hasUnsupportedSnapshotSessions = true; } } if (hasUnsupportedSnapshotSessions) { return "The volume is not ingestable because it has multiple array snapshots with the same name, " + "which is not supported by the controller. The storage system may use generation numbers " + "to differentiate these snapshots, and the controller does not currently support generation numbers"; } return null; } @Override protected void setPrerequisiteObjects(List<Object> inputArgs) throws BaseCollectionException { _args = inputArgs; } }