/** * 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); }
/** * Update (if it exists) the source and target UnManagedVolume objects with RP information needed * for ingestion * * @param unManagedProtectionSet unmanaged protection set * @param cg CG response got back from RP system * @param rpCopyAccessStateMap Map to hold the access state of the replication sets * @param rpWwnToNativeWwn Map of RP volume WWN to native volume WWN - required for XIO but * harmless otherwise * @param storageNativeIdPrefixes List of XIO systems discovered in ViPR * @param dbClient DB client instance */ private void mapCgSourceAndTargets( UnManagedProtectionSet unManagedProtectionSet, GetCGsResponse cg, Map<String, String> rpCopyAccessStateMap, Map<String, String> rpWwnToNativeWwn, List<String> storageNativeIdPrefixes, DbClient dbClient) { for (GetRSetResponse rset : cg.getRsets()) { for (GetVolumeResponse volume : rset.getVolumes()) { // Find this volume in UnManagedVolumes based on wwn UnManagedVolume unManagedVolume = findUnManagedVolumeForWwn(volume.getWwn(), dbClient, storageNativeIdPrefixes); // Check if this volume is already managed, which would indicate it has already been // partially ingested Volume managedVolume = DiscoveryUtils.checkManagedVolumeExistsInDBByWwn(dbClient, volume.getWwn()); // Add the WWN to the unmanaged protection set, regardless of whether this volume is // unmanaged or not. unManagedProtectionSet.getVolumeWwns().add(volume.getWwn()); if (null == unManagedVolume && null == managedVolume) { log.info( "Protection Set {} contains unknown Replication Set volume: {}. Skipping.", unManagedProtectionSet.getNativeGuid(), volume.getWwn()); continue; } if (null != managedVolume) { log.info( "Protection Set {} contains volume {} that is already managed", unManagedProtectionSet.getNativeGuid(), volume.getWwn()); // make sure it's in the UnManagedProtectionSet's ManagedVolume ids if (!unManagedProtectionSet .getManagedVolumeIds() .contains(managedVolume.getId().toString())) { unManagedProtectionSet.getManagedVolumeIds().add(managedVolume.getId().toString()); } if (!managedVolume.checkInternalFlags(Flag.INTERNAL_OBJECT) && null != unManagedVolume) { log.info( "Protection Set {} also has an orphaned UnManagedVolume {} that will be removed", unManagedProtectionSet.getNativeGuid(), unManagedVolume.getLabel()); // remove the unManagedVolume from the UnManagedProtectionSet's UnManagedVolume ids unManagedProtectionSet .getUnManagedVolumeIds() .remove(unManagedVolume.getId().toString()); unManagedVolumesToDelete.add(unManagedVolume); // because this volume is already managed, we can just continue to the next continue; } } // at this point, we have an legitimate UnManagedVolume whose RP properties should be // updated log.info("Processing Replication Set UnManagedVolume {}", unManagedVolume.forDisplay()); // Add the unmanaged volume to the list (if it's not there already) if (!unManagedProtectionSet .getUnManagedVolumeIds() .contains(unManagedVolume.getId().toString())) { unManagedProtectionSet.getUnManagedVolumeIds().add(unManagedVolume.getId().toString()); } // Update the fields in the UnManagedVolume to reflect RP characteristics String personality = Volume.PersonalityTypes.SOURCE.name(); if (!volume.isProduction()) { personality = Volume.PersonalityTypes.TARGET.name(); } updateCommonRPProperties( unManagedProtectionSet, unManagedVolume, personality, volume, dbClient); // Update other RP properties for source/targets // What Replication Set does this volume belong to? (so we can associate sources to // targets.) // What is the access state. StringSet rpAccessState = new StringSet(); rpAccessState.add(rpCopyAccessStateMap.get(volume.getRpCopyName())); unManagedVolume.putVolumeInfo( SupportedVolumeInformation.RP_ACCESS_STATE.toString(), rpAccessState); StringSet rsetName = new StringSet(); rsetName.add(rset.getName()); unManagedVolume.putVolumeInfo(SupportedVolumeInformation.RP_RSET_NAME.toString(), rsetName); rpWwnToNativeWwn.put(volume.getWwn(), unManagedVolume.getWwn()); unManagedVolumesToUpdateByWwn.put(unManagedVolume.getWwn(), unManagedVolume); } // Now that we've processed all of the sources and targets, we can mark all of the target // devices in the source devices. for (GetVolumeResponse volume : rset.getVolumes()) { // Only process source volumes here. if (!volume.isProduction()) { continue; } // Find this volume in UnManagedVolumes based on wwn // See if the unmanaged volume is in the list of volumes to update // (it should be, unless the backing array has not been discovered) UnManagedVolume unManagedVolume = null; String wwn = rpWwnToNativeWwn.get(volume.getWwn()); if (wwn != null) { unManagedVolume = findUnManagedVolumeForWwn(wwn, dbClient, storageNativeIdPrefixes); } if (null == unManagedVolume) { log.info( "Protection Set {} contains unknown volume: {}. Skipping.", unManagedProtectionSet.getNativeGuid(), volume.getWwn()); continue; } log.info("Linking target volumes to source volume {}", unManagedVolume.forDisplay()); StringSet rpTargetVolumeIds = linkTargetVolumes( unManagedProtectionSet, unManagedVolume, rset, rpWwnToNativeWwn, storageNativeIdPrefixes, dbClient); // Add the unmanaged target IDs to the source unmanaged volume unManagedVolume.putVolumeInfo( SupportedVolumeInformation.RP_UNMANAGED_TARGET_VOLUMES.toString(), rpTargetVolumeIds); unManagedVolumesToUpdateByWwn.put(unManagedVolume.getWwn(), unManagedVolume); } } }