/* * Copyright (c) 2016 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.constraint.AlternateIdConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.DiscoveredDataObject.Type; import com.emc.storageos.db.client.model.ExportMask; import com.emc.storageos.db.client.model.Initiator; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.svcs.errorhandling.resources.MigrationCallbackException; /** * If we are upgrading from any version 3.5 or before, * the associated existing initiators of the Export Mask Object needs to be moved * to the userAddedInitiator of the same Object for all Initiators that are part * introduced into ViPR. * * @author yalamh * @since 3.5+ */ public class ExportMaskExistingInitiatorsMigration extends BaseCustomMigrationCallback { private static final Logger logger = LoggerFactory.getLogger(ExportMaskExistingInitiatorsMigration.class); @Override public void process() throws MigrationCallbackException { DbClient dbClient = getDbClient(); Map<URI, StorageSystem> systemMap = new HashMap<>(); int pageSize = 100; int totalExportMaskObjectCount = 0; int exportMaskUpdatedCount = 0; URI nextId = null; while (true) { List<URI> exportMaskUris = dbClient.queryByType(ExportMask.class, true, nextId, pageSize); if (exportMaskUris == null || exportMaskUris.isEmpty()) { break; } logger.info("processing page of {} {} Objects", exportMaskUris.size(), ExportMask.class.getSimpleName()); Iterator<ExportMask> exportMaskIterator = dbClient.queryIterativeObjects(ExportMask.class, exportMaskUris, true); while (exportMaskIterator.hasNext()) { ExportMask exportMask = exportMaskIterator.next(); URI systemUri = exportMask.getStorageDevice(); StorageSystem system = systemMap.get(systemUri); if (system == null) { system = dbClient.queryObject(StorageSystem.class, systemUri); if (system != null) { systemMap.put(systemUri, system); } } if (system != null && (Type.vmax.toString().equalsIgnoreCase(system.getSystemType()) || (Type.vplex.toString().equalsIgnoreCase(system.getSystemType())))) { logger.info("Processing existing initiators for export mask {} on {} storage {}", exportMask.getId(), system.getSystemType(), systemUri); boolean updateObject = false; List<String> initiatorsToProcess = new ArrayList<String>(); if (exportMask.getExistingInitiators() != null && !exportMask.getExistingInitiators().isEmpty()) { initiatorsToProcess.addAll(exportMask.getExistingInitiators()); for (String portName : initiatorsToProcess) { Initiator existingInitiator = getInitiator(Initiator.toPortNetworkId(portName), dbClient); if (existingInitiator != null && !checkIfDifferentResource(exportMask, existingInitiator)) { exportMask.addInitiator(existingInitiator); exportMask.addToUserCreatedInitiators(existingInitiator); exportMask.removeFromExistingInitiators(existingInitiator); logger.info("Initiator {} is being moved from existing to userCreated for the Mask {}", portName, exportMask.forDisplay()); updateObject = true; } } } if (updateObject) { logger.info("Processed existing initiators for export mask {} on {} storage {} and updated the Mask Object", exportMask.getId(), system.getSystemType(), systemUri); dbClient.updateObject(exportMask); exportMaskUpdatedCount++; } } else if (system == null) { logger.warn("could not determine storage system type for exportMask {}", exportMask.forDisplay()); } } nextId = exportMaskUris.get(exportMaskUris.size() - 1); totalExportMaskObjectCount += exportMaskUris.size(); } logger.info("Updated Existing information on {} of {} Export Mask Objects on VMAX Storage", exportMaskUpdatedCount, totalExportMaskObjectCount); } /** * Get an initiator as specified by the initiator's network port. * * @param networkPort The initiator's port WWN or IQN. * @return A reference to an initiator. */ public static Initiator getInitiator(String networkPort, DbClient dbClient) { Initiator initiator = null; URIQueryResultList resultsList = new URIQueryResultList(); // find the initiator dbClient.queryByConstraint(AlternateIdConstraint.Factory.getInitiatorPortInitiatorConstraint( networkPort), resultsList); Iterator<URI> resultsIter = resultsList.iterator(); while (resultsIter.hasNext()) { initiator = dbClient.queryObject(Initiator.class, resultsIter.next()); // there should be one initiator, so return as soon as it is found if (initiator != null && !initiator.getInactive()) { return initiator; } } return null; } /** * Check if the mask and the initiator belong to different resource. */ public static boolean checkIfDifferentResource(ExportMask mask, Initiator existingInitiator) { boolean differentResource = false; String maskResource = mask.getResource(); if (!NullColumnValueGetter.isNullValue(maskResource)) { // check only if the mask has resource if (maskResource.startsWith("urn:storageos:Host")) { // We found scenarios where VPLEX Initiators/ports do not have the Host Name set and this is handled below. if (!NullColumnValueGetter.isNullURI(existingInitiator.getHost())) { differentResource = !maskResource.equals(existingInitiator.getHost().toString()); } else { differentResource = true; } } else { differentResource = !maskResource.equals(existingInitiator.getClusterName()); } } return differentResource; } }