Search in sources :

Example 16 with ExportMask

use of com.emc.storageos.db.client.model.ExportMask in project coprhd-controller by CoprHD.

the class VPlexUtil method getSharedStorageView.

/**
 * Pre Darth CorpHD used to create ExportMask per host even if there was single storage view on VPLEX
 * with multiple host. This method returns the storage view name to ExportMasks map which is single
 * storage view on VPLEX with multiple hosts but in ViPR database there is ExportMask per host.
 *
 * @param exportGroup - ExportGroup object
 * @param vplexURI - URI of the VPLEX system
 * @param dbClient - database client instance
 * @return the map of shared storage view name to ExportMasks
 */
public static Map<String, Set<ExportMask>> getSharedStorageView(ExportGroup exportGroup, URI vplexURI, DbClient dbClient) {
    // Map of Storage view name to list of ExportMasks that represent same storage view on VPLEX.
    Map<String, Set<ExportMask>> exportGroupExportMasks = new HashMap<>();
    Map<String, Set<ExportMask>> sharedExportMasks = new HashMap<>();
    if (exportGroup.getExportMasks() == null) {
        return null;
    }
    List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(dbClient, exportGroup, vplexURI);
    for (ExportMask exportMask : exportMasks) {
        if (!exportMask.getInactive()) {
            if (!exportGroupExportMasks.containsKey(exportMask.getMaskName())) {
                exportGroupExportMasks.put(exportMask.getMaskName(), new HashSet<ExportMask>());
            }
            exportGroupExportMasks.get(exportMask.getMaskName()).add(exportMask);
        }
    }
    for (Map.Entry<String, Set<ExportMask>> entry : exportGroupExportMasks.entrySet()) {
        if (entry.getValue().size() > 1) {
            sharedExportMasks.put(entry.getKey(), entry.getValue());
        }
    }
    return sharedExportMasks;
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) StringSet(com.emc.storageos.db.client.model.StringSet) HashMap(java.util.HashMap) ExportMask(com.emc.storageos.db.client.model.ExportMask) Map(java.util.Map) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap)

Example 17 with ExportMask

use of com.emc.storageos.db.client.model.ExportMask in project coprhd-controller by CoprHD.

the class AbstractBasicMaskingOrchestrator method exportGroupRemoveInitiators.

@Override
public void exportGroupRemoveInitiators(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, String token) throws Exception {
    ExportOrchestrationTask taskCompleter = null;
    try {
        BlockStorageDevice device = getDevice();
        taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
        StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
        ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
        StringBuffer errorMessage = new StringBuffer();
        logExportGroup(exportGroup, storageURI);
        // Set up workflow steps.
        Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupRemoveInitiators", true, token);
        Initiator firstInitiator = _dbClient.queryObject(Initiator.class, initiatorURIs.get(0));
        // No need to validate the orchestrator level validation for vplex/rp. Hence ignoring validation for vplex/rp initiators.
        boolean isValidationNeeded = validatorConfig.isValidationEnabled() && !VPlexControllerUtils.isVplexInitiator(firstInitiator, _dbClient) && !ExportUtils.checkIfInitiatorsForRP(Arrays.asList(firstInitiator));
        _log.info("Orchestration level validation needed : {}", isValidationNeeded);
        Map<String, URI> portNameToInitiatorURI = new HashMap<String, URI>();
        List<String> portNames = new ArrayList<String>();
        // Populate the port WWN/IQNs (portNames) and the
        // mapping of the WWN/IQNs to Initiator URIs
        processInitiators(exportGroup, initiatorURIs, portNames, portNameToInitiatorURI);
        // Populate a map of volumes on the storage device associated with this ExportGroup
        List<BlockObject> blockObjects = new ArrayList<BlockObject>();
        if (exportGroup.getVolumes() != null) {
            for (Map.Entry<String, String> entry : exportGroup.getVolumes().entrySet()) {
                URI boURI = URI.create(entry.getKey());
                BlockObject bo = BlockObject.fetch(_dbClient, boURI);
                if (bo.getStorageController().equals(storageURI)) {
                    blockObjects.add(bo);
                }
            }
        }
        List<String> initiatorNames = new ArrayList<String>();
        for (URI initiatorURI : initiatorURIs) {
            Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
            String normalizedName = Initiator.normalizePort(initiator.getInitiatorPort());
            initiatorNames.add(normalizedName);
        }
        _log.info("Normalized initiator names :{}", initiatorNames);
        device.findExportMasks(storage, initiatorNames, false);
        Map<URI, Boolean> initiatorIsPartOfFullListFlags = flagInitiatorsThatArePartOfAFullList(exportGroup, initiatorURIs);
        boolean anyOperationsToDo = false;
        if (exportGroup != null && !ExportMaskUtils.getExportMasks(_dbClient, exportGroup).isEmpty()) {
            // There were some exports out there that already have some or all of the
            // initiators that we are attempting to remove. We need to only
            // remove the volumes that the user added to these masks
            Map<String, Set<URI>> matchingExportMaskURIs = getInitiatorToExportMaskMap(exportGroup);
            // This loop will determine a list of volumes to update per export mask
            Map<URI, List<URI>> existingMasksToRemoveInitiator = new HashMap<URI, List<URI>>();
            Map<URI, List<URI>> existingMasksToRemoveVolumes = new HashMap<URI, List<URI>>();
            for (Map.Entry<String, Set<URI>> entry : matchingExportMaskURIs.entrySet()) {
                URI initiatorURI = portNameToInitiatorURI.get(entry.getKey());
                if (initiatorURI == null || !initiatorURIs.contains(initiatorURI)) {
                    // Entry key points to an initiator that was not passed in the remove request
                    continue;
                }
                Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
                // Get a list of the ExportMasks that were matched to the initiator
                // go through the initiators and figure out the proper intiator and volume ramifications
                // to the existing masks.
                List<URI> exportMaskURIs = new ArrayList<URI>();
                exportMaskURIs.addAll(entry.getValue());
                List<ExportMask> masks = _dbClient.queryObject(ExportMask.class, exportMaskURIs);
                _log.info(String.format("initiator %s masks {%s}", initiator.getInitiatorPort(), Joiner.on(',').join(exportMaskURIs)));
                for (ExportMask mask : masks) {
                    if (mask == null || mask.getInactive() || !mask.getStorageDevice().equals(storageURI)) {
                        continue;
                    }
                    mask = getDevice().refreshExportMask(storage, mask);
                    _log.info(String.format("mask %s has initiator %s", mask.getMaskName(), initiator.getInitiatorPort()));
                    // We cannot remove initiator if there are existing volumes in the mask.
                    if (!isValidationNeeded || !mask.hasAnyExistingVolumes()) {
                        /**
                         * If user asked to remove Host from Cluster
                         * 1. Check if the export mask is shared across other export Groups, if not remove the host.
                         * 2. If shared, check whether all the initiators of host is being asked to remove
                         * 3. If yes, check if atleast one of the other shared export Group is EXCLUSIVE
                         * 4. If yes, then remove the shared volumes
                         *
                         * In all other cases, remove the initiators.
                         */
                        List<ExportGroup> otherExportGroups = ExportUtils.getOtherExportGroups(exportGroup, mask, _dbClient);
                        if (!otherExportGroups.isEmpty() && initiatorIsPartOfFullListFlags.get(initiatorURI) && ExportUtils.exportMaskHasBothExclusiveAndSharedVolumes(exportGroup, otherExportGroups, mask)) {
                            if (!exportGroup.forInitiator()) {
                                List<URI> removeVolumesList = existingMasksToRemoveVolumes.get(mask.getId());
                                if (removeVolumesList == null) {
                                    removeVolumesList = new ArrayList<URI>();
                                    existingMasksToRemoveVolumes.put(mask.getId(), removeVolumesList);
                                }
                                for (String volumeIdStr : exportGroup.getVolumes().keySet()) {
                                    URI egVolumeID = URI.create(volumeIdStr);
                                    if (mask.getUserAddedVolumes().containsValue(volumeIdStr) && !removeVolumesList.contains(egVolumeID)) {
                                        removeVolumesList.add(egVolumeID);
                                    }
                                }
                            } else {
                                // Just a reminder to the world in the case where Initiator is used in this odd situation.
                                _log.info("Removing volumes from an Initiator type export group as part of an initiator removal is not supported.");
                            }
                        } else {
                            _log.info(String.format("We can remove initiator %s from mask %s", initiator.getInitiatorPort(), mask.getMaskName()));
                            List<URI> initiators = existingMasksToRemoveInitiator.get(mask.getId());
                            if (initiators == null) {
                                initiators = new ArrayList<URI>();
                                existingMasksToRemoveInitiator.put(mask.getId(), initiators);
                            }
                            if (!initiators.contains(initiator.getId())) {
                                initiators.add(initiator.getId());
                            }
                        }
                    } else {
                        errorMessage.append(String.format("Mask %s has existing volumes %s", mask.forDisplay(), Joiner.on(", ").join(mask.getExistingVolumes().keySet())));
                    }
                }
            }
            // At this point we have a mapping of masks to objects that we want to remove
            Set<URI> masksGettingRemoved = new HashSet<URI>();
            // In this loop we are trying to remove those initiators that exist
            // on a mask that ViPR created.
            Map<URI, String> stepMap = new HashMap<URI, String>();
            for (Map.Entry<URI, List<URI>> entry : existingMasksToRemoveInitiator.entrySet()) {
                ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
                List<URI> initiatorsToRemove = entry.getValue();
                Set<String> allInitiators = ExportUtils.getExportMaskAllInitiatorPorts(mask, _dbClient);
                List<Initiator> initiatorObjectsToRemove = _dbClient.queryObject(Initiator.class, initiatorsToRemove);
                List<String> initiatorPortNamesToRemove = new ArrayList<>(Collections2.transform(initiatorObjectsToRemove, CommonTransformerFunctions.fctnInitiatorToPortName()));
                allInitiators.removeAll(initiatorPortNamesToRemove);
                if (allInitiators.isEmpty()) {
                    masksGettingRemoved.add(mask.getId());
                    // For this case, we are attempting to remove all the
                    // initiators in the mask. This means that we will have to
                    // delete the
                    // exportGroup
                    _log.info(String.format("mask %s has removed all " + "initiators, we are going to delete the mask from the " + "array", mask.getMaskName()));
                    List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(mask);
                    List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, mask, null), CommonTransformerFunctions.fctnDataObjectToID()));
                    stepMap.put(entry.getKey(), generateDeviceSpecificDeleteWorkflow(workflow, null, exportGroup, mask, maskVolumeURIs, maskInitiatorURIs, storage));
                    anyOperationsToDo = true;
                } else {
                    _log.info(String.format("mask %s - going to remove the " + "following initiators %s", mask.getMaskName(), Joiner.on(',').join(initiatorsToRemove)));
                    Map<URI, List<URI>> maskToInitiatorsMap = new HashMap<URI, List<URI>>();
                    maskToInitiatorsMap.put(mask.getId(), initiatorsToRemove);
                    List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(mask);
                    stepMap.put(entry.getKey(), generateDeviceSpecificRemoveInitiatorsWorkflow(workflow, null, exportGroup, mask, storage, maskToInitiatorsMap, maskVolumeURIs, initiatorsToRemove, true));
                    anyOperationsToDo = true;
                }
            }
            // for the storage array and ExportGroup.
            for (Map.Entry<URI, List<URI>> entry : existingMasksToRemoveVolumes.entrySet()) {
                if (masksGettingRemoved.contains(entry.getKey())) {
                    _log.info("Mask {} is getting removed, no need to remove volumes from it", entry.getKey().toString());
                    continue;
                }
                ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
                List<URI> volumesToRemove = entry.getValue();
                List<URI> initiatorsToRemove = existingMasksToRemoveInitiator.get(mask.getId());
                if (initiatorsToRemove != null) {
                    List<URI> initiatorsInExportMask = ExportUtils.getExportMaskAllInitiators(mask, _dbClient);
                    initiatorsInExportMask.removeAll(initiatorsToRemove);
                    if (!initiatorsInExportMask.isEmpty()) {
                        // There are still some initiators in this ExportMask
                        _log.info(String.format("ExportMask %s would have remaining initiators {%s} that require access to {%s}. " + "Not going to remove any of the volumes", mask.getMaskName(), Joiner.on(',').join(initiatorsInExportMask), Joiner.on(',').join(volumesToRemove)));
                        continue;
                    }
                }
                Collection<String> volumesToRemoveURIStrings = Collections2.transform(volumesToRemove, CommonTransformerFunctions.FCTN_URI_TO_STRING);
                List<String> exportMaskVolumeURIStrings = new ArrayList<String>(mask.getVolumes().keySet());
                exportMaskVolumeURIStrings.removeAll(volumesToRemoveURIStrings);
                if (exportMaskVolumeURIStrings.isEmpty() && !mask.hasAnyExistingVolumes()) {
                    _log.info(String.format("All the volumes (%s) from mask %s will be removed, so will have to remove the whole mask", Joiner.on(",").join(volumesToRemove), mask.getMaskName()));
                    errorMessage.append(String.format("Mask %s will be removed from array. ", mask.forDisplay()));
                    List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(mask);
                    List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, mask, null), CommonTransformerFunctions.fctnDataObjectToID()));
                    generateDeviceSpecificDeleteWorkflow(workflow, null, exportGroup, mask, maskVolumeURIs, maskInitiatorURIs, storage);
                    anyOperationsToDo = true;
                } else {
                    // Null taskID is passed in because the generateExportMaskRemoveVolumesWorkflow will fill it in
                    ExportTaskCompleter completer = new ExportRemoveVolumesOnAdoptedMaskCompleter(exportGroupURI, mask.getId(), volumesToRemove, null);
                    _log.info(String.format("A subset of volumes will be removed from mask %s: %s. ", mask.getMaskName(), Joiner.on(",").join(volumesToRemove)));
                    List<? extends BlockObject> boList = BlockObject.fetchAll(_dbClient, volumesToRemove);
                    if (mask.hasAnyExistingInitiators()) {
                        errorMessage.append(String.format("A subset of volumes will be removed from mask %s: %s. This will affect the %s initiators", mask.getMaskName(), Joiner.on(", ").join(Collections2.transform(boList, CommonTransformerFunctions.fctnDataObjectToForDisplay())), mask.getExistingInitiators()));
                    }
                    List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, mask, null), CommonTransformerFunctions.fctnDataObjectToID()));
                    generateDeviceSpecificRemoveVolumesWorkflow(workflow, stepMap.get(entry.getKey()), exportGroup, mask, storage, volumesToRemove, maskInitiatorURIs, completer);
                    anyOperationsToDo = true;
                }
            }
        }
        if (errorMessage != null && !errorMessage.toString().isEmpty()) {
            _log.warn("Error Message {}", errorMessage);
        }
        if (isValidationNeeded && StringUtils.hasText(errorMessage)) {
            throw DeviceControllerException.exceptions.removeInitiatorValidationError(Joiner.on(", ").join(initiatorNames), storage.getLabel(), errorMessage.toString());
        }
        if (anyOperationsToDo) {
            String successMessage = String.format("Successfully removed exports for initiators on StorageArray %s", storage.getLabel());
            workflow.executePlan(taskCompleter, successMessage);
        } else {
            taskCompleter.ready(_dbClient);
        }
    } catch (Exception e) {
        _log.error("ExportGroup remove initiator Orchestration failed.", e);
        // TODO add service code here
        if (taskCompleter != null) {
            ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(e.getMessage(), e);
            taskCompleter.error(_dbClient, serviceError);
        }
    }
}
Also used : ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) HashSet(java.util.HashSet) Set(java.util.Set) StringSet(com.emc.storageos.db.client.model.StringSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) URI(java.net.URI) BlockStorageDevice(com.emc.storageos.volumecontroller.BlockStorageDevice) Initiator(com.emc.storageos.db.client.model.Initiator) ArrayList(java.util.ArrayList) List(java.util.List) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) HashSet(java.util.HashSet) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) Workflow(com.emc.storageos.workflow.Workflow) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ExportRemoveVolumesOnAdoptedMaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportRemoveVolumesOnAdoptedMaskCompleter) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) HashMap(java.util.HashMap) Map(java.util.Map) StringSetMap(com.emc.storageos.db.client.model.StringSetMap) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask)

Example 18 with ExportMask

use of com.emc.storageos.db.client.model.ExportMask in project coprhd-controller by CoprHD.

the class AbstractBasicMaskingOrchestrator method exportGroupDelete.

@Override
public void exportGroupDelete(URI storageURI, URI exportGroupURI, String token) throws Exception {
    ExportOrchestrationTask taskCompleter = null;
    try {
        taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
        StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
        ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
        String previousStep = null;
        boolean someOperationDone = false;
        logExportGroup(exportGroup, storageURI);
        if (!ExportMaskUtils.getExportMasks(_dbClient, exportGroup).isEmpty() && !exportGroup.getInactive()) {
            // Set up workflow steps.
            Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupDelete", true, token);
            List<ExportMask> exportMasksToZoneDelete = new ArrayList<ExportMask>();
            List<ExportMask> exportMasksToZoneRemoveVolumes = new ArrayList<ExportMask>();
            Set<URI> volumesToZoneRemoveVolumes = new HashSet<URI>();
            List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
            for (ExportMask exportMask : exportMasks) {
                taskCompleter.setMask(exportMask.getId());
                _log.info(String.format("Checking mask %s", exportMask.getMaskName()));
                if (!exportMask.getInactive() && exportMask.getStorageDevice().equals(storageURI)) {
                    exportMask = getDevice().refreshExportMask(storage, exportMask);
                    Collection<URI> volumeURIs = Collections2.transform(exportGroup.getVolumes().keySet(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
                    // One way to know if we should delete the mask is if all of the volumes in the mask
                    // are represented in the export group.
                    boolean deleteEntireMask = removingLastExportMaskVolumes(exportMask, new ArrayList<>(volumeURIs));
                    _log.info("deleteEntireMask for {}? {}", exportMask.getId(), deleteEntireMask);
                    Set<URI> volumesToRemove = new HashSet<>();
                    if (exportGroup.getInitiators() != null && !exportGroup.getInitiators().isEmpty()) {
                        Set<String> egInitiators = new HashSet<String>(exportGroup.getInitiators());
                        for (String initiatorIdStr : egInitiators) {
                            Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(initiatorIdStr));
                            if (initiator == null) {
                                _log.warn("Found that initiator " + initiatorIdStr + " in the export group is no longer in the database, removing from the initiator list.");
                                exportGroup.removeInitiator(URI.create(initiatorIdStr));
                                _dbClient.updateObject(exportGroup);
                                continue;
                            }
                            // Search for this initiator in another export group
                            List<ExportGroup> exportGroupList = ExportUtils.getInitiatorExportGroups(initiator, _dbClient);
                            // We cannot remove initiator from mask if the mask has existing volumes
                            if (exportMask.hasUserInitiator(URI.create(initiatorIdStr)) && !exportMask.hasAnyExistingVolumes()) {
                                // Best to just leave that initiator alone.
                                if ((exportGroupList != null && exportGroupList.size() > 1) && ExportUtils.isExportMaskShared(_dbClient, exportMask.getId(), null)) {
                                    _log.info(String.format("Found that my initiator is in %s more export groups, so we shouldn't remove it from the mask", exportGroupList.size() - 1));
                                    deleteEntireMask = false;
                                }
                            }
                        }
                    }
                    if (deleteEntireMask) {
                        _log.info(String.format("export_delete: export mask %s was either created by system or last volume is being removed.", exportMask.getMaskName()));
                        exportMasksToZoneDelete.add(exportMask);
                        someOperationDone = true;
                    } else {
                        // Volume removal -- check to see if that volume is already in another export group with that initiator.
                        for (String volumeIdStr : exportGroup.getVolumes().keySet()) {
                            URI egVolumeID = URI.create(volumeIdStr);
                            BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, egVolumeID);
                            if (bo != null && exportMask.hasUserCreatedVolume(bo.getId())) {
                                if (exportGroup.getInitiators() != null) {
                                    for (String initiatorIdStr : exportGroup.getInitiators()) {
                                        if (exportMask.hasInitiator(initiatorIdStr)) {
                                            Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(initiatorIdStr));
                                            List<ExportGroup> exportGroupList2 = ExportUtils.getInitiatorVolumeExportGroups(initiator, egVolumeID, _dbClient);
                                            if (exportGroupList2 != null && exportGroupList2.size() > 1) {
                                                _log.info(String.format("Found that my volume %s is in another export group with this initiator %s, so we shouldn't remove it from the mask", volumeIdStr, initiator.getInitiatorPort()));
                                            } else {
                                                _log.info(String.format("We can remove volume %s from mask %s", volumeIdStr, exportMask.getMaskName()));
                                                volumesToRemove.add(egVolumeID);
                                            }
                                        } else if (exportMask.getCreatedBySystem()) {
                                            _log.info(String.format("Export Mask %s does not contain initiator %s, so we will not modify this export mask", exportMask.getId().toString(), initiatorIdStr));
                                        } else {
                                            // We're in a case where there are no user added initiators for this *existing* mask. So, we
                                            // should be able remove any
                                            // of the volumes that we added to the system.
                                            volumesToRemove.add(egVolumeID);
                                        }
                                    }
                                }
                            }
                        }
                        // Remove volume steps are generated based on the initiators we collected for removal.
                        if (!volumesToRemove.isEmpty()) {
                            _log.info(String.format("Mask %s, Removing volumes %s only", exportMask.getMaskName(), Joiner.on(',').join(volumesToRemove)));
                            _log.info(String.format("volumes in mask: %s", Joiner.on(',').join(exportMask.getVolumes().entrySet())));
                            exportMasksToZoneRemoveVolumes.add(exportMask);
                            volumesToZoneRemoveVolumes.addAll(volumesToRemove);
                            List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null), CommonTransformerFunctions.fctnDataObjectToID()));
                            previousStep = generateDeviceSpecificRemoveVolumesWorkflow(workflow, previousStep, exportGroup, exportMask, storage, new ArrayList<URI>(volumesToRemove), maskInitiatorURIs, null);
                            someOperationDone = true;
                        }
                    }
                }
            }
            if (!exportMasksToZoneDelete.isEmpty()) {
                for (ExportMask exportMask : exportMasksToZoneDelete) {
                    List<URI> volumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(exportMask);
                    List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null), CommonTransformerFunctions.fctnDataObjectToID()));
                    previousStep = generateDeviceSpecificExportMaskDeleteWorkflow(workflow, previousStep, exportGroup, exportMask, volumeURIs, maskInitiatorURIs, storage);
                }
                // CTRL-8506 - VNX StorageGroup cannot be deleted because of a race condition with
                // the zoning. This is a live host test case. So, some initiators are still logged
                // in by the time ViPR tries to delete the StorageGroup.
                // General Solution:
                // When we have to delete ExportMask, we'll un-zone first so that any initiators
                // that are possibly logged into the array get a chance to log out. That way, there
                // should not be any problems with removing the ExportMask off the array.
                // 
                // COP-24183: Reversing the order with serialization to prevent DU if mask validation fails.
                previousStep = generateDeviceSpecificZoningDeleteWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneDelete);
            }
            if (!exportMasksToZoneRemoveVolumes.isEmpty()) {
                // Remove all the indicated volumes from the indicated
                // export masks.
                generateDeviceSpecificZoningRemoveVolumesWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneRemoveVolumes, new ArrayList<URI>(volumesToZoneRemoveVolumes));
            }
            String successMessage = String.format("Successfully removed export on StorageArray %s", storage.getLabel());
            workflow.executePlan(taskCompleter, successMessage);
        }
        if (!someOperationDone) {
            taskCompleter.ready(_dbClient);
        }
    } catch (Exception ex) {
        _log.error("ExportGroup Orchestration failed.", ex);
        // TODO add service code here
        if (taskCompleter != null) {
            ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(ex.getMessage(), ex);
            taskCompleter.error(_dbClient, serviceError);
        }
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) Workflow(com.emc.storageos.workflow.Workflow) URI(java.net.URI) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) Initiator(com.emc.storageos.db.client.model.Initiator) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) HashSet(java.util.HashSet)

Example 19 with ExportMask

use of com.emc.storageos.db.client.model.ExportMask in project coprhd-controller by CoprHD.

the class AbstractDefaultMaskingOrchestrator method determineInitiatorToExportMaskPlacements.

/**
 * Routine will examine the ExportGroup object's ExportMask and the passed in map of
 * compute-resource-to-initiators map to produce a mapping of the ExportMasks'
 * initiator port name to a list of ExportMask URIs.
 *
 * @param exportGroup
 *            [in] - ExportGroup object to examine
 * @param storage
 * @param computeResourceToInitiators
 *            [in] - Mapping of compute resource string key to
 *            list of Initiator URIs. @return Map of String to set of URIs. The key will be
 *            Initiator.normalizePort(initiator.portName).
 * @param partialMasks
 *            [out] - list of masks that were found to be "partial" masks, where there are multiple masks that make
 *            up one
 *            compute resource
 *            Value will be set of ExportMask URIs.
 */
protected Map<String, Set<URI>> determineInitiatorToExportMaskPlacements(ExportGroup exportGroup, URI storage, Map<String, List<URI>> computeResourceToInitiators, Map<String, Set<URI>> initiatorToExportMapOnArray, Map<String, URI> portNameToInitiatorURI, Set<URI> partialMasks) {
    Map<String, Set<URI>> initiatorToExportMaskURIMap = new HashMap<String, Set<URI>>();
    Map<String, Set<URI>> computeResourceToExportMaskMap = ExportMaskUtils.mapComputeResourceToExportMask(_dbClient, exportGroup, storage);
    Set<URI> allExportMaskURIs = new HashSet<>();
    // associated with the ExportGroup
    for (Map.Entry<String, List<URI>> entry : computeResourceToInitiators.entrySet()) {
        String computeResource = entry.getKey();
        List<URI> initiatorSet = entry.getValue();
        if (computeResourceToExportMaskMap.get(computeResource) != null) {
            for (URI exportMaskURI : computeResourceToExportMaskMap.get(computeResource)) {
                if (exportMaskURI == null) {
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - No ExportMask for compute resource %s in ExportGroup %s", computeResource, exportGroup.getLabel()));
                    continue;
                }
                for (URI initiatorURI : initiatorSet) {
                    Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
                    if (initiator == null) {
                        continue;
                    }
                    String normalizedName = Initiator.normalizePort(initiator.getInitiatorPort());
                    Set<URI> exportMaskURIs = initiatorToExportMaskURIMap.get(normalizedName);
                    if (exportMaskURIs == null) {
                        exportMaskURIs = new TreeSet<URI>();
                        initiatorToExportMaskURIMap.put(normalizedName, exportMaskURIs);
                    }
                    exportMaskURIs.add(exportMaskURI);
                }
            }
        }
    }
    // when combined, make up a cluster masking view
    for (Map.Entry<String, Set<URI>> entry : initiatorToExportMapOnArray.entrySet()) {
        allExportMaskURIs.addAll(entry.getValue());
    }
    Collection<URI> volumes = new HashSet<URI>();
    if (exportGroup.getVolumes() != null) {
        volumes = Collections2.transform(exportGroup.getVolumes().keySet(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
    }
    ExportPathParams exportPathParams = _blockScheduler.calculateExportPathParamForVolumes(volumes, 0, storage, exportGroup.getId());
    _log.info(String.format("determineInitiatorToExportMaskPlacements - ExportGroup=%s, exportPathParams=%s", exportGroup.getId().toString(), exportPathParams));
    URI portGroup = exportPathParams.getPortGroup();
    _log.info(String.format("Port group: %s", portGroup));
    // Update mapping based on what is seen on the array
    for (Map.Entry<String, Set<URI>> entry : initiatorToExportMapOnArray.entrySet()) {
        String portName = entry.getKey();
        // Validate this initiator and determine if it exists in the database
        URI initiatorURI = portNameToInitiatorURI.get(portName);
        if (initiatorURI == null) {
            URIQueryResultList uris = new URIQueryResultList();
            _dbClient.queryByConstraint(AlternateIdConstraint.Factory.getInitiatorPortInitiatorConstraint(portName), uris);
            if (!uris.iterator().hasNext()) {
                // There is no such initiator
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Could not find initiator port %s in DB", portName));
                continue;
            }
            initiatorURI = uris.iterator().next();
        }
        // We should have a non-null initiator URI at this point
        Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
        if (initiator == null) {
            _log.info(String.format("determineInitiatorToExportMaskPlacements - Initiator %s does not exist in DB", initiatorURI.toString()));
            continue;
        }
        _log.info(String.format("determineInitiatorToExportMaskPlacements - Scanning masks that contain initiator %s to see if those masks qualify for consideration for re-use", initiator.getInitiatorPort()));
        // This container is for capturing those ExportMasks that we find to
        // be matching based on the initiators, but unusable based on the
        // StoragePorts that the mask has. Basically, in order for a mask to
        // be considered a match, the initiators have to match, but the
        // StoragePorts have to be in the same Network as the ExportGroup's
        // VArray Network.
        Map<URI, Map<String, String>> masksWithUnmatchedStoragePorts = new HashMap<URI, Map<String, String>>();
        // Take a look at the ExportMask's initiators to see what compute resource that they support.
        String computeResource = ExportUtils.computeResourceForInitiator(exportGroup, initiator);
        List<URI> uriList = computeResourceToInitiators.get(computeResource);
        List<String> portsForComputeResource = new ArrayList<String>();
        Iterator<Initiator> iterator = _dbClient.queryIterativeObjects(Initiator.class, uriList);
        while (iterator.hasNext()) {
            portsForComputeResource.add(iterator.next().getInitiatorPort());
        }
        // At this point we have a non-null initiator object that we can use in the mapping
        Map<URI, Integer> maskToTotalMatchingPorts = new HashMap<URI, Integer>();
        int totalPorts = 0;
        Set<URI> candidateExportMaskURIs = new HashSet<URI>();
        Set<URI> exportMaskURIs = entry.getValue();
        for (URI exportMaskURI : exportMaskURIs) {
            ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
            if (mask == null || mask.getInactive()) {
                continue;
            }
            _log.info(String.format("determineInitiatorToExportMaskPlacements - Checking to see if we can consider mask %s, given its initiators, storage ports, and volumes", mask.getMaskName()));
            // Check for NO_VIPR. If found, avoid this mask.
            if (mask.getMaskName() != null && mask.getMaskName().toUpperCase().contains(ExportUtils.NO_VIPR)) {
                _log.info(String.format("ExportMask %s disqualified because the name contains %s (in upper or lower case) to exclude it", mask.getMaskName(), ExportUtils.NO_VIPR));
                continue;
            }
            Map<String, String> storagePortToNetworkName = new HashMap<String, String>();
            if (mask.getCreatedBySystem()) {
                if (mask.getResource().equals(computeResource)) {
                    if (maskHasPortGroup(mask, portGroup) && maskHasStoragePortsInExportVarray(exportGroup, mask, initiator, storagePortToNetworkName)) {
                        _log.info(String.format("determineInitiatorToExportMaskPlacements - ViPR-created mask %s qualifies for consideration for re-use", mask.getMaskName()));
                        candidateExportMaskURIs.add(exportMaskURI);
                        totalPorts += storagePortToNetworkName.keySet().size();
                        maskToTotalMatchingPorts.put(exportMaskURI, totalPorts);
                    // Ingest Fix : In ingest case, more than 1 export mask with createdBySystem flag set to
                    // true is possible
                    // remove the break statement
                    // break; First ViPR-created ExportMask associated with the resource, we will use
                    } else {
                        masksWithUnmatchedStoragePorts.put(exportMaskURI, storagePortToNetworkName);
                        _log.info(String.format("determineInitiatorToExportMaskPlacements - ViPR-created mask %s does not qualify for consideration for re-use due to storage ports mismatch with varray.", mask.getMaskName()));
                    }
                } else {
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - ViPR-created mask %s does not qualify for consideration for re-use due to compute resource mismatch.", mask.getMaskName()));
                }
            } else if (maskHasInitiatorsBasedOnExportType(exportGroup, mask, initiator, portsForComputeResource) || maskHasInitiatorsBasedOnExportType(exportGroup, mask, allExportMaskURIs, portsForComputeResource, partialMasks)) {
                if (maskHasPortGroup(mask, portGroup) && maskHasStoragePortsInExportVarray(exportGroup, mask, initiator, storagePortToNetworkName)) {
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - Pre-existing mask %s qualifies for consideration for re-use", mask.getMaskName()));
                    // This is a non-ViPR create ExportMask and it has the initiator
                    // as an existing initiator. Add it this as a matching candidate
                    candidateExportMaskURIs.add(exportMaskURI);
                    // We don't have zone ingest information for pre-existing masks, so for the purpose of
                    // matching more coexistence masks, we assume there are zones from every port to every
                    // initiator in the mask.
                    // Existing Initiators - initiators which are not userAdded.
                    int existingInitiators = mask.getExistingInitiators() == null ? 0 : mask.getExistingInitiators().size();
                    int userAddedInitators = mask.getUserAddedInitiators() == null ? 0 : mask.getUserAddedInitiators().size();
                    int totalInitiators = existingInitiators + userAddedInitators;
                    totalPorts += storagePortToNetworkName.keySet().size() * totalInitiators;
                    maskToTotalMatchingPorts.put(exportMaskURI, totalPorts);
                } else {
                    masksWithUnmatchedStoragePorts.put(exportMaskURI, storagePortToNetworkName);
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - Pre-existing mask %s does not qualify for consideration for re-use due to storage ports mismatch with varray.", mask.getMaskName()));
                }
            } else {
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Pre-existing mask %s does not qualify for consideration for re-use due to initiators not suitable for export group type.", mask.getMaskName()));
            }
        }
        if (!candidateExportMaskURIs.isEmpty()) {
            if (validateCandidateMasksAgainstExportPathParams(exportPathParams, maskToTotalMatchingPorts)) {
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Initiator %s (%s) will be mapped to these ExportMask URIs: %s", portName, initiatorURI.toString(), Joiner.on(',').join(exportMaskURIs)));
                initiatorToExportMaskURIMap.put(portName, candidateExportMaskURIs);
            }
        } else {
            if (masksWithUnmatchedStoragePorts.isEmpty()) {
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Could not find ExportMask to which %s can be associated", portName));
            } else {
                // We found matching exports on the array, but they were not viable due to
                // the StoragePorts used (they were pointing to a different VArray), so we should
                // warn the user in this case. We will likely still attempt to make a new mask,
                // so if the user doesn't prefer that, this message will tell them why we took that
                // path.
                StringBuilder exportMaskInfo = new StringBuilder();
                for (Map.Entry<URI, Map<String, String>> maskToStoragePortsEntry : masksWithUnmatchedStoragePorts.entrySet()) {
                    URI exportMaskURI = maskToStoragePortsEntry.getKey();
                    Map<String, String> storagePortToNetworks = maskToStoragePortsEntry.getValue();
                    ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
                    exportMaskInfo.append(String.format("MaskingView=%s StoragePorts [ %s ]%n", mask.getMaskName(), Joiner.on(',').join(storagePortToNetworks.entrySet())));
                }
                VirtualArray virtualArray = _dbClient.queryObject(VirtualArray.class, exportGroup.getVirtualArray());
                Exception e = DeviceControllerException.exceptions.existingExportFoundButWithSPsInDifferentNetwork(virtualArray.getLabel(), exportMaskInfo.toString());
                _log.warn(e.getMessage());
            }
        }
    }
    _log.info(String.format("determineInitiatorToExportMaskPlacements - initiatorToExportMaskURIMap: %s", Joiner.on(',').join(initiatorToExportMaskURIMap.entrySet())));
    return initiatorToExportMaskURIMap;
}
Also used : VirtualArray(com.emc.storageos.db.client.model.VirtualArray) Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) URI(java.net.URI) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) Initiator(com.emc.storageos.db.client.model.Initiator) List(java.util.List) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) HashSet(java.util.HashSet) ExportMask(com.emc.storageos.db.client.model.ExportMask) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint) ContainmentConstraint(com.emc.storageos.db.client.constraint.ContainmentConstraint) WorkflowException(com.emc.storageos.workflow.WorkflowException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) IOException(java.io.IOException) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams)

Example 20 with ExportMask

use of com.emc.storageos.db.client.model.ExportMask in project coprhd-controller by CoprHD.

the class AbstractDefaultMaskingOrchestrator method getInitiatorToExportMaskMap.

/**
 * Routine will examine the ExportGroup object's ExportMask and produce a mapping of the ExportMasks'
 * initiator port name to a list of ExportMask URIs.
 *
 * @param exportGroup
 *            [in] - ExportGroup object to examine
 * @return Map of String to set of URIs. The key will be Initiator.normalizePort(initiator.portName).
 *         Value will be set of ExportMask URIs.
 */
protected Map<String, Set<URI>> getInitiatorToExportMaskMap(ExportGroup exportGroup) {
    Map<String, Set<URI>> mapping = new HashMap<String, Set<URI>>();
    for (ExportMask exportMask : ExportMaskUtils.getExportMasks(_dbClient, exportGroup)) {
        if (ExportMaskUtils.isUsable(exportMask)) {
            Set<Initiator> initiators = ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null);
            for (Initiator initiator : initiators) {
                String name = Initiator.normalizePort(initiator.getInitiatorPort());
                Set<URI> maskURIs = mapping.get(name);
                if (maskURIs == null) {
                    maskURIs = new HashSet<URI>();
                    mapping.put(name, maskURIs);
                }
                maskURIs.add(exportMask.getId());
            }
        }
    }
    return mapping;
}
Also used : Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Initiator(com.emc.storageos.db.client.model.Initiator) ExportMask(com.emc.storageos.db.client.model.ExportMask) URI(java.net.URI)

Aggregations

ExportMask (com.emc.storageos.db.client.model.ExportMask)368 URI (java.net.URI)274 ArrayList (java.util.ArrayList)224 Initiator (com.emc.storageos.db.client.model.Initiator)155 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)140 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)134 HashMap (java.util.HashMap)128 HashSet (java.util.HashSet)121 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)107 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)102 List (java.util.List)79 StringSet (com.emc.storageos.db.client.model.StringSet)68 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)65 Map (java.util.Map)65 StringMap (com.emc.storageos.db.client.model.StringMap)60 BlockObject (com.emc.storageos.db.client.model.BlockObject)56 NamedURI (com.emc.storageos.db.client.model.NamedURI)56 Workflow (com.emc.storageos.workflow.Workflow)54 Set (java.util.Set)51 Volume (com.emc.storageos.db.client.model.Volume)44