/* * Copyright 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.utils; import java.io.IOException; import java.net.URI; import java.util.ArrayList; 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.CIMObjectPath; import javax.wbem.CloseableIterator; import javax.wbem.WBEMException; import javax.wbem.client.WBEMClient; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.constraint.AlternateIdConstraint; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.AutoTieringPolicy.HitachiTieringPolicy; import com.emc.storageos.db.client.model.AutoTieringPolicy.VnxFastPolicy; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.DiscoveredDataObject; import com.emc.storageos.db.client.model.ObjectNamespace; import com.emc.storageos.db.client.model.ProtectionSet; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StoragePort; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.VirtualNAS; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedConsistencyGroup; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedExportMask; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedProtectionSet; 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.CustomQueryUtility; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.plugins.common.PartitionManager; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.StoragePoolAssociationHelper; import com.emc.storageos.vplexcontroller.VplexBackendIngestionContext; import com.google.common.base.Joiner; import com.google.common.collect.Sets; import com.google.common.collect.Sets.SetView; public class DiscoveryUtils { private static final Logger _log = LoggerFactory.getLogger(DiscoveryUtils.class); public static final String UNMANAGED_EXPORT_MASK = "UnManagedExportMask"; public static final String UNMANAGED_VOLUME = "UnManagedVolume"; public static final String UNMANAGED_CONSISTENCY_GROUP = "UnManagedConsistencyGroup"; private static final String TRUE = "true"; /** * get Matched Virtual Pools For Pool. * This is called to calculate supported vpools during unmanaged objects discovery * * @param dbClient db client * @param poolUri storage pool * @param isThinlyProvisionedUnManagedObject is this thin provisioned? * @param srdfProtectedVPoolUris srdf protected vpools * @param rpProtectedVPoolUris RP protected vpools * @param volumeType type of volume * @param unManagedVolume the unManagedVolume being matched, if provided and the volume * is a VPLEX backend volume, the parent matched vpools will be added * @return a StringSet of matched VirtualPool URIs */ public static StringSet getMatchedVirtualPoolsForPool(DbClient dbClient, URI poolUri, String isThinlyProvisionedUnManagedObject, Set<URI> srdfProtectedVPoolUris, Set<URI> rpProtectedVPoolUris, String volumeType, UnManagedVolume unManagedVolume) { StringSet vpoolUriSet = new StringSet(); // We should match all virtual pools as below: // 1) Virtual pools which have useMatchedPools set to true and have the storage pool in their matched pools // 2) Virtual pools which have the storage pool in their assigned pools List<VirtualPool> vPoolsMatchedPools = getMatchedVPoolsOfAPool(poolUri, dbClient); String provisioningTypeUnManagedObject = UnManagedVolume.SupportedProvisioningType .getProvisioningType(isThinlyProvisionedUnManagedObject); StoragePool storagePool = dbClient.queryObject(StoragePool.class, poolUri); for (VirtualPool vPool : vPoolsMatchedPools) { if (!VirtualPool.vPoolSpecifiesHighAvailability(vPool)) { // if the volume is srdf target volume, then the vpool should have a relation to its source vpool. // Cases to skip the vpool // 1. If volume is SRDF Target volume but the vpool is not SRDF Protected. // 2. If the volume is regular volume but the vpool is SRDF protected either source/target. // 3. If the volume is SRDF Source volume but the vpool is SRDF target volume. boolean srdfVolNoMatchingVpool = Types.isTargetVolume(Types.valueOf(volumeType)) && !srdfProtectedVPoolUris.contains(vPool.getId()); boolean isSRDFSourceVpool = (null != vPool.getProtectionRemoteCopySettings() && !vPool .getProtectionRemoteCopySettings().isEmpty()); boolean regularVolWithSRDFVpool = Types.isRegularVolume(Types.valueOf(volumeType)) && (srdfProtectedVPoolUris.contains(vPool.getId()) || isSRDFSourceVpool); boolean srdfSourceWithTargetVpool = Types.isSourceVolume(Types.valueOf(volumeType)) && srdfProtectedVPoolUris.contains(vPool.getId()); if (srdfVolNoMatchingVpool || regularVolWithSRDFVpool || srdfSourceWithTargetVpool) { _log.debug( "Skipping vpool {} srdfVolNoMatchingVpool: {} regularVolWithSRDFVpool: {} srdfSourceWithTargetVpool:{}", new Object[] { vPool.getLabel(), srdfVolNoMatchingVpool, regularVolWithSRDFVpool, srdfSourceWithTargetVpool }); continue; } List<StoragePool> validPools = VirtualPool.getValidStoragePools(vPool, dbClient, true); for (StoragePool sPool : validPools) { if (sPool.getId().equals(storagePool.getId()) && provisioningTypeUnManagedObject.equalsIgnoreCase(vPool.getSupportedProvisioningType())) { vpoolUriSet.add(vPool.getId().toString()); break; } } } } addParentMatchedVpoolsIfVplexBackendVolume(unManagedVolume, vpoolUriSet, dbClient); return vpoolUriSet; } /** * Get Matched Virtual Pools For Pool. * This is called to calculate supported vpools during unmanaged objects discovery * * @param dbClient * @param poolUri * @param isThinlyProvisionedUnManagedObject * @return a StringSet of matched VirtualPool URIs */ public static StringSet getMatchedVirtualPoolsForPool(DbClient dbClient, URI poolUri, String isThinlyProvisionedUnManagedObject) { StringSet vpoolUriSet = new StringSet(); // We should match all virtual pools as below: // 1) Virtual pools which have useMatchedPools set to true and have the storage pool in their matched pools // 2) Virtual pools which have the storage pool in their assigned pools List<VirtualPool> vPoolsMatchedPools = getMatchedVPoolsOfAPool(poolUri, dbClient); String provisioningTypeUnManagedObject = UnManagedVolume.SupportedProvisioningType .getProvisioningType(isThinlyProvisionedUnManagedObject); StoragePool storagePool = dbClient.queryObject(StoragePool.class, poolUri); for (VirtualPool vPool : vPoolsMatchedPools) { if (!VirtualPool.vPoolSpecifiesHighAvailability(vPool)) { List<StoragePool> validPools = VirtualPool.getValidStoragePools(vPool, dbClient, true); for (StoragePool sPool : validPools) { if (sPool.getId().equals(storagePool.getId()) && provisioningTypeUnManagedObject.equalsIgnoreCase(vPool.getSupportedProvisioningType())) { vpoolUriSet.add(vPool.getId().toString()); break; } } } } return vpoolUriSet; } /** * Get Matched Virtual Pools For Pool. * This is called to calculate supported vpools during unmanaged objects discovery * * @param dbClient * @param poolUri * @param isThinlyProvisionedUnManagedObject * @param unManagedVolume the unManagedVolume being matched, if provided and the volume * is a VPLEX backend volume, the parent matched vpools will be added * @return a StringSet of matched VirtualPool URIs */ public static StringSet getMatchedVirtualPoolsForPool(DbClient dbClient, URI poolUri, String isThinlyProvisionedUnManagedObject, UnManagedVolume unManagedVolume) { StringSet vpoolUriSet = getMatchedVirtualPoolsForPool(dbClient, poolUri, isThinlyProvisionedUnManagedObject); addParentMatchedVpoolsIfVplexBackendVolume(unManagedVolume, vpoolUriSet, dbClient); return vpoolUriSet; } // Getting all the vpools public static StringSet getMatchedVirtualPoolsForPool(DbClient dbClient, URI poolUri) { StringSet vpoolUriSet = new StringSet(); // We should match all virtual pools as below: // 1) Virtual pools which have useMatchedPools set to true and have the storage pool in their matched pools // 2) Virtual pools which have the storage pool in their assigned pools List<VirtualPool> vPoolsMatchedPools = getMatchedVPoolsOfAPool(poolUri, dbClient); StoragePool storagePool = dbClient.queryObject(StoragePool.class, poolUri); for (VirtualPool vPool : vPoolsMatchedPools) { List<StoragePool> validPools = VirtualPool.getValidStoragePools(vPool, dbClient, true); for (StoragePool sPool : validPools) { if (sPool.getId().equals(storagePool.getId())) { vpoolUriSet.add(vPool.getId().toString()); break; } } } return vpoolUriSet; } /** * Add any matched virtual pools in the parent volume if the unManagedVolume is * a VPLEX backend volume. * * @param volume the UnManagedVolume in question * @param matchedVPools the StringSet of vpool URIs to add to * @param dbClient a reference to the database client */ public static void addParentMatchedVpoolsIfVplexBackendVolume( UnManagedVolume unManagedVolume, StringSet matchedVPools, DbClient dbClient) { if (null == unManagedVolume || null == unManagedVolume.getVolumeCharacterstics()) { return; } String status = unManagedVolume.getVolumeCharacterstics() .get(SupportedVolumeCharacterstics.IS_VPLEX_BACKEND_VOLUME.toString()); if (TRUE.equals(status)) { String vplexParentVolume = VplexBackendIngestionContext.extractValueFromStringSet( SupportedVolumeInformation.VPLEX_PARENT_VOLUME.toString(), unManagedVolume.getVolumeInformation()); if (StringUtils.isNotEmpty(vplexParentVolume)) { URIQueryResultList unManagedVolumeList = new URIQueryResultList(); dbClient.queryByConstraint(AlternateIdConstraint.Factory .getVolumeInfoNativeIdConstraint(vplexParentVolume), unManagedVolumeList); if (unManagedVolumeList.iterator().hasNext()) { UnManagedVolume parentVolume = dbClient.queryObject(UnManagedVolume.class, unManagedVolumeList.iterator().next()); StringSet parentMatchedPools = parentVolume.getSupportedVpoolUris(); if (parentMatchedPools != null && !parentMatchedPools.isEmpty()) { _log.info("Adding the following matched vpools from VPLEX parent volume {} to backend volume {}: {}", parentVolume.getLabel(), unManagedVolume.getLabel(), parentMatchedPools); matchedVPools.addAll(parentMatchedPools); } } } } } /** * Filters supported vPools in UnManaged Volume based on Auto-Tiering Policy. * * @param unManagedVolume the UnManaged volume * @param policyName the policy name associated with UnManaged volume * @param system the system * @param dbClient the db client */ public static void filterSupportedVpoolsBasedOnTieringPolicy( UnManagedVolume unManagedVolume, String policyName, StorageSystem system, DbClient dbClient) { StringSet supportedVpoolURIs = unManagedVolume.getSupportedVpoolUris(); List<String> vPoolsToRemove = new ArrayList<String>(); if (supportedVpoolURIs != null) { Iterator<String> itr = supportedVpoolURIs.iterator(); while (itr.hasNext()) { String uri = itr.next(); VirtualPool vPool = dbClient.queryObject(VirtualPool.class, URI.create(uri)); if (vPool != null && !vPool.getInactive()) { // generate unmanaged volume's policyId String autoTierPolicyId = NativeGUIDGenerator .generateAutoTierPolicyNativeGuid(system.getNativeGuid(), policyName, NativeGUIDGenerator.getTieringPolicyKeyForSystem(system)); if (!checkVPoolValidForUnManagedVolumeAutoTieringPolicy(vPool, autoTierPolicyId, system)) { String msg = "Removing vPool %s from SUPPORTED_VPOOL_LIST in UnManagedVolume %s " + "since Auto-tiering Policy %s in UnManaged Volume does not match with vPool's (%s)"; _log.info(String.format(msg, new Object[] { uri, unManagedVolume.getId(), autoTierPolicyId, vPool.getAutoTierPolicyName() })); vPoolsToRemove.add(uri); } } else { // remove Inactive vPool URI vPoolsToRemove.add(uri); } } } for (String uri : vPoolsToRemove) { // UnManagedVolume object is persisted by caller supportedVpoolURIs.remove(uri); } } /** * Checks the UnManaged Volume's policy with vPool's policy. * * @param vPool the vPool * @param autoTierPolicyId the auto tier policy id on unmanaged volume * @param system the system * @return true, if matching, false otherwise */ public static boolean checkVPoolValidForUnManagedVolumeAutoTieringPolicy( VirtualPool vPool, String autoTierPolicyId, StorageSystem system) { _log.debug("Policy Id: {}, vPool: {}", autoTierPolicyId, vPool); boolean policyMatching = false; String policyIdfromVPool = vPool.getAutoTierPolicyName(); if (autoTierPolicyId != null) { if (policyIdfromVPool != null) { if (vPool.getUniquePolicyNames() || DiscoveredDataObject.Type.vnxblock.name().equalsIgnoreCase(system.getSystemType())) { // Unique Policy names field will not be set for VNX. vPool will have policy name, not the policy's nativeGuid policyIdfromVPool = NativeGUIDGenerator .generateAutoTierPolicyNativeGuid(system.getNativeGuid(), policyIdfromVPool, NativeGUIDGenerator.getTieringPolicyKeyForSystem(system)); _log.debug("Policy Id generated: {}", policyIdfromVPool); } if (autoTierPolicyId.equalsIgnoreCase(policyIdfromVPool)) { policyMatching = true; } } } else if ((policyIdfromVPool == null) || (policyIdfromVPool.equalsIgnoreCase("none"))) { // if policy is not set in both unmanaged volume and vPool. Note // that the value in the vpool could be set to "none". policyMatching = true; } // Default policy for VNX - match volume with default policy to vPool with no policy as well if (!policyMatching && DiscoveredDataObject.Type.vnxblock.name().equalsIgnoreCase(system.getSystemType())) { if (autoTierPolicyId != null && autoTierPolicyId.contains(VnxFastPolicy.DEFAULT_START_HIGH_THEN_AUTOTIER.name()) && policyIdfromVPool == null) { policyMatching = true; } } // Default policy for HDS - match volume with default policy to vPool with no policy as well if (!policyMatching && DiscoveredDataObject.Type.hds.name().equalsIgnoreCase(system.getSystemType())) { if (autoTierPolicyId != null && autoTierPolicyId.contains(HitachiTieringPolicy.All.name()) && policyIdfromVPool == null) { policyMatching = true; } } return policyMatching; } public static void setSystemResourcesIncompatible(DbClient dbClient, CoordinatorClient coordinator, URI storageSystemId) { // Mark all Pools as incompatible URIQueryResultList storagePoolURIs = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getStorageDeviceStoragePoolConstraint(storageSystemId), storagePoolURIs); Iterator<URI> storagePoolIter = storagePoolURIs.iterator(); List<StoragePool> modifiedPools = new ArrayList<StoragePool>(); while (storagePoolIter.hasNext()) { StoragePool pool = dbClient.queryObject(StoragePool.class, storagePoolIter.next()); if (pool.getInactive()) { continue; } modifiedPools.add(pool); pool.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.INCOMPATIBLE.name()); dbClient.updateObject(pool); } StringBuffer errorMessage = new StringBuffer(); ImplicitPoolMatcher.matchModifiedStoragePoolsWithAllVirtualPool(modifiedPools, dbClient, coordinator, errorMessage); // Mark all Ports as incompatible URIQueryResultList storagePortURIs = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(storageSystemId), storagePortURIs); Iterator<URI> storagePortIter = storagePortURIs.iterator(); while (storagePortIter.hasNext()) { StoragePort port = dbClient.queryObject(StoragePort.class, storagePortIter.next()); if (port.getInactive()) { continue; } port.setCompatibilityStatus(DiscoveredDataObject.CompatibilityStatus.INCOMPATIBLE.name()); dbClient.updateObject(port); } } public static List<StoragePool> checkStoragePoolsNotVisible(List<StoragePool> discoveredPools, DbClient dbClient, URI storageSystemId) { List<StoragePool> modifiedPools = new ArrayList<StoragePool>(); // Get the pools previously discovered URIQueryResultList storagePoolURIs = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getStorageDeviceStoragePoolConstraint(storageSystemId), storagePoolURIs); Iterator<URI> storagePoolIter = storagePoolURIs.iterator(); List<URI> existingPoolsURI = new ArrayList<URI>(); while (storagePoolIter.hasNext()) { existingPoolsURI.add(storagePoolIter.next()); } List<URI> discoveredPoolsURI = new ArrayList<URI>(); for (StoragePool pool : discoveredPools) { discoveredPoolsURI.add(pool.getId()); } Set<URI> poolDiff = Sets.difference(new HashSet<URI>(existingPoolsURI), new HashSet<URI>(discoveredPoolsURI)); if (!poolDiff.isEmpty()) { Iterator<StoragePool> storagePoolIt = dbClient.queryIterativeObjects(StoragePool.class, poolDiff, true); while (storagePoolIt.hasNext()) { StoragePool pool = storagePoolIt.next(); modifiedPools.add(pool); _log.info("Setting discovery status of pool {} : {} as NOTVISIBLE", pool.getLabel(), pool.getId()); pool.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.NOTVISIBLE.name()); dbClient.persistObject(pool); } } return modifiedPools; } public static List<StoragePort> checkStoragePortsNotVisible(List<StoragePort> discoveredPorts, DbClient dbClient, URI storageSystemId) { List<StoragePort> modifiedPorts = new ArrayList<StoragePort>(); // Get the pools previousy discovered URIQueryResultList storagePortURIs = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(storageSystemId), storagePortURIs); Iterator<URI> storagePortIter = storagePortURIs.iterator(); List<URI> existingPortsURI = new ArrayList<URI>(); while (storagePortIter.hasNext()) { existingPortsURI.add(storagePortIter.next()); } List<URI> discoveredPortsURI = new ArrayList<URI>(); for (StoragePort port : discoveredPorts) { discoveredPortsURI.add(port.getId()); } Set<URI> portsDiff = Sets.difference(new HashSet<URI>(existingPortsURI), new HashSet<URI>(discoveredPortsURI)); if (!portsDiff.isEmpty()) { Iterator<StoragePort> storagePortIt = dbClient.queryIterativeObjects(StoragePort.class, portsDiff, true); while (storagePortIt.hasNext()) { StoragePort port = storagePortIt.next(); modifiedPorts.add(port); _log.info("Setting discovery status of port {} : {} as NOTVISIBLE", port.getLabel(), port.getId()); port.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.NOTVISIBLE.name()); dbClient.persistObject(port); } } return modifiedPorts; } public static void checkStoragePortsNotVisibleForSMI(List<StoragePort> discoveredPorts, Set<URI> systemsToRunRPConnectivity, List<StoragePort> portsToRunNetworkConnectivity, Map<URI, StoragePool> poolsToMatchWithVpool, DbClient dbClient, URI storageSystemId) { List<StoragePort> notVisiblePorts = checkStoragePortsNotVisible(discoveredPorts, dbClient, storageSystemId); // Systems used to run RP connectivity later after runing pool matcher if (systemsToRunRPConnectivity != null) { systemsToRunRPConnectivity.addAll(StoragePoolAssociationHelper.getStorageSytemsFromPorts(notVisiblePorts, null)); } if (poolsToMatchWithVpool != null) { List<StoragePool> modifiedPools = StoragePoolAssociationHelper.getStoragePoolsFromPorts(dbClient, null, notVisiblePorts); for (StoragePool pool : modifiedPools) { // pool matcher will be invoked on this pool if (!poolsToMatchWithVpool.containsKey(pool.getId())) { poolsToMatchWithVpool.put(pool.getId(), pool); } } } // ports used later to run Transport Zone connectivity if (portsToRunNetworkConnectivity != null) { portsToRunNetworkConnectivity.addAll(notVisiblePorts); } } /** * checkVirtualNasNotVisible - verifies that all existing virtual nas servers on * given storage system are discovered or not. * If any of the existing virtual nas server is not discovered, * Change the discovered status as not visible. * * @param discoveredVNasServers * @param dbClient * @param storageSystemId * @return * @throws IOException */ public static List<VirtualNAS> checkVirtualNasNotVisible(List<VirtualNAS> discoveredVNasServers, DbClient dbClient, URI storageSystemId) { List<VirtualNAS> modifiedVNas = new ArrayList<VirtualNAS>(); // Get the vnas servers previousy discovered URIQueryResultList vNasURIs = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getStorageDeviceVirtualNasConstraint(storageSystemId), vNasURIs); Iterator<URI> vNasIter = vNasURIs.iterator(); List<URI> existingVNasURI = new ArrayList<URI>(); while (vNasIter.hasNext()) { existingVNasURI.add(vNasIter.next()); } List<URI> discoveredVNasURI = new ArrayList<URI>(); for (VirtualNAS vNas : discoveredVNasServers) { discoveredVNasURI.add(vNas.getId()); } Set<URI> vNasDiff = Sets.difference(new HashSet<URI>(existingVNasURI), new HashSet<URI>(discoveredVNasURI)); if (!vNasDiff.isEmpty()) { Iterator<VirtualNAS> vNasIt = dbClient.queryIterativeObjects(VirtualNAS.class, vNasDiff, true); while (vNasIt.hasNext()) { VirtualNAS vnas = vNasIt.next(); modifiedVNas.add(vnas); _log.info("Setting discovery status of vnas {} as NOTVISIBLE", vnas.getNasName()); vnas.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.NOTVISIBLE.name()); // Set the nas state to UNKNOWN!!! vnas.setNasState(VirtualNAS.VirtualNasState.UNKNOWN.name()); } } //Persist the change!!! if(!modifiedVNas.isEmpty()) { dbClient.persistObject(modifiedVNas); } return modifiedVNas; } /** * check Storage Volume exists in DB * * @param dbClient * @param nativeGuid * @return * @throws IOException */ public static Volume checkStorageVolumeExistsInDB(DbClient dbClient, String nativeGuid) throws IOException { List<Volume> volumes = CustomQueryUtility.getActiveVolumeByNativeGuid(dbClient, nativeGuid); Iterator<Volume> volumesItr = volumes.iterator(); if (volumesItr.hasNext()) { return volumesItr.next(); } return null; } /** * check Block Snapshot exists in DB * * @param dbClient * @param nativeGuid * @return * @throws IOException */ public static BlockSnapshot checkBlockSnapshotExistsInDB(DbClient dbClient, String nativeGuid) throws IOException { List<BlockSnapshot> snapshots = CustomQueryUtility.getActiveBlockSnapshotByNativeGuid(dbClient, nativeGuid); Iterator<BlockSnapshot> snapshotItr = snapshots.iterator(); if (snapshotItr.hasNext()) { return snapshotItr.next(); } return null; } /** * check Protection Set exists in DB * * @param dbClient * @param nativeGuid * @return * @throws IOException */ public static ProtectionSet checkProtectionSetExistsInDB(DbClient dbClient, String nativeGuid) throws IOException { List<ProtectionSet> cgs = CustomQueryUtility.getActiveProtectionSetByNativeGuid(dbClient, nativeGuid); Iterator<ProtectionSet> cgsItr = cgs.iterator(); if (cgsItr.hasNext()) { return cgsItr.next(); } return null; } /** * check UnManagedVolume exists in DB * * @param nativeGuid * @param dbClient * @return * @throws IOException */ public static UnManagedVolume checkUnManagedVolumeExistsInDB(DbClient dbClient, String nativeGuid) { URIQueryResultList unManagedVolumeList = new URIQueryResultList(); dbClient.queryByConstraint(AlternateIdConstraint.Factory .getVolumeInfoNativeIdConstraint(nativeGuid), unManagedVolumeList); if (unManagedVolumeList.iterator().hasNext()) { URI unManagedVolumeURI = unManagedVolumeList.iterator().next(); UnManagedVolume volumeInfo = dbClient.queryObject(UnManagedVolume.class, unManagedVolumeURI); if (!volumeInfo.getInactive()) { return volumeInfo; } } return null; } /** * check UnManagedVolume exists in DB by WWN * * @param dbClient db client * @param wwn WWN * @return volume, if it's in the DB */ public static UnManagedVolume checkUnManagedVolumeExistsInDBByWwn(DbClient dbClient, String wwn) { URIQueryResultList unManagedVolumeList = new URIQueryResultList(); dbClient.queryByConstraint(AlternateIdConstraint.Factory .getUnManagedVolumeWwnConstraint(wwn), unManagedVolumeList); if (unManagedVolumeList.iterator().hasNext()) { URI unManagedVolumeURI = unManagedVolumeList.iterator().next(); UnManagedVolume volumeInfo = dbClient.queryObject(UnManagedVolume.class, unManagedVolumeURI); if (!volumeInfo.getInactive()) { return volumeInfo; } } return null; } /** * Check if a managed Volume exists in database, searching by WWN. * * @param dbClient database client reference * @param wwn the WWN to look for in the Volume table * @return a Volume object, if it's in the database */ public static Volume checkManagedVolumeExistsInDBByWwn(DbClient dbClient, String wwn) { URIQueryResultList volumeList = new URIQueryResultList(); dbClient.queryByConstraint(AlternateIdConstraint.Factory.getVolumeWwnConstraint(wwn), volumeList); if (volumeList.iterator().hasNext()) { URI volumeURI = volumeList.iterator().next(); Volume volumeInfo = dbClient.queryObject(Volume.class, volumeURI); if (!volumeInfo.getInactive()) { return volumeInfo; } } return null; } /** * check unmanaged Protection Set exists in DB * * @param dbClient a reference to the database client * @param nativeGuid native guid of the protection set * @return the unmanaged protection set associated with the native guid * @throws IOException */ public static UnManagedProtectionSet checkUnManagedProtectionSetExistsInDB(DbClient dbClient, String nativeGuid) throws IOException { List<UnManagedProtectionSet> cgs = CustomQueryUtility.getUnManagedProtectionSetByNativeGuid(dbClient, nativeGuid); Iterator<UnManagedProtectionSet> cgsItr = cgs.iterator(); if (cgsItr.hasNext()) { return cgsItr.next(); } return null; } /** * Get a Set of all UnManagedProtectionSet URIs for a given ProtectionSystem. * * @param dbClient a reference to the database client * @param protectionSystemUri the URI of the ProtectionSystem to check * @return a Set of all UnManagedProtectionSets for a given ProtectionSystem */ public static Set<URI> getAllUnManagedProtectionSetsForSystem( DbClient dbClient, String protectionSystemUri) { Set<URI> cgSet = new HashSet<URI>(); List<UnManagedProtectionSet> cgs = CustomQueryUtility.getUnManagedProtectionSetByProtectionSystem(dbClient, protectionSystemUri); Iterator<UnManagedProtectionSet> cgsItr = cgs.iterator(); while (cgsItr.hasNext()) { cgSet.add(cgsItr.next().getId()); } return cgSet; } /** * 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 storageSystem * @param discoveredUnManagedVolumes * @param dbClient * @param partitionManager */ public static void markInActiveUnManagedVolumes(StorageSystem storageSystem, Set<URI> discoveredUnManagedVolumes, DbClient dbClient, PartitionManager partitionManager) { _log.info(" -- Processing {} discovered UnManaged Volumes Objects from -- {}", discoveredUnManagedVolumes.size(), storageSystem.getLabel()); if (discoveredUnManagedVolumes.isEmpty()) { return; } // Get all available existing unmanaged Volume URIs for this array from DB URIQueryResultList allAvailableUnManagedVolumesInDB = new URIQueryResultList(); dbClient.queryByConstraint(ContainmentConstraint.Factory .getStorageDeviceUnManagedVolumeConstraint(storageSystem.getId()), allAvailableUnManagedVolumesInDB); Set<URI> unManagedVolumesInDBSet = new HashSet<URI>(); Iterator<URI> allAvailableUnManagedVolumesItr = allAvailableUnManagedVolumesInDB.iterator(); while (allAvailableUnManagedVolumesItr.hasNext()) { unManagedVolumesInDBSet.add(allAvailableUnManagedVolumesItr.next()); } SetView<URI> onlyAvailableinDB = Sets.difference(unManagedVolumesInDBSet, discoveredUnManagedVolumes); _log.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; } _log.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, UNMANAGED_VOLUME); } } } /** * Compares the set of unmanaged consistency groups for the current discovery operation * to the set of unmanaged consistency groups already in the database from a previous * discovery operation. Removes existing database entries if the object was not present * in the current discovery operation. * * @param storageSystem - storage system containing the CGs * @param currentUnManagedCGs - current list of unmanaged CGs * @param dbClient - database client * @param partitionManager - partition manager */ public static void performUnManagedConsistencyGroupsBookKeeping(StorageSystem storageSystem, Set<URI> currentUnManagedCGs, DbClient dbClient, PartitionManager partitionManager) { _log.info(" -- Processing {} discovered UnManaged Consistency Group Objects from -- {}", currentUnManagedCGs.size(), storageSystem.getLabel()); // no consistency groups discovered if (currentUnManagedCGs.isEmpty()) { return; } // Get all available existing unmanaged CG URIs for this array from DB URIQueryResultList allAvailableUnManagedCGsInDB = new URIQueryResultList(); dbClient.queryByConstraint(ContainmentConstraint.Factory.getStorageSystemUnManagedCGConstraint(storageSystem.getId()), allAvailableUnManagedCGsInDB); Set<URI> unManagedCGsInDBSet = new HashSet<URI>(); Iterator<URI> allAvailableUnManagedCGsItr = allAvailableUnManagedCGsInDB.iterator(); while (allAvailableUnManagedCGsItr.hasNext()) { unManagedCGsInDBSet.add(allAvailableUnManagedCGsItr.next()); } SetView<URI> onlyAvailableinDB = Sets.difference(unManagedCGsInDBSet, currentUnManagedCGs); _log.info("Diff :" + Joiner.on("\t").join(onlyAvailableinDB)); if (!onlyAvailableinDB.isEmpty()) { List<UnManagedConsistencyGroup> unManagedCGTobeDeleted = new ArrayList<UnManagedConsistencyGroup>(); Iterator<UnManagedConsistencyGroup> unManagedCGs = dbClient.queryIterativeObjects(UnManagedConsistencyGroup.class, new ArrayList<URI>(onlyAvailableinDB)); while (unManagedCGs.hasNext()) { UnManagedConsistencyGroup cg = unManagedCGs.next(); if (null == cg || cg.getInactive()) { continue; } _log.info("Setting UnManagedConsistencyGroup {} inactive", cg.getId()); cg.setStorageSystemUri(NullColumnValueGetter.getNullURI()); cg.setInactive(true); unManagedCGTobeDeleted.add(cg); } if (!unManagedCGTobeDeleted.isEmpty()) { partitionManager.updateAndReIndexInBatches(unManagedCGTobeDeleted, unManagedCGTobeDeleted.size(), dbClient, UNMANAGED_CONSISTENCY_GROUP); } } } public static void markInActiveUnManagedExportMask(URI storageSystemUri, Set<URI> discoveredUnManagedExportMasks, DbClient dbClient, PartitionManager partitionManager) { URIQueryResultList result = new URIQueryResultList(); dbClient.queryByConstraint(ContainmentConstraint.Factory .getStorageSystemUnManagedExportMaskConstraint(storageSystemUri), result); Set<URI> allMasksInDatabase = new HashSet<URI>(); Iterator<URI> it = result.iterator(); while (it.hasNext()) { allMasksInDatabase.add(it.next()); } SetView<URI> onlyAvailableinDB = Sets.difference(allMasksInDatabase, discoveredUnManagedExportMasks); if (!onlyAvailableinDB.isEmpty()) { _log.info("these UnManagedExportMasks are orphaned and will be cleaned up:" + Joiner.on("\t").join(onlyAvailableinDB)); List<UnManagedExportMask> unManagedExportMasksToBeDeleted = new ArrayList<UnManagedExportMask>(); Iterator<UnManagedExportMask> unManagedExportMasks = dbClient.queryIterativeObjects(UnManagedExportMask.class, new ArrayList<URI>(onlyAvailableinDB)); while (unManagedExportMasks.hasNext()) { UnManagedExportMask uem = unManagedExportMasks.next(); if (null == uem || uem.getInactive()) { continue; } _log.info("Setting UnManagedExportMask {} inactive", uem.getMaskingViewPath()); uem.setStorageSystemUri(NullColumnValueGetter.getNullURI()); uem.setInactive(true); unManagedExportMasksToBeDeleted.add(uem); } if (!unManagedExportMasksToBeDeleted.isEmpty()) { partitionManager.updateAndReIndexInBatches(unManagedExportMasksToBeDeleted, unManagedExportMasksToBeDeleted.size(), dbClient, UNMANAGED_EXPORT_MASK); } } } /** * Return the Matched VirtualPools of a given physical pool. * * @param poolUri * - Physical Pool URI. * @param dbClient * @return */ private static List<VirtualPool> getMatchedVPoolsOfAPool(URI poolUri, DbClient dbClient) { URIQueryResultList vpoolMatchedPoolsResultList = new URIQueryResultList(); dbClient.queryByConstraint(ContainmentConstraint.Factory .getMatchedPoolVirtualPoolConstraint(poolUri), vpoolMatchedPoolsResultList); return dbClient.queryObject(VirtualPool.class, vpoolMatchedPoolsResultList); } /** * Determines if the UnManagedConsistencyGroup object exists in the database * * @param nativeGuid - native Guid for the unmanaged consistency group * @param dbClient - database client * @return unmanagedCG - null if it does not exist in the database, otherwise it returns the * UnManagedConsistencyGroup object from the database * @throws IOException */ public static UnManagedConsistencyGroup checkUnManagedCGExistsInDB(DbClient dbClient, String nativeGuid) { UnManagedConsistencyGroup unmanagedCG = null; URIQueryResultList unManagedCGList = new URIQueryResultList(); dbClient.queryByConstraint(AlternateIdConstraint.Factory .getCGInfoNativeIdConstraint(nativeGuid), unManagedCGList); if (unManagedCGList.iterator().hasNext()) { URI unManagedCGURI = unManagedCGList.iterator().next(); unmanagedCG = dbClient.queryObject(UnManagedConsistencyGroup.class, unManagedCGURI); } return unmanagedCG; } /** * Dump & remove deleted namespaces in object storage * * @param discoveredNamespaces * @param dbClient * @param storageSystemId */ public static void checkNamespacesNotVisible(List<ObjectNamespace> discoveredNamespaces, DbClient dbClient, URI storageSystemId) { // Get the namespaces previousy discovered URIQueryResultList objNamespaceURIs = new URIQueryResultList(); dbClient.queryByConstraint( ContainmentConstraint.Factory.getStorageDeviceObjectNamespaceConstraint(storageSystemId), objNamespaceURIs); Iterator<URI> objNamespaceIter = objNamespaceURIs.iterator(); List<URI> existingNamespacesURI = new ArrayList<URI>(); while (objNamespaceIter.hasNext()) { existingNamespacesURI.add(objNamespaceIter.next()); } List<URI> discoveredNamespacesURI = new ArrayList<URI>(); for (ObjectNamespace namespace : discoveredNamespaces) { discoveredNamespacesURI.add(namespace.getId()); } // Present in existing but not in discovered; remove them Set<URI> namespacesDiff = Sets.difference(new HashSet<URI>(existingNamespacesURI), new HashSet<URI>(discoveredNamespacesURI)); if (!namespacesDiff.isEmpty()) { Iterator<ObjectNamespace> objNamespaceIt = dbClient.queryIterativeObjects(ObjectNamespace.class, namespacesDiff, true); while (objNamespaceIt.hasNext()) { ObjectNamespace namespace = objNamespaceIt.next(); // Namespace is not associated with tenant if (namespace.getTenant() == null) { _log.info("Object Namespace not visible & getting deleted {} : {}", namespace.getNativeId(), namespace.getId()); namespace.setDiscoveryStatus(DiscoveredDataObject.DiscoveryStatus.NOTVISIBLE.name()); namespace.setInactive(true); } dbClient.updateObject(namespace); } } } /** * Run WBEMClient execQuery method * * @param cimClient WBEMClient * @param objectPath CIMObjectPath * @param query query string * @param queryLanguage * @return list of matched instances */ public static List<CIMInstance> executeQuery(WBEMClient cimClient, CIMObjectPath objectPath, String query, String queryLanguage) { _log.info(String.format( "Executing query: %s, objectPath: %s, query language: %s", query, objectPath, queryLanguage)); CloseableIterator<CIMInstance> iterator = null; List<CIMInstance> instanceList = new ArrayList<CIMInstance>(); try { iterator = cimClient.execQuery(objectPath, query, queryLanguage); while (iterator.hasNext()) { instanceList.add(iterator.next()); } } catch (WBEMException we) { _log.error( "Caught an error while attempting to execute query and process query result. Query: " + query, we); } finally { if (iterator != null) { iterator.close(); } } return instanceList; } /** * Run WBEMClient associatorNames method * * @param cimClient WBEMClient * @param objectPath CIMObjectPath * @param assocClass associate class * @param resultClass * @param role * @param resultRole * @return list of CIMObjectPaths */ public static List<CIMObjectPath> getAssociatorNames(WBEMClient cimClient, CIMObjectPath objectPath, String assocClass, String resultClass, String role, String resultRole) { CloseableIterator<CIMObjectPath> iterator = null; List<CIMObjectPath> objectPaths = new ArrayList<CIMObjectPath>(); try { iterator = cimClient.associatorNames(objectPath, assocClass, resultClass, role, resultRole); while (iterator.hasNext()) { objectPaths.add(iterator.next()); } } catch (WBEMException we) { _log.error("Caught an error while attempting to execute associatorNames"); } finally { if (iterator != null) { iterator.close(); } } return objectPaths; } }