Search in sources :

Example 86 with BlockObject

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

the class VmaxMaskingOrchestrator method changePortGroup.

@Override
public void changePortGroup(URI storageURI, URI exportGroupURI, URI portGroupURI, List<URI> exportMaskURIs, boolean waitForApproval, String token) {
    ExportChangePortGroupCompleter taskCompleter = null;
    try {
        ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
        StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
        StoragePortGroup portGroup = _dbClient.queryObject(StoragePortGroup.class, portGroupURI);
        taskCompleter = new ExportChangePortGroupCompleter(storageURI, exportGroupURI, token, portGroupURI);
        logExportGroup(exportGroup, storageURI);
        String workflowKey = "changePortGroup";
        if (_workflowService.hasWorkflowBeenCreated(token, workflowKey)) {
            return;
        }
        Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), workflowKey, false, token);
        if (CollectionUtils.isEmpty(exportMaskURIs)) {
            _log.info("No export masks to change");
            taskCompleter.ready(_dbClient);
            return;
        }
        List<ExportMask> exportMasks = _dbClient.queryObject(ExportMask.class, exportMaskURIs);
        String previousStep = null;
        Set<URI> hostURIs = new HashSet<URI>();
        for (ExportMask oldMask : exportMasks) {
            // create a new masking view using the new port group
            SmisStorageDevice device = (SmisStorageDevice) getDevice();
            oldMask = device.refreshExportMask(storage, oldMask);
            StringSet existingInits = oldMask.getExistingInitiators();
            StringMap existingVols = oldMask.getExistingVolumes();
            if (!CollectionUtils.isEmpty(existingInits)) {
                String error = String.format("The export mask %s has unmanaged initiators %s", oldMask.getMaskName(), Joiner.on(',').join(existingInits));
                _log.error(error);
                ServiceError serviceError = DeviceControllerException.errors.changePortGroupValidationError(error);
                taskCompleter.error(_dbClient, serviceError);
                return;
            }
            if (!CollectionUtils.isEmpty(existingVols)) {
                String error = String.format("The export mask %s has unmanaged volumes %s", oldMask.getMaskName(), Joiner.on(',').join(existingVols.keySet()));
                _log.error(error);
                ServiceError serviceError = DeviceControllerException.errors.changePortGroupValidationError(error);
                taskCompleter.error(_dbClient, serviceError);
                return;
            }
            InitiatorHelper initiatorHelper = new InitiatorHelper(StringSetUtil.stringSetToUriList(oldMask.getInitiators())).process(exportGroup);
            List<String> initiatorNames = initiatorHelper.getPortNames();
            List<URI> volumes = StringSetUtil.stringSetToUriList(oldMask.getVolumes().keySet());
            ExportPathParams pathParams = _blockScheduler.calculateExportPathParamForVolumes(volumes, 0, storageURI, exportGroupURI);
            pathParams.setStoragePorts(portGroup.getStoragePorts());
            List<Initiator> initiators = ExportUtils.getExportMaskInitiators(oldMask, _dbClient);
            List<URI> initURIs = new ArrayList<URI>();
            for (Initiator init : initiators) {
                if (!NullColumnValueGetter.isNullURI(init.getHost())) {
                    hostURIs.add(init.getHost());
                }
                initURIs.add(init.getId());
            }
            // Get impacted export groups
            List<ExportGroup> impactedExportGroups = ExportMaskUtils.getExportGroups(_dbClient, oldMask);
            List<URI> exportGroupURIs = URIUtil.toUris(impactedExportGroups);
            _log.info("changePortGroup: exportMask {}, impacted export groups: {}", oldMask.getMaskName(), Joiner.on(',').join(exportGroupURIs));
            Map<URI, List<URI>> assignments = _blockScheduler.assignStoragePorts(storage, exportGroup, initiators, null, pathParams, volumes, _networkDeviceController, exportGroup.getVirtualArray(), token);
            // Trying to find if there is existing export mask or masking view for the same host and using the new
            // port group. If found one, add the volumes in the current export mask to the new one; otherwise, create
            // a new export mask/masking view, with the same storage group, initiator group and the new port group.
            // then delete the current export mask.
            ExportMask newMask = device.findExportMasksForPortGroupChange(storage, initiatorNames, portGroupURI);
            Map<URI, Integer> volumesToAdd = StringMapUtil.stringMapToVolumeMap(oldMask.getVolumes());
            if (newMask != null) {
                updateZoningMap(exportGroup, newMask, true);
                _log.info(String.format("adding these volumes %s to mask %s", Joiner.on(",").join(volumesToAdd.keySet()), newMask.getMaskName()));
                previousStep = generateZoningAddVolumesWorkflow(workflow, previousStep, exportGroup, Arrays.asList(newMask), new ArrayList<URI>(volumesToAdd.keySet()));
                String addVolumeStep = workflow.createStepId();
                ExportTaskCompleter exportTaskCompleter = new ExportMaskAddVolumeCompleter(exportGroupURI, newMask.getId(), volumesToAdd, addVolumeStep);
                exportTaskCompleter.setExportGroups(exportGroupURIs);
                Workflow.Method maskingExecuteMethod = new Workflow.Method("doExportGroupAddVolumes", storageURI, exportGroupURI, newMask.getId(), volumesToAdd, null, exportTaskCompleter);
                Workflow.Method maskingRollbackMethod = new Workflow.Method("rollbackExportGroupAddVolumes", storageURI, exportGroupURI, exportGroupURIs, newMask.getId(), volumesToAdd, initURIs, addVolumeStep);
                previousStep = workflow.createStep(EXPORT_GROUP_MASKING_TASK, String.format("Adding volumes to mask %s (%s)", newMask.getMaskName(), newMask.getId().toString()), previousStep, storageURI, storage.getSystemType(), MaskingWorkflowEntryPoints.class, maskingExecuteMethod, maskingRollbackMethod, addVolumeStep);
                previousStep = generateExportMaskAddVolumesWorkflow(workflow, previousStep, storage, exportGroup, newMask, volumesToAdd, null);
            } else {
                // We don't find existing export mask /masking view, we will create a new one.
                // first, to construct the new export mask name, if the export mask has the original name, then
                // append the new port group name to the current export mask name; if the export mask already has the current
                // port group name appended, then remove the current port group name, and append the new one.
                String oldName = oldMask.getMaskName();
                URI oldPGURI = oldMask.getPortGroup();
                if (oldPGURI != null) {
                    StoragePortGroup oldPG = _dbClient.queryObject(StoragePortGroup.class, oldPGURI);
                    if (oldPG != null) {
                        String pgName = oldPG.getLabel();
                        if (oldName.endsWith(pgName)) {
                            oldName = oldName.replaceAll(pgName, "");
                        }
                    }
                }
                String maskName = null;
                if (oldName.endsWith("_")) {
                    maskName = String.format("%s%s", oldName, portGroup.getLabel());
                } else {
                    maskName = String.format("%s_%s", oldName, portGroup.getLabel());
                }
                newMask = ExportMaskUtils.initializeExportMask(storage, exportGroup, initiators, volumesToAdd, getStoragePortsInPaths(assignments), assignments, maskName, _dbClient);
                newMask.setPortGroup(portGroupURI);
                List<BlockObject> vols = new ArrayList<BlockObject>();
                for (URI boURI : volumesToAdd.keySet()) {
                    BlockObject bo = BlockObject.fetch(_dbClient, boURI);
                    vols.add(bo);
                }
                newMask.addToUserCreatedVolumes(vols);
                _dbClient.updateObject(newMask);
                _log.info(String.format("Creating new exportMask %s", maskName));
                // Make a new TaskCompleter for the exportStep. It has only one subtask.
                // This is due to existing requirements in the doExportGroupCreate completion
                // logic.
                String maskingStep = workflow.createStepId();
                ExportTaskCompleter exportTaskCompleter = new ExportMaskChangePortGroupAddMaskCompleter(newMask.getId(), exportGroupURI, maskingStep);
                exportTaskCompleter.setExportGroups(exportGroupURIs);
                Workflow.Method maskingExecuteMethod = new Workflow.Method("doExportChangePortGroupAddPaths", storageURI, exportGroupURI, newMask.getId(), oldMask.getId(), portGroupURI, exportTaskCompleter);
                Workflow.Method maskingRollbackMethod = new Workflow.Method("rollbackExportGroupCreate", storageURI, exportGroupURI, newMask.getId(), maskingStep);
                maskingStep = workflow.createStep(EXPORT_GROUP_MASKING_TASK, String.format("Create export mask(%s) to use port group %s", newMask.getMaskName(), portGroup.getNativeGuid()), previousStep, storageURI, storage.getSystemType(), MaskingWorkflowEntryPoints.class, maskingExecuteMethod, maskingRollbackMethod, maskingStep);
                String zoningStep = workflow.createStepId();
                List<URI> masks = new ArrayList<URI>();
                masks.add(newMask.getId());
                previousStep = generateZoningCreateWorkflow(workflow, maskingStep, exportGroup, masks, volumesToAdd, zoningStep);
            }
        }
        previousStep = _wfUtils.generateHostRescanWorkflowSteps(workflow, hostURIs, previousStep);
        if (waitForApproval) {
            // Insert a step that will be suspended. When it resumes, it will re-acquire the lock keys,
            // which are released when the workflow suspends.
            List<String> lockKeys = ControllerLockingUtil.getHostStorageLockKeys(_dbClient, ExportGroup.ExportGroupType.valueOf(exportGroup.getType()), StringSetUtil.stringSetToUriList(exportGroup.getInitiators()), storageURI);
            String suspendMessage = "Adjust/rescan host/cluster paths. Press \"Resume\" to start removal of unnecessary paths." + "\"Rollback\" will terminate the order and roll back";
            Workflow.Method method = WorkflowService.acquireWorkflowLocksMethod(lockKeys, LockTimeoutValue.get(LockType.EXPORT_GROUP_OPS));
            Workflow.Method rollbackNull = Workflow.NULL_METHOD;
            previousStep = workflow.createStep("AcquireLocks", "Suspending for user verification of host/cluster connectivity.", previousStep, storage.getId(), storage.getSystemType(), WorkflowService.class, method, rollbackNull, waitForApproval, null);
            workflow.setSuspendedStepMessage(previousStep, suspendMessage);
        }
        for (ExportMask exportMask : exportMasks) {
            previousStep = generateChangePortGroupDeleteMaskWorkflowstep(storageURI, exportGroup, exportMask, previousStep, workflow);
        }
        _wfUtils.generateHostRescanWorkflowSteps(workflow, hostURIs, previousStep);
        if (!workflow.getAllStepStatus().isEmpty()) {
            _log.info("The change port group workflow has {} steps. Starting the workflow.", workflow.getAllStepStatus().size());
            // update ExportChangePortGroupCompleter with affected export groups
            Set<URI> affectedExportGroups = new HashSet<URI>();
            for (ExportMask mask : exportMasks) {
                List<ExportGroup> assocExportGroups = ExportMaskUtils.getExportGroups(_dbClient, mask);
                for (ExportGroup eg : assocExportGroups) {
                    affectedExportGroups.add(eg.getId());
                }
            }
            taskCompleter.setAffectedExportGroups(affectedExportGroups);
            workflow.executePlan(taskCompleter, "Change port group successfully.");
            _workflowService.markWorkflowBeenCreated(token, workflowKey);
        } else {
            taskCompleter.ready(_dbClient);
        }
    } catch (Exception e) {
        _log.error("Export change port group Orchestration failed.", e);
        if (taskCompleter != null) {
            ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(e.getMessage(), e);
            taskCompleter.error(_dbClient, serviceError);
        }
    }
}
Also used : StoragePortGroup(com.emc.storageos.db.client.model.StoragePortGroup) StringMap(com.emc.storageos.db.client.model.StringMap) ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) Lists.newArrayList(com.google.common.collect.Lists.newArrayList) ArrayList(java.util.ArrayList) URI(java.net.URI) Initiator(com.emc.storageos.db.client.model.Initiator) WorkflowService(com.emc.storageos.workflow.WorkflowService) StringSet(com.emc.storageos.db.client.model.StringSet) List(java.util.List) Lists.newArrayList(com.google.common.collect.Lists.newArrayList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) 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) ExportMaskChangePortGroupAddMaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskChangePortGroupAddMaskCompleter) Workflow(com.emc.storageos.workflow.Workflow) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) ExportChangePortGroupCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportChangePortGroupCompleter) ExportMaskAddVolumeCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddVolumeCompleter) SmisStorageDevice(com.emc.storageos.volumecontroller.impl.smis.SmisStorageDevice) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams)

Example 87 with BlockObject

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

the class VmaxMaskingOrchestrator 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>();
    // 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 != null && 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);
            }
        }
    }
    InitiatorHelper initiatorHelper = new InitiatorHelper(initiatorURIs).process(exportGroup);
    boolean anyOperationsToDo = false;
    Set<URI> partialMasks = new HashSet<>();
    Map<String, Set<URI>> initiatorToExportMaskPlacementMap = determineInitiatorToExportMaskPlacements(exportGroup, storageURI, initiatorHelper.getResourceToInitiators(), device.findExportMasks(storage, initiatorHelper.getPortNames(), false), initiatorHelper.getPortNameToInitiatorURI(), partialMasks);
    if (!initiatorToExportMaskPlacementMap.isEmpty()) {
        Map<URI, ExportMaskPolicy> policyCache = new HashMap<>();
        // The logic contained here is trying to place the initiators that were passed down in the
        // request. If we are in this path where the initiatorToExportMaskPlacementMap is not empty, then there
        // are several cases why we got here:
        // 
        // 1). An ExportMask has been found that is associated with the ExportGroup and it
        // is supposed to be the container for the compute resources that we are attempting
        // to add initiators for.
        // 2). An ExportMask has been found that is on the array. It may not be associated with the
        // ExportGroup, but it is supposed to be the container for the compute resources that
        // we are attempting to add initiators for.
        // 3). An ExportMask has been found that is on the array. It may not be associated with the
        // ExportGroup, but it has the initiators that we are trying to add
        // 4). One of the above possibilities + an initiator that cannot be placed. The use-case here
        // would someone adds a new initiator for an existing host and a new host to a cluster export.
        List<URI> initiatorsToPlace = new ArrayList<URI>();
        initiatorsToPlace.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 : initiatorToExportMaskPlacementMap.entrySet()) {
            URI initiatorURI = initiatorHelper.getPortNameToInitiatorURI().get(entry.getKey());
            if (initiatorURI == null || exportGroup == null) {
                // This initiator does not exist or it is not one of the initiators passed to the function
                continue;
            }
            Initiator initiator = _dbClient.queryObject(Initiator.class, 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("Trying to place initiator %s", entry.getKey()));
            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;
                }
                _log.info(String.format("Trying to place initiator %s in mask %s", entry.getKey(), mask.getMaskName()));
                if (mask.getInactive() && !mask.getStorageDevice().equals(storageURI)) {
                    continue;
                }
                // determineInitiatorToExportMaskPlacements or findExportMasks
                if (!refreshedMasks.containsKey(mask.getId())) {
                    mask = device.refreshExportMask(storage, mask);
                    refreshedMasks.put(mask.getId(), mask);
                }
                ExportMaskPolicy policy = getExportMaskPolicy(policyCache, device, storage, mask);
                // yet. The below logic will add the volumes necessary.
                if (mask.hasInitiator(initiatorURI.toString()) && CollectionUtils.isEmpty(ExportUtils.getExportMasksSharingInitiator(_dbClient, initiatorURI, mask, exportMaskURIs))) {
                    _log.info(String.format("mask %s has initiator %s", mask.getMaskName(), initiator.getInitiatorPort()));
                    // already in the masks to the placement list
                    for (BlockObject blockObject : blockObjects) {
                        // blockObject properties, and so on.
                        if (!mask.hasExistingVolume(blockObject.getWWN()) && !mask.hasVolume(blockObject.getId())) {
                            String volumePolicyName = ControllerUtils.getAutoTieringPolicyName(blockObject.getId(), _dbClient);
                            if (((volumePolicyName == null || volumePolicyName.equalsIgnoreCase(Constants.NONE.toString())) && (policy.tierPolicies == null || policy.tierPolicies.isEmpty())) || ((volumePolicyName != null && policy.tierPolicies != null && policy.tierPolicies.size() == 1 && policy.tierPolicies.contains(volumePolicyName)))) {
                                _log.info(String.format("mask doesn't have volume %s yet, need to add it", blockObject.getId()));
                                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()));
                            }
                        } else {
                            _log.info(String.format("not adding volume %s to mask %s", blockObject.getId(), mask.getMaskName()));
                        }
                    }
                    // The initiator has been placed - it is in an already existing export
                    // for which case, we may just have to add volumes to it
                    initiatorsToPlace.remove(initiatorURI);
                } else {
                    Set<URI> existingInitiatorIds = ExportMaskUtils.getAllInitiatorsForExportMask(_dbClient, mask);
                    if (existingInitiatorIds.isEmpty()) {
                        _log.info(String.format("not adding initiator to %s mask %s because there are no initiators associated with this mask", initiatorURI, mask.getMaskName()));
                    }
                    // This mask does not contain the initiator, but it may not belong to the same compute resource.
                    for (URI existingInitiatorId : existingInitiatorIds) {
                        Initiator existingInitiator = _dbClient.queryObject(Initiator.class, existingInitiatorId);
                        if (existingInitiator == null) {
                            _log.warn(String.format("Initiator %s was found to be associated with ExportMask %s, but no longer exists in the DB", existingInitiatorId, mask.getId()));
                            continue;
                        }
                        if ((existingInitiator.getHost() != null && existingInitiator.getHost().equals(initiator.getHost())) || (existingInitiator.getClusterName() != null && existingInitiator.getClusterName().equals(initiator.getClusterName()))) {
                            // Place the initiator in this ExportMask.
                            if (exportGroup.forCluster() && !policy.isCascadedIG() && ((existingInitiator.getHost() == null || !existingInitiator.getHost().equals(initiator.getHost())))) {
                                _log.info(String.format("not adding initiator to %s mask %s because it is likely part of another mask in the cluster", initiatorURI, mask.getMaskName()));
                                continue;
                            }
                            Set<Initiator> existingMaskInitiators = existingMasksToUpdateWithNewInitiators.get(mask.getId());
                            if (existingMaskInitiators == null) {
                                existingMaskInitiators = new HashSet<Initiator>();
                                existingMasksToUpdateWithNewInitiators.put(mask.getId(), existingMaskInitiators);
                            }
                            _log.info(String.format("adding initiator to %s mask %s because it was found to be in the same compute resource", initiatorURI, mask.getMaskName()));
                            existingMaskInitiators.add(initiator);
                            // The initiator has been placed - it is not in the export, we will have to
                            // add it to the mask
                            initiatorsToPlace.remove(initiatorURI);
                        } else {
                            _log.info(String.format("not adding initiator to %s mask %s because it doesn't belong to the same compute resource", existingInitiator.getId(), mask.getMaskName()));
                        }
                    }
                }
                updateZoningMap(exportGroup, mask, true);
            }
        }
        // so let's add them to the main tracker
        if (!initiatorsToPlace.isEmpty()) {
            Map<String, List<URI>> computeResourceToInitiators = mapInitiatorsToComputeResource(exportGroup, initiatorsToPlace);
            for (Map.Entry<String, List<URI>> resourceEntry : computeResourceToInitiators.entrySet()) {
                String computeKey = resourceEntry.getKey();
                List<URI> computeInitiatorURIs = resourceEntry.getValue();
                _log.info(String.format("New export masks for %s", computeKey));
                GenExportMaskCreateWorkflowResult result = generateExportMaskCreateWorkflow(workflow, previousStep, storage, exportGroup, computeInitiatorURIs, volumeMap, token);
                previousStep = result.getStepId();
                zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
                anyOperationsToDo = true;
            }
        }
        _log.info(String.format("existingMasksToUpdateWithNewVolumes.size = %d", existingMasksToUpdateWithNewVolumes.size()));
        // At this point we have a mapping of all the masks that we need to update with new volumes
        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());
            List<ExportMask> masks = new ArrayList<ExportMask>();
            masks.add(mask);
            previousStep = generateZoningAddVolumesWorkflow(workflow, previousStep, exportGroup, masks, volumeURIs);
            previousStep = generateExportMaskAddVolumesWorkflow(workflow, previousStep, storage, exportGroup, mask, volumesToAdd, null);
            anyOperationsToDo = true;
        }
        // At this point we have a mapping of all the masks that we need to update with new initiators
        for (Map.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(), initiatorsURIs);
            previousStep = generateExportMaskAddInitiatorsWorkflow(workflow, previousStep, storage, exportGroup, mask, initiatorsURIs, null, token);
            previousStep = generateZoningAddInitiatorsWorkflow(workflow, previousStep, exportGroup, maskToInitiatorsMap);
            anyOperationsToDo = true;
        }
    } else {
        _log.info("There are no masks for this export. Need to create anew.");
        // zones required (which might be on multiple NetworkSystems.)
        for (Map.Entry<String, List<URI>> resourceEntry : initiatorHelper.getResourceToInitiators().entrySet()) {
            String computeKey = resourceEntry.getKey();
            List<URI> computeInitiatorURIs = resourceEntry.getValue();
            _log.info(String.format("New export masks for %s", computeKey));
            GenExportMaskCreateWorkflowResult result = generateExportMaskCreateWorkflow(workflow, previousStep, storage, exportGroup, computeInitiatorURIs, volumeMap, token);
            zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
            previousStep = result.getStepId();
            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 = generateZoningCreateWorkflow(workflow, previousStep, exportGroup, exportMaskList, overallVolumeMap);
        }
        if (!zoneMasksToInitiatorsURIs.isEmpty()) {
            previousStep = generateZoningAddInitiatorsWorkflow(workflow, previousStep, exportGroup, zoneMasksToInitiatorsURIs);
        }
        String successMessage = String.format("Successfully exported to initiators on StorageArray %s", storage.getLabel());
        workflow.executePlan(taskCompleter, successMessage);
    } else {
        taskCompleter.ready(_dbClient);
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) StringSet(com.emc.storageos.db.client.model.StringSet) HashMap(java.util.HashMap) Lists.newArrayList(com.google.common.collect.Lists.newArrayList) ArrayList(java.util.ArrayList) URI(java.net.URI) BlockStorageDevice(com.emc.storageos.volumecontroller.BlockStorageDevice) Initiator(com.emc.storageos.db.client.model.Initiator) List(java.util.List) Lists.newArrayList(com.google.common.collect.Lists.newArrayList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) HashSet(java.util.HashSet) ExportMask(com.emc.storageos.db.client.model.ExportMask) Workflow(com.emc.storageos.workflow.Workflow) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) Map(java.util.Map) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask)

Example 88 with BlockObject

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

the class VnxMaskingOrchestrator method exportGroupAddVolumes.

@Override
public void exportGroupAddVolumes(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap, 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);
        boolean anyVolumesAdded = false;
        boolean createdNewMask = false;
        if (exportGroup != null && exportGroup.getExportMasks() != null) {
            // Set up workflow steps.
            Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupAddVolumes", true, token);
            List<ExportMask> exportMasksToZoneAddVolumes = new ArrayList<ExportMask>();
            List<URI> volumesToZoneAddVolumes = new ArrayList<URI>();
            // Add the volume to all the ExportMasks that are contained in the
            // ExportGroup. The volumes should be added only if they don't
            // already exist for the ExportMask.
            Collection<URI> initiatorURIs = Collections2.transform(exportGroup.getInitiators(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
            List<URI> hostURIs = new ArrayList<URI>();
            Map<String, URI> portNameToInitiatorURI = new HashMap<String, URI>();
            List<String> portNames = new ArrayList<String>();
            processInitiators(exportGroup, initiatorURIs, portNames, portNameToInitiatorURI, hostURIs);
            // 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);
            Map<String, Set<URI>> foundMatches = device.findExportMasks(storage, portNames, false);
            findAndUpdateFreeHLUsForClusterExport(storage, exportGroup, new ArrayList<URI>(initiatorURIs), volumeMap);
            Set<String> checkMasks = mergeWithExportGroupMaskURIs(exportGroup, foundMatches.values());
            for (String maskURIStr : checkMasks) {
                ExportMask exportMask = _dbClient.queryObject(ExportMask.class, URI.create(maskURIStr));
                _log.info(String.format("Checking mask %s", exportMask.getMaskName()));
                // Check for NO_VIPR. If found, avoid this mask.
                if (exportMask.getMaskName() != null && exportMask.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", exportMask.getMaskName(), ExportUtils.NO_VIPR));
                    continue;
                }
                if (!exportMask.getInactive() && exportMask.getStorageDevice().equals(storageURI)) {
                    exportMask = device.refreshExportMask(storage, exportMask);
                    // BlockStorageDevice level, so that it has up-to-date
                    // info from the array
                    Map<URI, Integer> volumesToAdd = new HashMap<URI, Integer>();
                    for (URI boURI : volumeMap.keySet()) {
                        BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, boURI);
                        if (bo != null && !exportMask.hasExistingVolume(bo.getWWN()) && !exportMask.hasUserAddedVolume(bo.getWWN())) {
                            URI thisVol = bo.getId();
                            Integer hlu = volumeMap.get(boURI);
                            volumesToAdd.put(thisVol, hlu);
                        }
                        // volumes
                        if (bo != null && exportMask.hasExistingVolume(bo.getWWN())) {
                            exportMask.removeFromExistingVolumes(bo);
                            exportMask.addToUserCreatedVolumes(bo);
                            _dbClient.updateObject(exportMask);
                        }
                        // Check if the requested HLU for the volume is
                        // already taken by a pre-existing volume.
                        Integer requestedHLU = volumeMap.get(boURI);
                        StringMap existingVolumesInMask = exportMask.getExistingVolumes();
                        if (existingVolumesInMask != null && requestedHLU.intValue() != ExportGroup.LUN_UNASSIGNED && !ExportGroup.LUN_UNASSIGNED_DECIMAL_STR.equals(requestedHLU.toString()) && existingVolumesInMask.containsValue(requestedHLU.toString())) {
                            ExportOrchestrationTask completer = new ExportOrchestrationTask(exportGroup.getId(), token);
                            ServiceError serviceError = DeviceControllerException.errors.exportHasExistingVolumeWithRequestedHLU(boURI.toString(), requestedHLU.toString());
                            completer.error(_dbClient, serviceError);
                            return;
                        }
                    }
                    _log.info(String.format("Mask %s, adding volumes %s", exportMask.getMaskName(), Joiner.on(',').join(volumesToAdd.entrySet())));
                    if (volumesToAdd.size() > 0) {
                        List<URI> volumeURIs = new ArrayList<URI>();
                        volumeURIs.addAll(volumesToAdd.keySet());
                        exportMasksToZoneAddVolumes.add(exportMask);
                        volumesToZoneAddVolumes.addAll(volumeURIs);
                        // This is the list of export masks where volumes will be added
                        // some may be user-created and being 'accepted' into ViPR for
                        // the first time. Need to update zoning map
                        updateZoningMap(exportGroup, exportMask, true);
                        generateExportMaskAddVolumesWorkflow(workflow, EXPORT_GROUP_ZONING_TASK, storage, exportGroup, exportMask, volumesToAdd, null);
                        anyVolumesAdded = true;
                        // associated it with the ExportGroup.
                        if (!exportGroup.hasMask(exportMask.getId())) {
                            exportGroup.addExportMask(exportMask.getId());
                            _dbClient.updateAndReindexObject(exportGroup);
                        }
                    }
                }
            }
            if (!anyVolumesAdded) {
                String attachGroupSnapshot;
                // masks and if there are initiators for the export.
                if (!ExportMaskUtils.hasExportMaskForStorage(_dbClient, exportGroup, storageURI) && exportGroup.hasInitiators()) {
                    _log.info("No existing masks to which the requested volumes can be added. Creating a new mask");
                    List<URI> initiators = StringSetUtil.stringSetToUriList(exportGroup.getInitiators());
                    attachGroupSnapshot = checkForSnapshotsToCopyToTarget(workflow, storage, null, volumeMap, null);
                    Map<URI, List<URI>> hostInitiatorMap = new HashMap<URI, List<URI>>();
                    for (URI newExportMaskInitiator : initiators) {
                        Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
                        // Not all initiators have hosts, be sure to handle either case.
                        URI hostURI = initiator.getHost();
                        if (hostURI == null) {
                            hostURI = NullColumnValueGetter.getNullURI();
                        }
                        List<URI> initiatorSet = hostInitiatorMap.get(hostURI);
                        if (initiatorSet == null) {
                            initiatorSet = new ArrayList<URI>();
                            hostInitiatorMap.put(hostURI, initiatorSet);
                        }
                        initiatorSet.add(initiator.getId());
                        _log.info(String.format("host = %s, " + "initiators to add: %d, ", hostURI, hostInitiatorMap.get(hostURI).size()));
                    }
                    if (!hostInitiatorMap.isEmpty()) {
                        for (URI hostID : hostInitiatorMap.keySet()) {
                            _log.info(String.format("new export masks %s", Joiner.on(",").join(hostInitiatorMap.get(hostID))));
                            String zoningStep = workflow.createStepId();
                            GenExportMaskCreateWorkflowResult result = generateExportMaskCreateWorkflow(workflow, zoningStep, storage, exportGroup, hostInitiatorMap.get(hostID), volumeMap, token);
                            List<URI> masks = new ArrayList<URI>();
                            masks.add(result.getMaskURI());
                            generateZoningCreateWorkflow(workflow, attachGroupSnapshot, exportGroup, masks, volumeMap, zoningStep);
                        }
                        createdNewMask = true;
                    }
                }
            }
            if (!exportMasksToZoneAddVolumes.isEmpty()) {
                generateZoningAddVolumesWorkflow(workflow, null, exportGroup, exportMasksToZoneAddVolumes, volumesToZoneAddVolumes);
            }
            String successMessage = String.format("Successfully added volumes to export on StorageArray %s", storage.getLabel());
            workflow.executePlan(taskCompleter, successMessage);
        } else {
            if (exportGroup.hasInitiators()) {
                _log.info("There are no masks for this export. Need to create anew.");
                List<URI> initiatorURIs = new ArrayList<URI>();
                for (String initiatorURIStr : exportGroup.getInitiators()) {
                    initiatorURIs.add(URI.create(initiatorURIStr));
                }
                // Invoke the export group create operation,
                // which should in turn create a workflow operations to
                // create the export for the newly added volume(s).
                exportGroupCreate(storageURI, exportGroupURI, initiatorURIs, volumeMap, token);
                anyVolumesAdded = true;
            } else {
                _log.warn("There are no initiator for export group: " + exportGroup.getLabel());
            }
        }
        if (!anyVolumesAdded && !createdNewMask) {
            taskCompleter.ready(_dbClient);
            _log.info("No volumes pushed to array because either they already exist " + "or there were no initiators added to the export yet.");
        }
    } 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 : StringMap(com.emc.storageos.db.client.model.StringMap) HashSet(java.util.HashSet) Set(java.util.Set) 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) 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) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask)

Example 89 with BlockObject

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

the class XIVMaskingOrchestrator method exportGroupAddVolumes.

@Override
public void exportGroupAddVolumes(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap, 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);
        boolean anyVolumesAdded = false;
        boolean createdNewMask = false;
        if (exportGroup != null && exportGroup.getExportMasks() != null) {
            // Set up workflow steps.
            Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupAddVolumes", true, token);
            List<ExportMask> exportMasksToZoneAddVolumes = new ArrayList<ExportMask>();
            List<URI> volumesToZoneAddVolumes = new ArrayList<URI>();
            // Add the volume to all the ExportMasks that are contained in the
            // ExportGroup. The volumes should be added only if they don't
            // already exist for the ExportMask.
            Collection<URI> initiatorURIs = Collections2.transform(exportGroup.getInitiators(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
            List<URI> hostURIs = new ArrayList<URI>();
            Map<String, URI> portNameToInitiatorURI = new HashMap<String, URI>();
            List<String> portNames = new ArrayList<String>();
            processInitiators(exportGroup, initiatorURIs, portNames, portNameToInitiatorURI, hostURIs);
            // 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);
            Map<String, Set<URI>> foundMatches = device.findExportMasks(storage, portNames, false);
            // Need to maintain separate Export mask for Cluster and Host.
            // So remove off the Export mask not matching to the Export Group.
            filterExportMaskForGroup(exportGroup, foundMatches);
            Set<String> checkMasks = mergeWithExportGroupMaskURIs(exportGroup, foundMatches.values());
            for (String maskURIStr : checkMasks) {
                ExportMask exportMask = _dbClient.queryObject(ExportMask.class, URI.create(maskURIStr));
                _log.info(String.format("Checking mask %s", exportMask.getMaskName()));
                // Check for NO_VIPR. If found, avoid this mask.
                if (exportMask.getMaskName() != null && exportMask.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", exportMask.getMaskName(), ExportUtils.NO_VIPR));
                    continue;
                }
                if (!exportMask.getInactive() && exportMask.getStorageDevice().equals(storageURI)) {
                    exportMask = device.refreshExportMask(storage, exportMask);
                    // BlockStorageDevice level, so that it has up-to-date
                    // info from
                    // the array
                    Map<URI, Integer> volumesToAdd = new HashMap<URI, Integer>();
                    for (URI boURI : volumeMap.keySet()) {
                        BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, boURI);
                        if (bo != null && !exportMask.hasExistingVolume(bo.getWWN()) && !exportMask.hasUserAddedVolume(bo.getWWN())) {
                            URI thisVol = bo.getId();
                            Integer hlu = volumeMap.get(boURI);
                            volumesToAdd.put(thisVol, hlu);
                        }
                        // Check if the requested HLU for the volume is
                        // already taken by a pre-existing volume.
                        Integer requestedHLU = volumeMap.get(boURI);
                        StringMap existingVolumesInMask = exportMask.getExistingVolumes();
                        if (existingVolumesInMask != null && requestedHLU.intValue() != ExportGroup.LUN_UNASSIGNED && !ExportGroup.LUN_UNASSIGNED_DECIMAL_STR.equals(requestedHLU.toString()) && existingVolumesInMask.containsValue(requestedHLU.toString())) {
                            ExportOrchestrationTask completer = new ExportOrchestrationTask(exportGroup.getId(), token);
                            ServiceError serviceError = DeviceControllerException.errors.exportHasExistingVolumeWithRequestedHLU(boURI.toString(), requestedHLU.toString());
                            completer.error(_dbClient, serviceError);
                            return;
                        }
                    }
                    _log.info(String.format("Mask %s, adding volumes %s", exportMask.getMaskName(), Joiner.on(',').join(volumesToAdd.entrySet())));
                    if (volumesToAdd.size() > 0) {
                        List<URI> volumeURIs = new ArrayList<URI>();
                        volumeURIs.addAll(volumesToAdd.keySet());
                        exportMasksToZoneAddVolumes.add(exportMask);
                        volumesToZoneAddVolumes.addAll(volumeURIs);
                        // Make sure the zoning map is getting updated for user-created masks
                        updateZoningMap(exportGroup, exportMask, true);
                        // Update volumeMap to find the next HLU here.
                        updateVolumeHLU(storage, initiatorURIs, volumesToAdd);
                        generateExportMaskAddVolumesWorkflow(workflow, EXPORT_GROUP_ZONING_TASK, storage, exportGroup, exportMask, volumesToAdd, null);
                        anyVolumesAdded = true;
                        // associated it with the ExportGroup.
                        if (!exportGroup.hasMask(exportMask.getId())) {
                            exportGroup.addExportMask(exportMask.getId());
                            _dbClient.updateAndReindexObject(exportGroup);
                        }
                    }
                }
            }
            if (!anyVolumesAdded) {
                String attachGroupSnapshot;
                // masks and if there are initiators for the export.
                if (!ExportMaskUtils.hasExportMaskForStorage(_dbClient, exportGroup, storageURI) && exportGroup.hasInitiators()) {
                    _log.info("No existing masks to which the requested volumes can be added. Creating a new mask");
                    List<URI> initiators = StringSetUtil.stringSetToUriList(exportGroup.getInitiators());
                    attachGroupSnapshot = checkForSnapshotsToCopyToTarget(workflow, storage, null, volumeMap, null);
                    Map<URI, List<URI>> hostInitiatorMap = new HashMap<URI, List<URI>>();
                    for (URI newExportMaskInitiator : initiators) {
                        Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
                        // Not all initiators have hosts, be sure to handle either case.
                        URI hostURI = initiator.getHost();
                        if (hostURI == null) {
                            hostURI = NullColumnValueGetter.getNullURI();
                        }
                        List<URI> initiatorSet = hostInitiatorMap.get(hostURI);
                        if (initiatorSet == null) {
                            initiatorSet = new ArrayList<URI>();
                            hostInitiatorMap.put(hostURI, initiatorSet);
                        }
                        initiatorSet.add(initiator.getId());
                        _log.info(String.format("host = %s, " + "initiators to add: %d, ", hostURI, hostInitiatorMap.get(hostURI).size()));
                    }
                    if (!hostInitiatorMap.isEmpty()) {
                        for (URI hostID : hostInitiatorMap.keySet()) {
                            _log.info(String.format("new export masks %s", Joiner.on(",").join(hostInitiatorMap.get(hostID))));
                            String zoningStep = workflow.createStepId();
                            GenExportMaskCreateWorkflowResult result = generateExportMaskCreateWorkflow(workflow, zoningStep, storage, exportGroup, hostInitiatorMap.get(hostID), volumeMap, token);
                            List<URI> masks = new ArrayList<URI>();
                            masks.add(result.getMaskURI());
                            generateZoningCreateWorkflow(workflow, attachGroupSnapshot, exportGroup, masks, volumeMap, zoningStep);
                        }
                        createdNewMask = true;
                    }
                }
            }
            if (!exportMasksToZoneAddVolumes.isEmpty()) {
                generateZoningAddVolumesWorkflow(workflow, null, exportGroup, exportMasksToZoneAddVolumes, volumesToZoneAddVolumes);
            }
            String successMessage = String.format("Successfully added volumes to export on StorageArray %s", storage.getLabel());
            workflow.executePlan(taskCompleter, successMessage);
        } else {
            if (exportGroup.hasInitiators()) {
                _log.info("There are no masks for this export. Need to create anew.");
                List<URI> initiatorURIs = new ArrayList<URI>();
                for (String initiatorURIStr : exportGroup.getInitiators()) {
                    initiatorURIs.add(URI.create(initiatorURIStr));
                }
                // Invoke the export group create operation,
                // which should in turn create a workflow operations to
                // create the export for the newly added volume(s).
                exportGroupCreate(storageURI, exportGroupURI, initiatorURIs, volumeMap, token);
                anyVolumesAdded = true;
            } else {
                _log.warn("There are no initiator for export group: " + exportGroup.getLabel());
            }
        }
        if (!anyVolumesAdded && !createdNewMask) {
            taskCompleter.ready(_dbClient);
            _log.info("No volumes pushed to array because either they already exist " + "or there were no initiators added to the export yet.");
        }
    } 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 : StringMap(com.emc.storageos.db.client.model.StringMap) HashSet(java.util.HashSet) Set(java.util.Set) 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) 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) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask)

Example 90 with BlockObject

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

the class XIVMaskingOrchestrator method determineExportGroupCreateSteps.

/**
 * Routine contains logic to create an export mask on the array
 *
 * @param workflow - Workflow object to create steps against
 * @param previousStep - [optional] Identifier of workflow step to wait for
 * @param device - BlockStorageDevice implementation
 * @param storage - StorageSystem object representing the underlying array
 * @param exportGroup - ExportGroup object representing Bourne-level masking
 * @param initiatorURIs - List of Initiator URIs
 * @param volumeMap - Map of Volume URIs to requested Integer HLUs
 * @param zoningStepNeeded - Not required for XIV
 * @param token - Identifier for the operation
 * @throws Exception
 */
@Override
public boolean determineExportGroupCreateSteps(Workflow workflow, String previousStep, BlockStorageDevice device, StorageSystem storage, ExportGroup exportGroup, List<URI> initiatorURIs, Map<URI, Integer> volumeMap, boolean zoningStepNeeded, String token) throws Exception {
    Map<String, URI> portNameToInitiatorURI = new HashMap<String, URI>();
    List<URI> volumeURIs = new ArrayList<URI>();
    volumeURIs.addAll(volumeMap.keySet());
    Map<URI, URI> hostToExistingExportMaskMap = new HashMap<URI, URI>();
    List<URI> hostURIs = new ArrayList<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);
    // 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);
    // Update volumeMap to find the next HLU here.
    updateVolumeHLU(storage, initiatorURIs, volumeMap);
    // Find the export masks that are associated with any or all the ports in
    // portNames. We will have to do processing differently based on whether
    // or there is an existing ExportMasks.
    Map<String, Set<URI>> matchingExportMaskURIs = device.findExportMasks(storage, portNames, false);
    // Need to maintain separate Export mask for Cluster and Host.
    // So remove off the Export mask not matching to the Export Group.
    filterExportMaskForGroup(exportGroup, matchingExportMaskURIs);
    if (matchingExportMaskURIs.isEmpty()) {
        String attachGroupSnapshot = checkForSnapshotsToCopyToTarget(workflow, storage, previousStep, volumeMap, null);
        _log.info(String.format("No existing mask found w/ initiators { %s }", Joiner.on(",").join(portNames)));
        createNewExportMaskWorkflowForInitiators(initiatorURIs, exportGroup, workflow, volumeMap, storage, token, attachGroupSnapshot);
    } else {
        _log.info(String.format("Mask(s) found w/ initiators {%s}. " + "MatchingExportMaskURIs {%s}, portNameToInitiators {%s}", Joiner.on(",").join(portNames), Joiner.on(",").join(matchingExportMaskURIs.keySet()), Joiner.on(",").join(portNameToInitiatorURI.entrySet())));
        // There are some initiators that already exist. We need to create a
        // workflow that create new masking containers or updates masking
        // containers as necessary.
        // These data structures will be used to track new initiators - ones
        // that don't already exist on the array
        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);
            // Keep track of those initiators that have been found to exist already
            // in some export mask on the array
            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 masks {%s}", initiator.getInitiatorPort(), Joiner.on(',').join(exportMaskURIs)));
            for (ExportMask mask : masks) {
                _log.info(String.format("mask %s has initiator %s", mask.getMaskName(), initiator.getInitiatorPort()));
                // 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 (mask.getCreatedBySystem()) {
                    _log.info(String.format("initiator %s is in persisted mask %s", initiator.getInitiatorPort(), mask.getMaskName()));
                    // 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 (initiatorCopy != null && initiatorCopy.getId() != null && !mask.hasInitiator(initiatorCopy.getId().toString())) {
                                    Initiator existingMaskInitiator = _dbClient.queryObject(Initiator.class, URI.create(existingMaskInitiatorStr));
                                    if (existingMaskInitiator != null && initiatorCopy.getHost() != null && 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);
                                        }
                                        existingMaskInitiators.add(initiatorCopy);
                                        // remove this from the list of initiators we'll make a new mask from
                                        initiatorIter.remove();
                                    }
                                }
                            }
                        }
                    }
                } else {
                    // Insert this initiator into the mask's list of initiators managed by the system.
                    // This will get persisted below.
                    mask.addInitiator(initiator);
                    if (!NullColumnValueGetter.isNullURI(initiator.getHost())) {
                        hostToExistingExportMaskMap.put(initiator.getHost(), mask.getId());
                    }
                }
                // if it doesn't then we'll add it to the list of volumes to add.
                for (URI boURI : volumeURIs) {
                    BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, boURI);
                    if (bo != null && !mask.hasExistingVolume(bo) && !mask.hasUserAddedVolume(bo.getWWN())) {
                        _log.info(String.format("volume %s is not in mask %s", bo.getWWN(), mask.getMaskName()));
                        // The volume doesn't exist, so we have to add it to
                        // the masking container.
                        Map<URI, Integer> newVolumes = existingMasksToUpdateWithNewVolumes.get(mask.getId());
                        if (newVolumes == null) {
                            newVolumes = new HashMap<URI, Integer>();
                            existingMasksToUpdateWithNewVolumes.put(mask.getId(), newVolumes);
                        }
                        // Check if the requested HLU for the volume is
                        // already taken by a pre-existing volume.
                        Integer requestedHLU = volumeMap.get(boURI);
                        StringMap existingVolumesInMask = mask.getExistingVolumes();
                        if (existingVolumesInMask != null && requestedHLU.intValue() != ExportGroup.LUN_UNASSIGNED && !ExportGroup.LUN_UNASSIGNED_DECIMAL_STR.equals(requestedHLU.toString()) && existingVolumesInMask.containsValue(requestedHLU.toString())) {
                            ExportOrchestrationTask completer = new ExportOrchestrationTask(exportGroup.getId(), token);
                            ServiceError serviceError = DeviceControllerException.errors.exportHasExistingVolumeWithRequestedHLU(boURI.toString(), requestedHLU.toString());
                            completer.error(_dbClient, serviceError);
                            return false;
                        }
                        newVolumes.put(bo.getId(), requestedHLU);
                        mask.addToUserCreatedVolumes(bo);
                    }
                }
                // Update the list of volumes and initiators for the mask
                Map<URI, Integer> volumeMapForExistingMask = existingMasksToUpdateWithNewVolumes.get(mask.getId());
                if (volumeMapForExistingMask != null && !volumeMapForExistingMask.isEmpty()) {
                    mask.addVolumes(volumeMapForExistingMask);
                }
                Set<Initiator> initiatorSetForExistingMask = existingMasksToUpdateWithNewInitiators.get(mask.getId());
                if (initiatorSetForExistingMask != null && initiatorSetForExistingMask.isEmpty()) {
                    mask.addInitiators(initiatorSetForExistingMask);
                }
                updateZoningMap(exportGroup, mask);
                _dbClient.updateAndReindexObject(mask);
                // TODO: All export group modifications should be moved to completers
                exportGroup.addExportMask(mask.getId());
                _dbClient.updateAndReindexObject(exportGroup);
            }
        }
        // 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()));
            }
        }
        _log.info(String.format("existingMasksToUpdateWithNewVolumes.size = %d", existingMasksToUpdateWithNewVolumes.size()));
        String attachGroupSnapshot = checkForSnapshotsToCopyToTarget(workflow, storage, previousStep, volumeMap, existingMasksToUpdateWithNewVolumes.values());
        // and/or add volumes to existing masks.
        if (!hostInitiatorMap.isEmpty()) {
            for (URI hostID : hostInitiatorMap.keySet()) {
                // associated with that host to the list
                if (hostToExistingExportMaskMap.containsKey(hostID)) {
                    URI existingExportMaskURI = hostToExistingExportMaskMap.get(hostID);
                    Set<Initiator> toAddInits = new HashSet<Initiator>();
                    List<URI> hostInitaitorList = hostInitiatorMap.get(hostID);
                    for (URI initURI : hostInitaitorList) {
                        Initiator initiator = _dbClient.queryObject(Initiator.class, initURI);
                        if (!initiator.getInactive()) {
                            toAddInits.add(initiator);
                        }
                    }
                    _log.info(String.format("Need to add new initiators to existing mask %s, %s", existingExportMaskURI.toString(), Joiner.on(',').join(hostInitaitorList)));
                    existingMasksToUpdateWithNewInitiators.put(existingExportMaskURI, toAddInits);
                    continue;
                }
                // We have some brand new initiators, let's add them to new masks
                _log.info(String.format("new export masks %s", Joiner.on(",").join(hostInitiatorMap.get(hostID))));
                generateExportMaskCreateWorkflow(workflow, attachGroupSnapshot, storage, exportGroup, hostInitiatorMap.get(hostID), volumeMap, token);
            }
        }
        Map<URI, String> stepMap = new HashMap<URI, String>();
        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()));
            stepMap.put(entry.getKey(), generateExportMaskAddVolumesWorkflow(workflow, attachGroupSnapshot, storage, exportGroup, mask, volumesToAdd, null));
        }
        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()));
            previousStep = stepMap.get(entry.getKey()) == null ? attachGroupSnapshot : stepMap.get(entry.getKey());
            generateExportMaskAddInitiatorsWorkflow(workflow, previousStep, storage, exportGroup, mask, initiatorsURIs, null, token);
        }
    }
    return true;
}
Also used : StringMap(com.emc.storageos.db.client.model.StringMap) HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) URI(java.net.URI) Initiator(com.emc.storageos.db.client.model.Initiator) ArrayList(java.util.ArrayList) List(java.util.List) BlockObject(com.emc.storageos.db.client.model.BlockObject) HashSet(java.util.HashSet) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) HashMap(java.util.HashMap) Map(java.util.Map) StringMap(com.emc.storageos.db.client.model.StringMap) ExportOrchestrationTask(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask)

Aggregations

BlockObject (com.emc.storageos.db.client.model.BlockObject)341 URI (java.net.URI)222 ArrayList (java.util.ArrayList)152 Volume (com.emc.storageos.db.client.model.Volume)141 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)109 NamedURI (com.emc.storageos.db.client.model.NamedURI)82 HashMap (java.util.HashMap)82 BlockSnapshot (com.emc.storageos.db.client.model.BlockSnapshot)69 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)65 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)60 ExportMask (com.emc.storageos.db.client.model.ExportMask)56 HashSet (java.util.HashSet)56 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)48 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)45 CIMObjectPath (javax.cim.CIMObjectPath)44 Initiator (com.emc.storageos.db.client.model.Initiator)43 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)43 List (java.util.List)40 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)38 StringSet (com.emc.storageos.db.client.model.StringSet)36