/** * Filter vpools from the qualified list. rpSource true: Filter out anything other than RP source * vpools rpSource false: Filter out RP and SRDF source vpools * * @param dbClient dbclient * @param unManagedVolume unmanaged volume * @param personality SOURCE, TARGET, or METADATA */ private void filterProtectedVpools( DbClient dbClient, UnManagedVolume unManagedVolume, String personality) { if (unManagedVolume.getSupportedVpoolUris() != null && !unManagedVolume.getSupportedVpoolUris().isEmpty()) { Iterator<VirtualPool> vpoolItr = dbClient.queryIterativeObjects( VirtualPool.class, URIUtil.toURIList(unManagedVolume.getSupportedVpoolUris())); while (vpoolItr.hasNext()) { boolean remove = false; VirtualPool vpool = vpoolItr.next(); // If this is an SRDF source vpool, we can filter out since we're dealing with an RP volume if (vpool.getProtectionRemoteCopySettings() != null) { remove = true; } // If this is not an RP source, the vpool should be filtered out if: // The vpool is an RP vpool (has settings) and target vpools are non-null if (vpool.getProtectionVarraySettings() != null && ((Volume.PersonalityTypes.TARGET.name().equalsIgnoreCase(personality)) || Volume.PersonalityTypes.METADATA.name().equalsIgnoreCase(personality))) { boolean foundEmptyTargetVpool = false; Map<URI, VpoolProtectionVarraySettings> settings = VirtualPool.getProtectionSettings(vpool, dbClient); for (Map.Entry<URI, VpoolProtectionVarraySettings> setting : settings.entrySet()) { if (NullColumnValueGetter.isNullURI(setting.getValue().getVirtualPool())) { foundEmptyTargetVpool = true; break; } } // If this is a journal volume, also check the journal vpools. If they're not set, we // cannot filter out this vpool. if (Volume.PersonalityTypes.METADATA.name().equalsIgnoreCase(personality) && (NullColumnValueGetter.isNullValue(vpool.getJournalVpool()) || NullColumnValueGetter.isNullValue(vpool.getStandbyJournalVpool()))) { foundEmptyTargetVpool = true; } // If every relevant target (and journal for journal volumes) vpool is filled-in, then // you would never assign your target volume to this source vpool, so filter it out. if (!foundEmptyTargetVpool) { remove = true; } } if (Volume.PersonalityTypes.SOURCE.name().equalsIgnoreCase(personality)) { if (!VirtualPool.vPoolSpecifiesProtection(vpool)) { // If this an RP source, the vpool must be an RP vpool remove = true; } else if (unManagedVolume .getVolumeInformation() .containsKey(SupportedVolumeInformation.RP_STANDBY_INTERNAL_SITENAME.toString()) && !VirtualPool.vPoolSpecifiesMetroPoint(vpool)) { // Since this is a Source volume with the presence of RP_STANDBY_INTERNAL_SITENAME // it indicates that this volume is MetroPoint, if we get here, this is vpool // must be filtered out since it's not MP. remove = true; } } if (remove) { log.info( "Removing virtual pool " + vpool.getLabel() + " from supported vpools for unmanaged volume: " + unManagedVolume.getLabel()); unManagedVolume.getSupportedVpoolUris().remove(vpool.getId().toString()); } } } }
/** * Creates the RP source volume/journal and the specified number of target/journal volumes. * * @param volumeName * @param numTargets */ private List<Volume> createRpVolumes( String volumeName, int numTargets, ProtectionSet protectionSet, boolean isRpVPlex) { List<Volume> volumes = new ArrayList<Volume>(); StringSet associatedVolumes = new StringSet(); associatedVolumes.add("associatedVol1"); StorageSystem storageSystem = null; if (isRpVPlex) { storageSystem = createStorageSystem(true); } else { storageSystem = createStorageSystem(false); } String rsetName = "RSet-" + volumeName; Volume sourceVolume = new Volume(); URI sourceVolumeURI = URIUtil.createId(Volume.class); volumes.add(sourceVolume); sourceVolume.setId(sourceVolumeURI); sourceVolume.setLabel(volumeName); sourceVolume.setPersonality(Volume.PersonalityTypes.SOURCE.toString()); sourceVolume.setRSetName(rsetName); sourceVolume.setProtectionSet(new NamedURI(protectionSet.getId(), sourceVolume.getLabel())); sourceVolume.setStorageController(storageSystem.getId()); if (isRpVPlex) { sourceVolume.setAssociatedVolumes(associatedVolumes); sourceVolume.setNativeId( "/clusters/cluster-1/virtual-volumes/device_V000195701573-01E7A_vol"); // Create a VPLEX ViPR BlockConsistencyGroup for the source volume BlockConsistencyGroup sourceVolumeCg = createBlockConsistencyGroup( sourceVolume.getLabel() + "-CG", storageSystem.getId(), Types.VPLEX.name(), true); addVolumeToBlockConsistencyGroup(sourceVolumeCg.getId(), sourceVolume); rpVplexVolumeToCgMapping.put(sourceVolumeURI, sourceVolumeCg.getId()); } else { rpVolumeURIs.add(sourceVolumeURI); } _dbClient.createObject(sourceVolume); Volume sourceVolumeJournal = new Volume(); URI sourceVolumeJournalURI = URIUtil.createId(Volume.class); volumes.add(sourceVolumeJournal); sourceVolumeJournal.setId(sourceVolumeJournalURI); sourceVolumeJournal.setLabel(volumeName + RP_SRC_JOURNAL_APPEND); sourceVolumeJournal.setPersonality(Volume.PersonalityTypes.METADATA.toString()); sourceVolumeJournal.setProtectionSet( new NamedURI(protectionSet.getId(), sourceVolumeJournal.getLabel())); sourceVolumeJournal.setStorageController(storageSystem.getId()); if (isRpVPlex) { sourceVolumeJournal.setAssociatedVolumes(associatedVolumes); sourceVolumeJournal.setNativeId( "/clusters/cluster-1/virtual-volumes/device_V000195701573-01E7B_vol"); // Create a VPLEX ViPR BlockConsistencyGroup for the source journal volume BlockConsistencyGroup sourceVolumeJournalCg = createBlockConsistencyGroup( sourceVolumeJournal.getLabel() + "-CG", storageSystem.getId(), Types.VPLEX.name(), true); addVolumeToBlockConsistencyGroup(sourceVolumeJournalCg.getId(), sourceVolumeJournal); rpVplexVolumeToCgMapping.put(sourceVolumeJournalURI, sourceVolumeJournalCg.getId()); } else { rpVolumeURIs.add(sourceVolumeJournalURI); } _dbClient.createObject(sourceVolumeJournal); for (int i = 1; i <= numTargets; i++) { Volume sourceVolumeTarget = new Volume(); URI sourceVolumeTargetURI = URIUtil.createId(Volume.class); volumes.add(sourceVolumeTarget); sourceVolumeTarget.setId(sourceVolumeTargetURI); sourceVolumeTarget.setLabel(volumeName + RP_TGT_APPEND + "vArray" + i); sourceVolumeTarget.setPersonality(Volume.PersonalityTypes.TARGET.toString()); sourceVolumeTarget.setRSetName(rsetName); sourceVolumeTarget.setProtectionSet( new NamedURI(protectionSet.getId(), sourceVolumeTarget.getLabel())); sourceVolumeTarget.setStorageController(storageSystem.getId()); if (isRpVPlex) { sourceVolumeTarget.setAssociatedVolumes(associatedVolumes); sourceVolumeTarget.setNativeId( "/clusters/cluster-2/virtual-volumes/device_V000195701573-01E7C_vol" + i); // Create a VPLEX ViPR BlockConsistencyGroup for the target volume BlockConsistencyGroup sourceVolumeTargetCg = createBlockConsistencyGroup( sourceVolumeTarget.getLabel() + "-CG", storageSystem.getId(), Types.VPLEX.name(), true); addVolumeToBlockConsistencyGroup(sourceVolumeTargetCg.getId(), sourceVolumeTarget); rpVplexVolumeToCgMapping.put(sourceVolumeTargetURI, sourceVolumeTargetCg.getId()); } else { rpVolumeURIs.add(sourceVolumeTargetURI); } _dbClient.createObject(sourceVolumeTarget); Volume sourceVolumeTargetJournal = new Volume(); URI sourceVolumeTargetJournalURI = URIUtil.createId(Volume.class); volumes.add(sourceVolumeTargetJournal); sourceVolumeTargetJournal.setId(sourceVolumeTargetJournalURI); sourceVolumeTargetJournal.setLabel(volumeName + RP_TGT_JOURNAL_APPEND + "vArray" + i); sourceVolumeTargetJournal.setPersonality(Volume.PersonalityTypes.METADATA.toString()); sourceVolumeTargetJournal.setProtectionSet( new NamedURI(protectionSet.getId(), sourceVolumeTargetJournal.getLabel())); sourceVolumeTargetJournal.setStorageController(storageSystem.getId()); if (isRpVPlex) { sourceVolumeTargetJournal.setAssociatedVolumes(associatedVolumes); sourceVolumeTargetJournal.setNativeId( "/clusters/cluster-2/virtual-volumes/device_V000195701573-01ED_vol" + i); // Create a VPLEX ViPR BlockConsistencyGroup for the source target journal volume BlockConsistencyGroup sourceVolumeTargetJournalCg = createBlockConsistencyGroup( sourceVolumeTargetJournal.getLabel() + "-CG", storageSystem.getId(), Types.VPLEX.name(), true); addVolumeToBlockConsistencyGroup( sourceVolumeTargetJournalCg.getId(), sourceVolumeTargetJournal); rpVplexVolumeToCgMapping.put( sourceVolumeTargetJournalURI, sourceVolumeTargetJournalCg.getId()); } else { rpVolumeURIs.add(sourceVolumeTargetJournalURI); } _dbClient.createObject(sourceVolumeTargetJournal); } return volumes; }
/** * 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); } } }