/** * Re-validate the ExportMask * * <p>This is required to be done as the ExportMask gets updated by reading the cinder export * volume response. * * @param varrayURI * @param initiatorPortMap * @param mask * @param invalidMasks * @param directorToInitiatorIds * @param idToInitiatorMap * @param dbClient * @param portWwnToClusterMap */ public void updateZoningMapAndvalidateExportMask( URI varrayURI, Map<URI, List<StoragePort>> initiatorPortMap, URI exportMaskURI, Map<String, Set<String>> directorToInitiatorIds, Map<String, Initiator> idToInitiatorMap, Map<String, String> portWwnToClusterMap, StorageSystem vplex, StorageSystem array, String clusterId, String stepId) { try { WorkflowStepCompleter.stepExecuting(stepId); // Export Mask is updated, read it from DB ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); // First step would be to update the zoning map based on the connectivity updateZoningMap(initiatorPortMap, directorToInitiatorIds, exportMask); boolean passed = VPlexBackEndOrchestratorUtil.validateExportMask( varrayURI, initiatorPortMap, exportMask, null, directorToInitiatorIds, idToInitiatorMap, _dbClient, portWwnToClusterMap); if (!passed) { // Mark this mask as inactive, so that we dont pick it in the next iteration exportMask.setInactive(Boolean.TRUE); _dbClient.persistObject(exportMask); _log.error("Export Mask is not suitable for VPLEX to backend storage system"); WorkflowStepCompleter.stepFailed( stepId, VPlexApiException.exceptions.couldNotFindValidArrayExportMask( vplex.getNativeGuid(), array.getNativeGuid(), clusterId)); throw VPlexApiException.exceptions.couldNotFindValidArrayExportMask( vplex.getNativeGuid(), array.getNativeGuid(), clusterId); } WorkflowStepCompleter.stepSucceded(stepId); } catch (Exception ex) { _log.error("Failed to validate export mask for cinder: ", ex); VPlexApiException vplexex = DeviceControllerExceptions.vplex.failedToValidateExportMask(exportMaskURI.toString(), ex); WorkflowStepCompleter.stepFailed(stepId, vplexex); } }
/** * 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; }
/** * 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) { StringSetMap unManagedVolumeInformation = unManagedVolume.getVolumeInformation(); StringSet supportedVpoolURIs = unManagedVolumeInformation.get(SupportedVolumeInformation.SUPPORTED_VPOOL_LIST.toString()); 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); } }
/** * Discovers the RP CGs and all the volumes therein. It updates/creates the UnManagedProtectionSet * objects and updates (if it exists) the UnManagedVolume objects with RP information needed for * ingestion * * @param accessProfile access profile * @param dbClient db client * @param partitionManager partition manager * @throws Exception */ public void discoverUnManagedObjects( AccessProfile accessProfile, DbClient dbClient, PartitionManager partitionManager) throws Exception { this.partitionManager = partitionManager; log.info("Started discovery of UnManagedVolumes for system {}", accessProfile.getSystemId()); ProtectionSystem protectionSystem = dbClient.queryObject(ProtectionSystem.class, accessProfile.getSystemId()); if (protectionSystem == null) { log.error( "Discovery is not run! Protection System not found: " + accessProfile.getSystemId()); return; } RecoverPointClient rp = RPHelper.getRecoverPointClient(protectionSystem); unManagedCGsInsert = new ArrayList<UnManagedProtectionSet>(); unManagedCGsUpdate = new ArrayList<UnManagedProtectionSet>(); unManagedVolumesToDelete = new ArrayList<UnManagedVolume>(); unManagedVolumesToUpdateByWwn = new HashMap<String, UnManagedVolume>(); unManagedCGsReturnedFromProvider = new HashSet<URI>(); // Get all of the consistency groups (and their volumes) from RP Set<GetCGsResponse> cgs = rp.getAllCGs(); if (cgs == null) { log.warn("No CGs were found on protection system: " + protectionSystem.getLabel()); return; } // This section of code allows us to cache XIO native GUID to workaround an issue // with RP's understanding of XIO volume WWNs (128-bit) and the rest of the world's // understanding of the XIO volume WWN once it's exported (64-bit) Map<String, String> rpWwnToNativeWwn = new HashMap<String, String>(); List<URI> storageSystemIds = dbClient.queryByType(StorageSystem.class, true); List<String> storageNativeIdPrefixes = new ArrayList<String>(); if (storageSystemIds != null) { Iterator<StorageSystem> storageSystemsItr = dbClient.queryIterativeObjects(StorageSystem.class, storageSystemIds); while (storageSystemsItr.hasNext()) { StorageSystem storageSystem = storageSystemsItr.next(); if (storageSystem.getSystemType().equalsIgnoreCase(Type.xtremio.name())) { storageNativeIdPrefixes.add(storageSystem.getNativeGuid()); } } } for (GetCGsResponse cg : cgs) { try { log.info("Processing returned CG: " + cg.getCgName()); boolean newCG = false; // UnManagedProtectionSet native GUID is protection system GUID + consistency group ID String nativeGuid = protectionSystem.getNativeGuid() + Constants.PLUS + cg.getCgId(); // First check to see if this protection set is already part of our managed DB if (null != DiscoveryUtils.checkProtectionSetExistsInDB(dbClient, nativeGuid)) { log.info( "Protection Set " + nativeGuid + " already is managed by ViPR, skipping unmanaged discovery"); continue; } // Now check to see if the unmanaged CG exists in the database UnManagedProtectionSet unManagedProtectionSet = DiscoveryUtils.checkUnManagedProtectionSetExistsInDB(dbClient, nativeGuid); if (null == unManagedProtectionSet) { log.info("Creating new unmanaged protection set for CG: " + cg.getCgName()); unManagedProtectionSet = new UnManagedProtectionSet(); unManagedProtectionSet.setId(URIUtil.createId(UnManagedProtectionSet.class)); unManagedProtectionSet.setNativeGuid(nativeGuid); unManagedProtectionSet.setProtectionSystemUri(protectionSystem.getId()); StringSet protectionId = new StringSet(); protectionId.add("" + cg.getCgId()); unManagedProtectionSet.putCGInfo( SupportedCGInformation.PROTECTION_ID.toString(), protectionId); // Default MP to false until proven otherwise unManagedProtectionSet .getCGCharacteristics() .put( UnManagedProtectionSet.SupportedCGCharacteristics.IS_MP.name(), Boolean.FALSE.toString()); newCG = true; } else { log.info( "Found existing unmanaged protection set for CG: " + cg.getCgName() + ", using " + unManagedProtectionSet.getId().toString()); } unManagedCGsReturnedFromProvider.add(unManagedProtectionSet.getId()); // Update the fields for the CG unManagedProtectionSet.setCgName(cg.getCgName()); unManagedProtectionSet.setLabel(cg.getCgName()); // Indicate whether the CG is in a healthy state or not to ingest. unManagedProtectionSet .getCGCharacteristics() .put( UnManagedProtectionSet.SupportedCGCharacteristics.IS_HEALTHY.name(), cg.getCgState().equals(GetCGStateResponse.HEALTHY) ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); // Indicate whether the CG is sync or async unManagedProtectionSet .getCGCharacteristics() .put( UnManagedProtectionSet.SupportedCGCharacteristics.IS_SYNC.name(), cg.getCgPolicy().synchronous ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); // Fill in RPO type and value information StringSet rpoType = new StringSet(); rpoType.add(cg.getCgPolicy().rpoType); unManagedProtectionSet.putCGInfo(SupportedCGInformation.RPO_TYPE.toString(), rpoType); StringSet rpoValue = new StringSet(); rpoValue.add(cg.getCgPolicy().rpoValue.toString()); unManagedProtectionSet.putCGInfo(SupportedCGInformation.RPO_VALUE.toString(), rpoValue); if (null == cg.getCopies()) { log.info("Protection Set " + nativeGuid + " does not contain any copies. Skipping..."); continue; } if (null == cg.getRsets()) { log.info( "Protection Set " + nativeGuid + " does not contain any replication sets. Skipping..."); continue; } // clean up the existing journal and replicationsets info in the unmanaged protection set, // so that updated info is populated if (!newCG) { cleanUpUnManagedResources( unManagedProtectionSet, unManagedVolumesToUpdateByWwn, dbClient); } // Now map UnManagedVolume objects to the journal and rset (sources/targets) and put RP // fields in them Map<String, String> rpCopyAccessStateMap = new HashMap<String, String>(); mapCgJournals( unManagedProtectionSet, cg, rpCopyAccessStateMap, rpWwnToNativeWwn, storageNativeIdPrefixes, dbClient); mapCgSourceAndTargets( unManagedProtectionSet, cg, rpCopyAccessStateMap, rpWwnToNativeWwn, storageNativeIdPrefixes, dbClient); if (newCG) { unManagedCGsInsert.add(unManagedProtectionSet); } else { unManagedCGsUpdate.add(unManagedProtectionSet); } } catch (Exception ex) { log.error("Error processing RP CG {}", cg.getCgName(), ex); } } handlePersistence(dbClient, false); cleanUp(protectionSystem, dbClient); }