/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.client.upgrade.callbacks; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; 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.AlternateIdConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.RemoteDirectorGroup; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException; /** * Migration handler to update the SRDF Target volumes with the source RDFGroup URI instead of target RDFGroup * for all ingested volumes in 2.3 version. * * This handles both 4.x & 8.x versions. * */ public class SRDFTargetVolumeRDFGroupMigration extends BaseCustomMigrationCallback { private static final Logger log = LoggerFactory.getLogger(SRDFTargetVolumeRDFGroupMigration.class); public static final String SMIS_DOT_REGEX = "\\."; public static final String SMIS_PLUS_REGEX = "\\+"; public static final String PLUS = "+"; @Override public void process() throws MigrationCallbackException { log.info("Updating SRDF Target volume rdfGroup information."); DbClient dbClient = this.getDbClient(); List<URI> volumeURIs = dbClient.queryByType(Volume.class, true); Map<URI, RemoteDirectorGroup> rdfGroupCache = new HashMap<URI, RemoteDirectorGroup>(); Map<URI, StorageSystem> systemCache = new HashMap<URI, StorageSystem>(); List<Volume> volumesToUpdate = new ArrayList<Volume>(); Iterator<Volume> volumes = dbClient.queryIterativeObjects(Volume.class, volumeURIs); while (volumes.hasNext()) { Volume volume = volumes.next(); try { if (null != volume.getSrdfParent() && !NullColumnValueGetter.isNullNamedURI(volume.getSrdfParent())) { if (null != volume.getSrdfGroup() && !NullColumnValueGetter.isNullURI(volume.getSrdfGroup()) && !NullColumnValueGetter.isNullURI(volume.getStorageController())) { log.info("Determining SRDF Target volume {} to update rdf group", volume.getLabel()); RemoteDirectorGroup volumeSrdfGroup = fetchRDFGroupFromCache(rdfGroupCache, volume.getSrdfGroup()); StorageSystem system = fetchSystemFromCache(systemCache, volume.getStorageController()); // Found a target volume with the target SRDFGroup uri if (URIUtil.identical(volumeSrdfGroup.getSourceStorageSystemUri(), volume.getStorageController())) { // Set the source SRDF Group URI RemoteDirectorGroup sourceRDFGroup = getAssociatedTargetRemoteDirectorGroup(system.getUsingSmis80(), volumeSrdfGroup.getNativeGuid()); if (null == sourceRDFGroup) { log.info("Source RDFGroup not found in DB. Hence skipping."); continue; } volume.setSrdfGroup(sourceRDFGroup.getId()); volumesToUpdate.add(volume); if (volumesToUpdate.size() > 100) { this.dbClient.updateObject(volumesToUpdate); log.info("Updated {} SRDF Target volumes in db", volumesToUpdate.size()); volumesToUpdate.clear(); } } else { log.info("No need to update the rdfgroup for volume {} as it has the right source RDFGroup {}", volume.getLabel(), volume.getSrdfGroup()); } } } } catch (Exception ex) { log.error("Exception occurred while updating the SRDFGroup for the target volume {}. proceeding next..", volume.getLabel()); } } // Update the remaining volumes if (volumesToUpdate.size() > 0) { this.dbClient.updateObject(volumesToUpdate); log.info("Updated {} SRDF Target volumes in db", volumesToUpdate.size()); } } /** * Return the storageSystem if it is found in cache otherwise query from db. * * @param systemCache * @param storageController * @return */ private StorageSystem fetchSystemFromCache(Map<URI, StorageSystem> systemCache, URI storageController) { if (systemCache.containsKey(storageController)) { return systemCache.get(storageController); } StorageSystem system = this.getDbClient().queryObject(StorageSystem.class, storageController); if (null != system && !system.getInactive()) { systemCache.put(storageController, system); } return system; } /** * Return the RemoteDirectorGroup from cache otherwise query from db. * * @param rdfGroupCache * @param srdfGroupURI * @return */ private RemoteDirectorGroup fetchRDFGroupFromCache(Map<URI, RemoteDirectorGroup> rdfGroupCache, URI srdfGroupURI) { if (rdfGroupCache.containsKey(srdfGroupURI)) { return rdfGroupCache.get(srdfGroupURI); } RemoteDirectorGroup rdfGroup = this.getDbClient().queryObject(RemoteDirectorGroup.class, srdfGroupURI); if (null != rdfGroup && !rdfGroup.getInactive()) { rdfGroupCache.put(srdfGroupURI, rdfGroup); } return rdfGroup; } /** * Gets the associated target remote director group * by forming target RDF group's NativeGuid from source group NativeGuid */ private RemoteDirectorGroup getAssociatedTargetRemoteDirectorGroup(boolean is80Provider, String raGroupId) { // interchange source and target ids & group ids // 8.0.x NativeGuid format in DB // SYMMETRIX+000195700985+REMOTEGROUP+000195700985+60+000195700999+60 // SYMMETRIX+000195700999+REMOTEGROUP+000195700999+60+000195700985+60 // 4.6.x NativeGuid format in DB // SYMMETRIX+000195701573+REMOTEGROUP+000195701505+60+000195701573+60 // SYMMETRIX+000195701505+REMOTEGROUP+000195701505+60+000195701573+60 String targetRaGroupNativeGuid = null; StringBuilder strBuilder = new StringBuilder(); String[] nativeGuidArray = raGroupId.split(SMIS_PLUS_REGEX); String sourceArray = nativeGuidArray[1]; if (is80Provider) { String targetArray = nativeGuidArray[5]; strBuilder.append(nativeGuidArray[0]).append(PLUS) .append(targetArray).append(PLUS) .append(nativeGuidArray[2]).append(PLUS) .append(targetArray).append(PLUS) .append(nativeGuidArray[6]).append(PLUS) .append(sourceArray).append(PLUS) .append(nativeGuidArray[4]); } else { String targetArray = null; if (nativeGuidArray[3].contains(sourceArray)) { targetArray = nativeGuidArray[5]; } else { targetArray = nativeGuidArray[3]; } strBuilder.append(nativeGuidArray[0]).append(PLUS) .append(targetArray).append(PLUS) .append(nativeGuidArray[2]).append(PLUS) .append(nativeGuidArray[3]).append(PLUS) .append(nativeGuidArray[6]).append(PLUS) .append(nativeGuidArray[5]).append(PLUS) .append(nativeGuidArray[4]); } targetRaGroupNativeGuid = strBuilder.toString(); log.debug("Target RA Group Id : {}", targetRaGroupNativeGuid); RemoteDirectorGroup remoteGroup = getRAGroupFromDB(targetRaGroupNativeGuid); if (null == remoteGroup) { log.warn("Target RA Group {} not found", targetRaGroupNativeGuid); return null; } return remoteGroup; } /** * Return the RemoteDirectorGroup based on the nativeGuid. * * @param raGroupNativeGuid * @return */ private RemoteDirectorGroup getRAGroupFromDB(String raGroupNativeGuid) { URIQueryResultList raGroupUris = new URIQueryResultList(); this.getDbClient().queryByConstraint(AlternateIdConstraint.Factory.getRAGroupByNativeGuidConstraint(raGroupNativeGuid), raGroupUris); for (URI raGroupURI : raGroupUris) { RemoteDirectorGroup raGroup = dbClient.queryObject(RemoteDirectorGroup.class, raGroupURI); if (null != raGroup && !raGroup.getInactive()) { return raGroup; } } return null; } }