Search in sources :

Example 31 with ExportOrchestrationTask

use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.

the class ScaleIOMaskingOrchestrator method exportGroupAddVolumes.

@Override
public void exportGroupAddVolumes(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap, String token) throws Exception {
    /*
         * foreach volume in list
         * foreach initiator in ExportGroup
         * scli map --volume volid --sdc initiator.sdcid
         */
    ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
    try {
        ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
        StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
        List<URI> initiatorURIs = StringSetUtil.stringSetToUriList(exportGroup.getInitiators());
        if (initiatorURIs != null && !initiatorURIs.isEmpty()) {
            // Set up workflow steps.
            Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupAddVolumes", true, token);
            // Create a mapping of ExportMasks to Add Volumes to or
            // add to a list of new Exports to create
            Map<URI, Map<URI, Integer>> exportMaskToVolumesToAdd = new HashMap<>();
            List<URI> initiatorsToPlace = new ArrayList<>(initiatorURIs);
            // Need to figure out which ExportMasks to add volumes to.
            for (ExportMask exportMask : ExportMaskUtils.getExportMasks(_dbClient, exportGroup, storageURI)) {
                if (exportMask.hasAnyInitiators()) {
                    exportMaskToVolumesToAdd.put(exportMask.getId(), volumeMap);
                    for (String uriString : exportMask.getInitiators()) {
                        URI initiatorURI = URI.create(uriString);
                        initiatorsToPlace.remove(initiatorURI);
                    }
                }
            }
            Map<String, List<URI>> computeResourceToInitiators = mapInitiatorsToComputeResource(exportGroup, initiatorsToPlace);
            log.info(String.format("Need to create ExportMasks for these compute resources %s", Joiner.on(',').join(computeResourceToInitiators.entrySet())));
            // volumes from 'storage' StorageSystem to this ExportGroup
            for (Map.Entry<String, List<URI>> toCreate : computeResourceToInitiators.entrySet()) {
                generateExportMaskCreateWorkflow(workflow, null, storage, exportGroup, toCreate.getValue(), volumeMap, token);
            }
            log.info(String.format("Need to add volumes for these ExportMasks %s", exportMaskToVolumesToAdd.entrySet()));
            // We already know about the ExportMask, so we just add volumes to it
            for (Map.Entry<URI, Map<URI, Integer>> toAddVolumes : exportMaskToVolumesToAdd.entrySet()) {
                ExportMask exportMask = _dbClient.queryObject(ExportMask.class, toAddVolumes.getKey());
                generateExportMaskAddVolumesWorkflow(workflow, null, storage, exportGroup, exportMask, toAddVolumes.getValue(), null);
            }
            String successMessage = String.format("ExportGroup add volumes successfully applied for StorageArray %s", storage.getLabel());
            workflow.executePlan(taskCompleter, successMessage);
        } else {
            taskCompleter.ready(_dbClient);
        }
    } catch (DeviceControllerException dex) {
        taskCompleter.error(_dbClient, DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("exportGroupAddVolumes", dex.getMessage()));
    } catch (Exception ex) {
        _log.error("ExportGroup Orchestration failed.", ex);
        taskCompleter.error(_dbClient, DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("exportGroupAddVolumes", ex.getMessage()));
    }
}
Also used : HashMap(java.util.HashMap) 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) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 32 with ExportOrchestrationTask

use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.

the class AbstractBasicMaskingOrchestrator method exportGroupChangePathParams.

@Override
public void exportGroupChangePathParams(URI storageURI, URI exportGroupURI, URI volumeURI, String token) throws Exception {
    ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
    ExportPathUpdater updater = new ExportPathUpdater(_dbClient);
    try {
        Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupChangePathParams", true, token);
        ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
        StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
        BlockObject volume = BlockObject.fetch(_dbClient, volumeURI);
        _log.info(String.format("Changing path parameters for volume %s (%s)", volume.getLabel(), volume.getId()));
        // Call the ExportPathUpdater to generate Workflow steps necessary to change
        // the path parameters. It will analyze the ExportGroups versus the ExportParams in
        // the VPool of the volume, and call increaseMaxPaths if necessary.
        updater.generateExportGroupChangePathParamsWorkflow(workflow, _blockScheduler, this, storage, exportGroup, volume, token);
        if (!workflow.getAllStepStatus().isEmpty()) {
            _log.info("The changePathParams workflow has {} steps. Starting the workflow.", workflow.getAllStepStatus().size());
            workflow.executePlan(taskCompleter, "Update the export group on all export masks successfully.");
        } else {
            taskCompleter.ready(_dbClient);
        }
    } catch (Exception ex) {
        _log.error("ExportGroup Orchestration failed.", ex);
        ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(ex.getMessage(), ex);
        taskCompleter.error(_dbClient, serviceError);
    }
}
Also used : ExportPathUpdater(com.emc.storageos.volumecontroller.placement.ExportPathUpdater) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Workflow(com.emc.storageos.workflow.Workflow) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask) BlockObject(com.emc.storageos.db.client.model.BlockObject) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 33 with ExportOrchestrationTask

use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.

the class AbstractBasicMaskingOrchestrator method exportGroupAddInitiators.

@Override
public void exportGroupAddInitiators(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, String token) throws Exception {
    BlockStorageDevice device = getDevice();
    String previousStep = null;
    ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
    StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
    ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
    logExportGroup(exportGroup, storageURI);
    // Set up workflow steps.
    Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupAddInitiators", true, token);
    Map<URI, List<URI>> zoneMasksToInitiatorsURIs = new HashMap<URI, List<URI>>();
    Map<URI, Map<URI, Integer>> zoneNewMasksToVolumeMap = new HashMap<URI, Map<URI, Integer>>();
    Map<URI, ExportMask> refreshedMasks = new HashMap<URI, ExportMask>();
    List<URI> hostURIs = new ArrayList<URI>();
    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, hostURIs);
    // Populate a map of volumes on the storage device
    List<BlockObject> blockObjects = new ArrayList<BlockObject>();
    Map<URI, Integer> volumeMap = new HashMap<URI, Integer>();
    if (exportGroup.getVolumes() != null) {
        for (Map.Entry<String, String> entry : exportGroup.getVolumes().entrySet()) {
            URI boURI = URI.create(entry.getKey());
            Integer hlu = Integer.valueOf(entry.getValue());
            BlockObject bo = BlockObject.fetch(_dbClient, boURI);
            if (bo.getStorageController().equals(storageURI)) {
                volumeMap.put(boURI, hlu);
                blockObjects.add(bo);
            }
        }
    }
    // We always want to have the full list of initiators for the hosts involved in
    // this export. This will allow the export operation to always find any
    // existing exports for a given host.
    queryHostInitiatorsAndAddToList(portNames, portNameToInitiatorURI, initiatorURIs, hostURIs);
    boolean anyOperationsToDo = false;
    Map<String, Set<URI>> matchingExportMaskURIs = device.findExportMasks(storage, portNames, false);
    if (matchingExportMaskURIs != null && !matchingExportMaskURIs.isEmpty()) {
        // There were some exports out there that already have some or all of the
        // initiators that we are attempting to add. We need to only add
        // volumes to those existing exports.
        List<URI> initiatorURIsCopy = new ArrayList<URI>();
        initiatorURIsCopy.addAll(initiatorURIs);
        // This loop will determine a list of volumes to update per export mask
        Map<URI, Map<URI, Integer>> existingMasksToUpdateWithNewVolumes = new HashMap<URI, Map<URI, Integer>>();
        Map<URI, Set<Initiator>> existingMasksToUpdateWithNewInitiators = new HashMap<URI, Set<Initiator>>();
        for (Map.Entry<String, Set<URI>> entry : matchingExportMaskURIs.entrySet()) {
            URI initiatorURI = portNameToInitiatorURI.get(entry.getKey());
            Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
            initiatorURIsCopy.remove(initiatorURI);
            // Get a list of the ExportMasks that were matched to the initiator
            List<URI> exportMaskURIs = new ArrayList<URI>();
            exportMaskURIs.addAll(entry.getValue());
            List<ExportMask> masks = _dbClient.queryObject(ExportMask.class, exportMaskURIs);
            _log.info(String.format("initiator %s is in these masks {%s}", initiator.getInitiatorPort(), Joiner.on(',').join(exportMaskURIs)));
            for (ExportMask mask : masks) {
                // 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;
                }
                if (!refreshedMasks.containsKey(mask.getId())) {
                    mask = getDevice().refreshExportMask(storage, mask);
                    refreshedMasks.put(mask.getId(), mask);
                }
                _log.info(String.format("mask %s has initiator %s", mask.getMaskName(), initiator.getInitiatorPort()));
                if (!mask.getInactive() && mask.getStorageDevice().equals(storageURI)) {
                    // already in the masks to the placement list
                    for (BlockObject blockObject : blockObjects) {
                        if (!mask.hasExistingVolume(blockObject.getWWN()) && !mask.hasUserAddedVolume(blockObject.getWWN())) {
                            Map<URI, Integer> newVolumesMap = existingMasksToUpdateWithNewVolumes.get(mask.getId());
                            if (newVolumesMap == null) {
                                newVolumesMap = new HashMap<URI, Integer>();
                                existingMasksToUpdateWithNewVolumes.put(mask.getId(), newVolumesMap);
                            }
                            newVolumesMap.put(blockObject.getId(), volumeMap.get(blockObject.getId()));
                        }
                    }
                    // in our export group, because we would simply add to them.
                    if (mask.getInitiators() != null) {
                        for (String existingMaskInitiatorStr : mask.getInitiators()) {
                            // Now look at it from a different angle. Which one of our export group initiators
                            // are NOT in the current mask? And if so, if it belongs to the same host as an existing one,
                            // we should add it to this mask.
                            Iterator<URI> initiatorIter = initiatorURIsCopy.iterator();
                            while (initiatorIter.hasNext()) {
                                Initiator initiatorCopy = _dbClient.queryObject(Initiator.class, initiatorIter.next());
                                if (!mask.hasInitiator(initiatorCopy.getId().toString())) {
                                    Initiator existingMaskInitiator = _dbClient.queryObject(Initiator.class, URI.create(existingMaskInitiatorStr));
                                    if (initiatorCopy.getHost().equals(existingMaskInitiator.getHost())) {
                                        // Add to the list of initiators we need to add to this mask
                                        Set<Initiator> existingMaskInitiators = existingMasksToUpdateWithNewInitiators.get(mask.getId());
                                        if (existingMaskInitiators == null) {
                                            existingMaskInitiators = new HashSet<Initiator>();
                                            existingMasksToUpdateWithNewInitiators.put(mask.getId(), existingMaskInitiators);
                                        }
                                        if (!existingMaskInitiators.contains(initiatorCopy)) {
                                            existingMaskInitiators.add(initiatorCopy);
                                        }
                                        // remove this from the list of initiators we'll make a new mask from
                                        initiatorIter.remove();
                                    }
                                }
                            }
                        }
                    }
                }
                updateZoningMap(exportGroup, mask, true);
            }
        }
        // The initiatorURIsCopy was used in the foreach initiator loop to see
        // which initiators already exist in a mask. If it is non-empty,
        // then it means there are initiators that are new,
        // so let's add them to the main tracker
        Map<URI, List<URI>> hostInitiatorMap = new HashMap<URI, List<URI>>();
        if (!initiatorURIsCopy.isEmpty()) {
            for (URI newExportMaskInitiator : initiatorURIsCopy) {
                Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
                List<URI> initiatorSet = hostInitiatorMap.get(initiator.getHost());
                if (initiatorSet == null) {
                    initiatorSet = new ArrayList<URI>();
                    hostInitiatorMap.put(initiator.getHost(), initiatorSet);
                }
                initiatorSet.add(initiator.getId());
                _log.info(String.format("host = %s, " + "initiators to add: %d, " + "existingMasksToUpdateWithNewVolumes.size = %d", initiator.getHost(), hostInitiatorMap.get(initiator.getHost()).size(), existingMasksToUpdateWithNewVolumes.size()));
            }
        }
        for (URI host : hostInitiatorMap.keySet()) {
            // Create two steps, one for Zoning, one for the ExportGroup actions.
            // This step is for zoning. It is not specific to a single NetworkSystem,
            // as it will look at all the initiators and targets and compute the
            // zones required (which might be on multiple NetworkSystems.)
            GenExportMaskCreateWorkflowResult result = generateExportMaskCreateWorkflow(workflow, previousStep, storage, exportGroup, hostInitiatorMap.get(host), volumeMap, token);
            previousStep = result.getStepId();
            zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
            anyOperationsToDo = true;
            previousStep = result.getStepId();
        }
        _log.info(String.format("existingMasksToUpdateWithNewVolumes.size = %d", existingMasksToUpdateWithNewVolumes.size()));
        _log.info(String.format("existingMasksToUpdateWithNewInitiators.size = %d", existingMasksToUpdateWithNewInitiators.size()));
        previousStep = checkForSnapshotsToCopyToTarget(workflow, storage, previousStep, volumeMap, existingMasksToUpdateWithNewVolumes.values());
        // stepMap [URI, String] => [Export Mask URI, StepId of previous task i.e. Add volumes work flow.]
        for (Map.Entry<URI, Map<URI, Integer>> entry : existingMasksToUpdateWithNewVolumes.entrySet()) {
            ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
            Map<URI, Integer> volumesToAdd = entry.getValue();
            _log.info(String.format("adding these volumes %s to mask %s", Joiner.on(",").join(volumesToAdd.keySet()), mask.getMaskName()));
            List<URI> volumeURIs = new ArrayList<URI>();
            volumeURIs.addAll(volumesToAdd.keySet());
            previousStep = generateDeviceSpecificAddVolumeWorkFlow(workflow, previousStep, storage, exportGroup, mask, volumesToAdd, volumeURIs, null);
            anyOperationsToDo = true;
        }
        // At this point we have a mapping of all the masks that we need to update with new initiators
        for (Entry<URI, Set<Initiator>> entry : existingMasksToUpdateWithNewInitiators.entrySet()) {
            ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
            Set<Initiator> initiatorsToAdd = entry.getValue();
            List<URI> initiatorsURIs = new ArrayList<URI>();
            for (Initiator initiator : initiatorsToAdd) {
                initiatorsURIs.add(initiator.getId());
            }
            _log.info(String.format("adding these initiators %s to mask %s", Joiner.on(",").join(initiatorsURIs), mask.getMaskName()));
            Map<URI, List<URI>> maskToInitiatorsMap = new HashMap<URI, List<URI>>();
            maskToInitiatorsMap.put(mask.getId(), initiatorURIs);
            previousStep = generateDeviceSpecificAddInitiatorWorkFlow(workflow, previousStep, storage, exportGroup, mask, null, initiatorsURIs, maskToInitiatorsMap, token);
            anyOperationsToDo = true;
        }
    } else {
        // None of the initiators that we're trying to add exist on the
        // array in some export. We need to find the ExportMask that was created by
        // the system and add the new initiator(s) to it.
        boolean foundASystemCreatedMask = false;
        Map<String, List<URI>> hostInitiatorMap = new HashMap<String, List<URI>>();
        if (!initiatorURIs.isEmpty()) {
            for (URI newExportMaskInitiator : initiatorURIs) {
                Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
                if (initiator != null) {
                    String hostURIString = initiator.getHost().toString();
                    List<URI> initiatorSet = hostInitiatorMap.get(hostURIString);
                    if (initiatorSet == null) {
                        hostInitiatorMap.put(initiator.getHost().toString(), new ArrayList<URI>());
                        initiatorSet = hostInitiatorMap.get(hostURIString);
                    }
                    initiatorSet.add(initiator.getId());
                    _log.info(String.format("host = %s, " + "initiators to add: %d, ", initiator.getHost(), hostInitiatorMap.get(hostURIString).size()));
                }
            }
        }
        List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
        if (!exportMasks.isEmpty()) {
            _log.info("There are export masks for this group. Adding initiators.");
            // the storage system that were created by Bourne and are still active.
            for (ExportMask exportMask : exportMasks) {
                if (exportMask != null && !exportMask.getInactive() && exportMask.getStorageDevice().equals(storageURI) && exportMask.getCreatedBySystem()) {
                    List<URI> newInitiators = hostInitiatorMap.get(exportMask.getResource());
                    if (newInitiators != null && !newInitiators.isEmpty()) {
                        zoneMasksToInitiatorsURIs.put(exportMask.getId(), newInitiators);
                        previousStep = generateDeviceSpecificExportMaskAddInitiatorsWorkflow(workflow, previousStep, storage, exportGroup, exportMask, null, newInitiators, token);
                        foundASystemCreatedMask = true;
                        anyOperationsToDo = true;
                    }
                }
            }
        }
        if (!foundASystemCreatedMask) {
            List<String> volumeURIsWithoutHLUs = ExportUtils.findVolumesWithoutHLUs(exportGroup);
            if (!volumeURIsWithoutHLUs.isEmpty()) {
                // will get consistent HLUs applied for their volumes
                for (ExportMask exportMask : ExportMaskUtils.getExportMasks(_dbClient, exportGroup)) {
                    Map<URI, Integer> refreshedVolumeMap = device.getExportMaskHLUs(storage, exportMask);
                    if (!refreshedVolumeMap.isEmpty()) {
                        ExportUtils.reconcileHLUs(_dbClient, exportGroup, exportMask, volumeMap);
                        _dbClient.updateObject(exportGroup);
                        for (URI uri : refreshedVolumeMap.keySet()) {
                            Integer hlu = refreshedVolumeMap.get(uri);
                            if (volumeMap.containsKey(uri)) {
                                volumeMap.put(uri, hlu);
                            }
                        }
                        _log.info(String.format("ExportMask %s (%s) will be updated with these volumes %s", exportMask.getMaskName(), exportMask.getId(), CommonTransformerFunctions.collectionString(volumeMap.entrySet())));
                        // Do the reconciliation once, based on the first non-empty refreshedVolumeMap that's found
                        break;
                    }
                }
            }
            _log.info("There are no masks for this export. Need to create anew.");
            for (String host : hostInitiatorMap.keySet()) {
                // Zoning is done for the new masks identified i.e. zoneNewMasksToVolumeMap.
                GenExportMaskCreateWorkflowResult result = generateDeviceSpecificExportMaskCreateWorkFlow(workflow, previousStep, storage, exportGroup, hostInitiatorMap.get(host), volumeMap, token);
                previousStep = result.getStepId();
                zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
                anyOperationsToDo = true;
            }
        }
    }
    if (anyOperationsToDo) {
        if (!zoneNewMasksToVolumeMap.isEmpty()) {
            List<URI> exportMaskList = new ArrayList<URI>();
            exportMaskList.addAll(zoneNewMasksToVolumeMap.keySet());
            Map<URI, Integer> overallVolumeMap = new HashMap<URI, Integer>();
            for (Map<URI, Integer> oneVolumeMap : zoneNewMasksToVolumeMap.values()) {
                overallVolumeMap.putAll(oneVolumeMap);
            }
            previousStep = generateDeviceSpecificZoningCreateWorkflow(workflow, previousStep, exportGroup, exportMaskList, overallVolumeMap);
        }
        if (!zoneMasksToInitiatorsURIs.isEmpty()) {
            previousStep = generateDeviceSpecificZoningAddInitiatorsWorkflow(workflow, previousStep, exportGroup, zoneMasksToInitiatorsURIs);
        }
        String successMessage = String.format("Successfully exported to initiators on StorageArray %s", storage.getLabel());
        workflow.executePlan(taskCompleter, successMessage);
    } else {
        _log.info("There were no operations to perform.  Mask may already be in desired state.");
        taskCompleter.ready(_dbClient);
    }
}
Also used : 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) ExportMask(com.emc.storageos.db.client.model.ExportMask) Workflow(com.emc.storageos.workflow.Workflow) 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 34 with ExportOrchestrationTask

use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.

the class AbstractBasicMaskingOrchestrator method portRebalance.

@Override
public void portRebalance(URI storageSystem, URI exportGroupURI, URI varray, URI exportMaskURI, Map<URI, List<URI>> adjustedPaths, Map<URI, List<URI>> removedPaths, boolean isAdd, String token) throws Exception {
    String workflowKey = "exportMaskExportPathAdjustment";
    if (_workflowService.hasWorkflowBeenCreated(token, workflowKey)) {
        return;
    }
    Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), workflowKey, false, token);
    ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
    try {
        StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageSystem);
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
        if (isAdd) {
            Map<URI, List<URI>> newPaths = getNewPathsForExportMask(exportMask, adjustedPaths);
            generateExportMaskAddPathsWorkflow(workflow, storage, exportGroupURI, exportMaskURI, newPaths, null);
        } else {
            generateExportMaskRemovePathsWorkflow(workflow, storage, exportGroupURI, exportMaskURI, adjustedPaths, removedPaths, null);
        }
        if (!workflow.getAllStepStatus().isEmpty()) {
            _log.info("The port rebalance workflow has {} steps. Starting the workflow.", workflow.getAllStepStatus().size());
            workflow.executePlan(taskCompleter, "Update the export group on all export masks successfully.");
            _workflowService.markWorkflowBeenCreated(token, workflowKey);
        } else {
            taskCompleter.ready(_dbClient);
        }
    } catch (Exception ex) {
        _log.error("ExportGroup port rebalance failed.", ex);
        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) Workflow(com.emc.storageos.workflow.Workflow) ArrayList(java.util.ArrayList) List(java.util.List) URI(java.net.URI) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 35 with ExportOrchestrationTask

use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.

the class AbstractBasicMaskingOrchestrator method exportGroupRemoveVolumes.

@Override
public void exportGroupRemoveVolumes(URI storageURI, URI exportGroupURI, List<URI> volumeURIs, 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);
        logExportGroup(exportGroup, storageURI);
        String previousStep = null;
        boolean generatedWorkFlowSteps = false;
        if (!ExportMaskUtils.getExportMasks(_dbClient, exportGroup).isEmpty()) {
            // Set up workflow steps.
            Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupRemoveVolumes", true, token);
            List<ExportMask> exportMasksToZoneDelete = new ArrayList<ExportMask>();
            List<ExportMask> exportMasksToZoneRemoveVolumes = new ArrayList<ExportMask>();
            List<ExportMask> exportMasksToDelete = new ArrayList<ExportMask>();
            List<URI> volumesToZoneRemoveVolumes = new ArrayList<URI>();
            List<ExportMask> tempMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
            for (ExportMask tempMask : tempMasks) {
                _log.info(String.format("Checking mask %s", tempMask.getMaskName()));
                if (!tempMask.getInactive() && tempMask.getStorageDevice().equals(storageURI)) {
                    tempMask = device.refreshExportMask(storage, tempMask);
                    // BlockStorageDevice level, so that it has up-to-date
                    // info from the array
                    Set<URI> volumesToRemove = new HashSet<URI>();
                    // If they specify to delete all volumes, we qualify to delete the whole mask.
                    // Otherwise, no chance of us deleting masks as part of this operation because
                    // each mask will still have at least one volume in it.
                    boolean removingLastVolumeFromMask = removingLastExportMaskVolumes(tempMask, new ArrayList<>(volumeURIs));
                    boolean anyVolumesFoundInAnotherExportGroup = false;
                    // check to see if the export mask has other initiators that aren't being removed.
                    for (URI egVolumeID : volumeURIs) {
                        String volumeIdStr = egVolumeID.toString();
                        BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, egVolumeID);
                        if (bo != null && tempMask.hasUserCreatedVolume(bo.getId())) {
                            if (exportGroup.getInitiators() != null) {
                                for (String initiatorIdStr : exportGroup.getInitiators()) {
                                    if (tempMask.hasInitiator(initiatorIdStr)) {
                                        // In here, we're looking at an initiator that is both in our export group and in the export
                                        // mask we're looking at,
                                        // so it needs further scrutiny. Is this combo in more than one export group? If so, leave it
                                        // alone.
                                        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()));
                                            anyVolumesFoundInAnotherExportGroup = true;
                                        } else {
                                            if (!volumesToRemove.contains(egVolumeID)) {
                                                _log.info(String.format("We can remove volume %s from mask %s", volumeIdStr, tempMask.getMaskName()));
                                                volumesToRemove.add(egVolumeID);
                                            }
                                        }
                                    } else if (tempMask.getCreatedBySystem()) {
                                        _log.info(String.format("Export Mask %s does not contain initiator %s, so we will not modify this export mask", tempMask.getId().toString(), initiatorIdStr));
                                    } else {
                                        // system.
                                        if (!volumesToRemove.contains((egVolumeID))) {
                                            _log.info(String.format("We can remove volume %s from mask %s", volumeIdStr, tempMask.getMaskName()));
                                            volumesToRemove.add(egVolumeID);
                                        }
                                    }
                                }
                            }
                        } else {
                            _log.info(String.format("Export mask %s does not contain system-created volume %s, so it will not be removed from this export mask", tempMask.getId().toString(), volumeIdStr));
                        }
                    }
                    // Determine if we are removing the last volume from the ExportGroup
                    Map<URI, Integer> exportGroupVolumeMap = ExportUtils.getExportGroupVolumeMap(_dbClient, storage, exportGroup);
                    Set<URI> exportGroupVolumeURIs = exportGroupVolumeMap.keySet();
                    exportGroupVolumeURIs.removeAll(volumesToRemove);
                    boolean exportGroupHasMoreVolumes = !exportGroupVolumeURIs.isEmpty();
                    boolean exportMaskIsShared = ExportUtils.isExportMaskShared(_dbClient, tempMask.getId(), null);
                    List<URI> allExportMaskInitiators = ExportUtils.getExportMaskAllInitiators(tempMask, _dbClient);
                    _log.info(String.format("ExportMask %s(%s) - exportGroupHasMoreVolumes=%s exportMaskIsShared=%s " + "removingLastVolumeFromMask=%s anyVolumesFoundInAnotherExportGroup=%s", tempMask.getMaskName(), tempMask.getId(), exportGroupHasMoreVolumes, exportMaskIsShared, removingLastVolumeFromMask, anyVolumesFoundInAnotherExportGroup));
                    // Assume that we cannot delete the ExportMask
                    boolean canDeleteExportMask = false;
                    if (tempMask.getCreatedBySystem()) {
                        // We should only delete ViPR created ExportMasks
                        if (exportMaskIsShared) {
                            // Shared ExportMask, need to evaluate the volumes
                            if (!anyVolumesFoundInAnotherExportGroup && removingLastVolumeFromMask) {
                                // None of the volumes are being shared by another ExportGroup and
                                // we're removing the last volume from the ExportMask
                                canDeleteExportMask = true;
                                _log.info(String.format("ExportMask %s(%s) - Determined that this mask is shared, " + "but volumes are exclusive to the ExportGroup %s, so we can delete it", tempMask.getMaskName(), tempMask.getId(), exportGroup.getId()));
                            }
                        } else if (!anyVolumesFoundInAnotherExportGroup) {
                            // Evaluate the situation with the volumes
                            if (!exportGroupHasMoreVolumes && removingLastVolumeFromMask) {
                                // The remove will empty the ExportGroup or ExportMask of volumes
                                canDeleteExportMask = true;
                                _log.info(String.format("ExportMask %s(%s) - Determined that this mask is not shared and meets the criteria for deletion", tempMask.getMaskName(), tempMask.getId()));
                            }
                        } else {
                            _log.info("Checks have determined that the ExportMask %s(%s) should not be deleted", tempMask.getMaskName(), tempMask.getId());
                        }
                    }
                    if (canDeleteExportMask) {
                        _log.info(String.format("Determined that we can delete mask %s", tempMask.getMaskName()));
                        exportMasksToZoneDelete.add(tempMask);
                        exportMasksToDelete.add(tempMask);
                        generatedWorkFlowSteps = true;
                    } else {
                        // We have determined that we cannot delete the ExportMask. We have to determine if we
                        // should remove initiators or volumes
                        @SuppressWarnings("unchecked") List<URI> userAddedVolumes = (tempMask.getUserAddedVolumes() != null) ? StringSetUtil.stringSetToUriList(tempMask.getUserAddedVolumes().values()) : Collections.EMPTY_LIST;
                        userAddedVolumes.removeAll(volumesToRemove);
                        boolean removingAllUserAddedVolumes = userAddedVolumes.isEmpty();
                        boolean canRemoveVolumes = (!volumesToRemove.isEmpty() && !removingLastVolumeFromMask);
                        if (storage.getSystemType().equals(DiscoveredDataObject.Type.hds.name())) {
                            // Fix for COP-25152 as a part of COP-23625
                            /*
                                 * Hitachi arrays can have HostStorageDomains (HSD's) without volumes associated with it.
                                 * In case if the mask which was not created by VIPR and having no volumes has chosen for export,
                                 * while un exporting if we even consider !removingLastVolumeFromMask condition the export mask will
                                 * not be deleted (since it was not created by VIPR) and the lun path continue to be exist.
                                 */
                            canRemoveVolumes = !volumesToRemove.isEmpty();
                        }
                        _log.info(String.format("ExportMask %s(%s) - canRemoveVolumes=%s " + "allExportMaskInitiators=%d removingLastVolumeFromMask=%s removingAllUserAddedVolumes=%s", tempMask.getMaskName(), tempMask.getId(), canRemoveVolumes, allExportMaskInitiators.size(), removingLastVolumeFromMask, removingAllUserAddedVolumes));
                        if (canRemoveVolumes) {
                            // If we got here it means that:
                            // -- ExportMask was not created by ViPR
                            // -- We're not dealing with a subset of initiators for the ExportMask
                            // Then we will just schedule the removal of the volumes
                            _log.info(String.format("Determined that we can remove volumes from mask %s (%s): %s", tempMask.getMaskName(), tempMask.getId(), CommonTransformerFunctions.collectionString(volumesToRemove)));
                            exportMasksToZoneRemoveVolumes.add(tempMask);
                            volumesToZoneRemoveVolumes.addAll(volumesToRemove);
                            List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, tempMask, null), CommonTransformerFunctions.fctnDataObjectToID()));
                            List<URI> volumesToRemoveList = new ArrayList<>();
                            volumesToRemoveList.addAll(volumesToRemove);
                            previousStep = generateDeviceSpecificExportMaskRemoveVolumesWorkflow(workflow, previousStep, exportGroup, tempMask, storage, volumesToRemoveList, maskInitiatorURIs, null);
                            generatedWorkFlowSteps = true;
                        }
                    }
                }
            }
            if (!exportMasksToDelete.isEmpty()) {
                for (ExportMask exportMaskToDelete : exportMasksToDelete) {
                    _log.info("generating workflow to remove exportmask {}", exportMaskToDelete.getMaskName());
                    List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(exportMaskToDelete);
                    List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMaskToDelete, null), CommonTransformerFunctions.fctnDataObjectToID()));
                    previousStep = generateDeviceSpecificExportMaskDeleteWorkflow(workflow, previousStep, exportGroup, exportMaskToDelete, maskVolumeURIs, maskInitiatorURIs, storage);
                }
            }
            if (!exportMasksToZoneRemoveVolumes.isEmpty()) {
                _log.info("generating workflow for exportmask to zoneRemoveVolumes.");
                // Remove all the indicated volumes from the indicated export masks.
                previousStep = generateDeviceSpecificZoningRemoveVolumesWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneRemoveVolumes, volumesToZoneRemoveVolumes);
            }
            if (!exportMasksToZoneDelete.isEmpty()) {
                _log.info("generating workflow to remove all zones in exportmask");
                // Add the zone ExportMask delete operations
                previousStep = generateDeviceSpecificZoningDeleteWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneDelete);
            }
            if (generatedWorkFlowSteps) {
                // Add a task to clean up the export group when the export masks remove their volumes
                previousStep = generateDeviceSpecificExportGroupRemoveVolumesCleanup(workflow, previousStep, storage, exportGroup, volumeURIs, null);
            }
            String successMessage = String.format("Successfully removed volumes from export on StorageArray %s", storage.getLabel());
            workflow.executePlan(taskCompleter, successMessage);
        }
        if (!generatedWorkFlowSteps) {
            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) BlockStorageDevice(com.emc.storageos.volumecontroller.BlockStorageDevice) 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)

Aggregations

ExportOrchestrationTask (com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask)53 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)46 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)44 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)42 Workflow (com.emc.storageos.workflow.Workflow)40 ExportMask (com.emc.storageos.db.client.model.ExportMask)39 URI (java.net.URI)39 ArrayList (java.util.ArrayList)36 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)33 HashMap (java.util.HashMap)31 List (java.util.List)28 Map (java.util.Map)25 Initiator (com.emc.storageos.db.client.model.Initiator)20 HashSet (java.util.HashSet)19 BlockObject (com.emc.storageos.db.client.model.BlockObject)17 BlockStorageDevice (com.emc.storageos.volumecontroller.BlockStorageDevice)16 ExportTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter)16 Set (java.util.Set)15 StringMap (com.emc.storageos.db.client.model.StringMap)12 TaskCompleter (com.emc.storageos.volumecontroller.TaskCompleter)7