/* * Copyright (c) 2017 Dell EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.client.upgrade.callbacks; import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.FileShare.PersonalityTypes; import com.emc.storageos.db.client.model.VirtualPool; 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 internalSiteName field on MetroPoint Volume objects where it has * been set incorrectly due to pre-3.0 code. Jira: COP-27924 * */ public class MetroPointVolumeInternalSiteNameMigration extends BaseCustomMigrationCallback { private static final Logger log = LoggerFactory.getLogger(MetroPointVolumeInternalSiteNameMigration.class); @Override public void process() throws MigrationCallbackException { updateVolumeInternalSiteName(); } /** * Update the MetroPoint Volume objects to ensure the source VPlex volume uses the * internalSiteName of the source side backing Volume. The correct source side backing * volume can be found by matching up the RP copy name on the volumes. */ private void updateVolumeInternalSiteName() throws MigrationCallbackException { log.info("Migrating MetroPoint Volume internalSiteName fields."); try { DbClient dbClient = getDbClient(); List<URI> volumeURIs = dbClient.queryByType(Volume.class, true); Iterator<Volume> volumes = dbClient.queryIterativeObjects(Volume.class, volumeURIs); List<String> updatedVolumes = new ArrayList<String>(); List<String> invalidVolumes = new ArrayList<String>(); while (volumes.hasNext()) { Volume volume = volumes.next(); if (PersonalityTypes.SOURCE.name().equals(volume.getPersonality()) && (NullColumnValueGetter.isNullNamedURI(volume.getProtectionSet()) || NullColumnValueGetter.isNullURI(volume .getConsistencyGroup()))) { invalidVolumes.add(volume.getId().toString()); continue; } if (volume != null && NullColumnValueGetter.isNotNullValue(volume.getRpCopyName()) && PersonalityTypes.SOURCE.name().equals(volume.getPersonality()) && volume.getAssociatedVolumes() != null && volume.getAssociatedVolumes().size() == 2 && !NullColumnValueGetter.isNullURI(volume.getVirtualPool())) { // Get the volume's virtual pool and use that to determine if this is a MetroPoint volume VirtualPool vpool = dbClient.queryObject(VirtualPool.class, volume.getVirtualPool()); if (vpool != null && VirtualPool.vPoolSpecifiesMetroPoint(vpool)) { // This is a MetroPoint VPlex source volume, so update it. if (updateVolume(volume)) { updatedVolumes.add(volume.getId().toString()); } } } } log.info(String.format("MetroPointVolumeInternalSiteNameMigration has updated %d MetroPoint source volumes: %s", updatedVolumes.size(), updatedVolumes.toString())); log.info(String .format("MetroPointVolumeInternalSiteNameMigration has found %d invalid volumes. These volumes have an invalid protection set or consistency group reference: %s", invalidVolumes.size(), invalidVolumes.toString())); } catch (Exception e) { String errorMsg = String.format("%s encounter unexpected error %s", this.getName(), e.getMessage()); throw new MigrationCallbackException(errorMsg, e); } } /** * Updates the MetroPoint VPlex source volume's internalSiteName to match that of * the corresponding active production backing volume. * * @param volumes the volumes to verify and update */ private boolean updateVolume(Volume volume) { for (String volUri : volume.getAssociatedVolumes()) { Volume backingVolume = dbClient.queryObject(Volume.class, URI.create(volUri)); // Get the associated volumes and determine which one is the active production volume // based on the virtual array. The backing volume matching the virtual array of the source // VPlex volume is the active production backing volume. Only update the VPlex source // volume's internalSiteName if it is different from the corresponding backing volume. if (!NullColumnValueGetter.isNullURI(volume.getVirtualArray()) && volume.getVirtualArray().equals(backingVolume.getVirtualArray()) && NullColumnValueGetter.isNotNullValue(backingVolume.getInternalSiteName()) && !backingVolume.getInternalSiteName().equals(volume.getInternalSiteName())) { log.info(String .format("MetroPoint source volume [%s] has an invalid internal site name [%s]. Updating the internal site name to [%s] based on corresponding backing volume [%s].", volume.getId(), volume.getInternalSiteName(), backingVolume.getInternalSiteName(), backingVolume.getId())); volume.setInternalSiteName(backingVolume.getInternalSiteName()); dbClient.updateObject(volume); // volume has been updated to return true; return true; } } return false; } }