Search in sources :

Example 1 with ExportMaskAddVolumeCompleter

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

the class AbstractDefaultMaskingOrchestrator method generateExportMaskAddVolumesWorkflow.

/**
 * Generate workflow steps to add volumes to an export mask
 *
 * @param workflow
 *            workflow
 * @param previousStep
 *            previous step ID
 * @param storage
 *            storage system
 * @param exportGroup
 *            export group
 * @param exportMask
 *            export mask
 * @param volumesToAdd
 *            volumes to add to the mask
 * @param initiators
 *            initiators that should be impacted by this operation (and for rollback)
 * @return step ID
 * @throws Exception
 */
public String generateExportMaskAddVolumesWorkflow(Workflow workflow, String previousStep, StorageSystem storage, ExportGroup exportGroup, ExportMask exportMask, Map<URI, Integer> volumesToAdd, List<URI> initiators) throws Exception {
    URI exportGroupURI = exportGroup.getId();
    URI exportMaskURI = exportMask.getId();
    URI storageURI = storage.getId();
    String maskingStep = workflow.createStepId();
    ExportTaskCompleter exportTaskCompleter = new ExportMaskAddVolumeCompleter(exportGroupURI, exportMask.getId(), volumesToAdd, maskingStep);
    Workflow.Method maskingExecuteMethod = new Workflow.Method("doExportGroupAddVolumes", storageURI, exportGroupURI, exportMaskURI, volumesToAdd, initiators, exportTaskCompleter);
    Workflow.Method maskingRollbackMethod = new Workflow.Method("rollbackExportGroupAddVolumes", storageURI, exportGroupURI, exportMaskURI, volumesToAdd, initiators, maskingStep);
    maskingStep = workflow.createStep(EXPORT_GROUP_MASKING_TASK, String.format("Adding volumes to mask %s (%s)", exportMask.getMaskName(), exportMask.getId().toString()), previousStep, storageURI, storage.getSystemType(), MaskingWorkflowEntryPoints.class, maskingExecuteMethod, maskingRollbackMethod, maskingStep);
    return maskingStep;
}
Also used : ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) Workflow(com.emc.storageos.workflow.Workflow) ExportMaskAddVolumeCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddVolumeCompleter) URI(java.net.URI)

Example 2 with ExportMaskAddVolumeCompleter

use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddVolumeCompleter 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 3 with ExportMaskAddVolumeCompleter

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

the class VPlexBackendManager method addWorkflowStepsToAddBackendVolumes.

/**
 * Add steps to generate the Workflow to add a volume to the VPLEX backend.
 * The VNX is special, we do zoning after masking.
 * For all the other arrays, we do zoning, then masking.
 *
 * @param workflow
 * @param dependantStepId
 * @param exportGroup
 * @param exportMask
 * @param volumeMap
 * @param varrayURI
 * @param vplex
 * @param array
 * @param forgetRollbackStepId
 * @return String stepId of last added step
 */
public String addWorkflowStepsToAddBackendVolumes(Workflow workflow, String dependantStepId, ExportGroup exportGroup, ExportMask exportMask, Map<URI, Volume> volumeMap, URI varrayURI, StorageSystem vplex, StorageSystem array, String forgetRollbackStepId) {
    // Determine if VNX or OpenStack so can order VNX zoning after masking
    boolean isMaskingFirst = isMaskingFirst(array);
    boolean isOpenStack = isOpenStack(array);
    Map<URI, Integer> volumeLunIdMap = createVolumeMap(array.getId(), volumeMap);
    String zoningStep = null;
    String maskStepId = workflow.createStepId();
    String reValidateExportMaskStep = workflow.createStepId();
    ExportMaskAddVolumeCompleter createCompleter = new ExportMaskAddVolumeCompleter(exportGroup.getId(), exportMask.getId(), volumeLunIdMap, maskStepId, forgetRollbackStepId);
    List<URI> volumeList = new ArrayList<>();
    volumeList.addAll(volumeLunIdMap.keySet());
    String previousStepId = dependantStepId;
    String zoningDependentStep = ((isMaskingFirst && isOpenStack) ? reValidateExportMaskStep : ((isMaskingFirst && !isOpenStack) ? maskStepId : previousStepId));
    if (exportMask.getCreatedBySystem()) {
        _log.info(String.format("Creating zone references for Backend ExportMask %s", exportMask.getMaskName()));
        List<URI> maskURIs = Collections.singletonList(exportMask.getId());
        List<NetworkZoningParam> zoningParams = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportGroup.getId(), maskURIs, _dbClient);
        HashSet<URI> volumes = new HashSet<URI>(volumeLunIdMap.keySet());
        Workflow.Method zoneCreateMethod = _networkDeviceController.zoneExportAddVolumesMethod(exportGroup.getId(), maskURIs, volumes);
        Workflow.Method zoneDeleteMethod = _networkDeviceController.zoneExportRemoveVolumesMethod(zoningParams, volumes);
        zoningStep = workflow.createStep(ZONING_STEP, String.format("Adding zones for ExportMask %s", exportMask.getMaskName()), zoningDependentStep, nullURI, "network-system", _networkDeviceController.getClass(), zoneCreateMethod, zoneDeleteMethod, null);
        if (!isMaskingFirst) {
            previousStepId = zoningStep;
        }
    }
    // Initiators that are sent down for export validation are the known initiators.
    // For back-end VPLEX masks, I find that userAddedInitiators are not getting filled-in,
    // so we're playing it safe by using known initiators.
    List<URI> initiatorURIs = new ArrayList<>();
    if (exportMask.getInitiators() != null) {
        initiatorURIs = new ArrayList<URI>(Collections2.transform(exportMask.getInitiators(), CommonTransformerFunctions.FCTN_STRING_TO_URI));
    }
    VplexBackEndMaskingOrchestrator orca = getOrch(array);
    Workflow.Method updateMaskMethod = orca.createOrAddVolumesToExportMaskMethod(array.getId(), exportGroup.getId(), exportMask.getId(), volumeLunIdMap, initiatorURIs, createCompleter);
    Workflow.Method rollbackMaskMethod = orca.deleteOrRemoveVolumesFromExportMaskMethod(array.getId(), exportGroup.getId(), exportMask.getId(), volumeList, initiatorURIs);
    workflow.createStep(EXPORT_STEP, "createOrAddVolumesToExportMask: " + exportMask.getMaskName(), previousStepId, array.getId(), array.getSystemType(), orca.getClass(), updateMaskMethod, rollbackMaskMethod, maskStepId);
    // This is required as the export mask gets updated by reading the cinder response.
    if (isOpenStack) {
        // START - updateZoningMapAndValidateExportMask Step
        Workflow.Method updatezoningAndvalidateMaskMethod = ((VplexCinderMaskingOrchestrator) orca).updateZoningMapAndValidateExportMaskMethod(varrayURI, _initiatorPortMap, exportMask.getId(), _directorToInitiatorIds, _idToInitiatorMap, _portWwnToClusterMap, vplex, array, _cluster);
        workflow.createStep(REVALIDATE_MASK, "updatezoningAndrevalidateExportMask: " + exportMask.getMaskName(), maskStepId, array.getId(), array.getSystemType(), orca.getClass(), updatezoningAndvalidateMaskMethod, rollbackMaskMethod, reValidateExportMaskStep);
    // END - updateZoningMapAndValidateExportMask Step
    }
    _log.info(String.format("VPLEX ExportGroup %s (%s) vplex %s varray %s", exportGroup.getLabel(), exportGroup.getId(), vplex.getId(), exportGroup.getVirtualArray()));
    return (isMaskingFirst && zoningStep != null) ? zoningStep : maskStepId;
}
Also used : VplexCinderMaskingOrchestrator(com.emc.storageos.volumecontroller.impl.block.VplexCinderMaskingOrchestrator) ArrayList(java.util.ArrayList) Workflow(com.emc.storageos.workflow.Workflow) URI(java.net.URI) NetworkZoningParam(com.emc.storageos.networkcontroller.impl.NetworkZoningParam) VplexBackEndMaskingOrchestrator(com.emc.storageos.volumecontroller.impl.block.VplexBackEndMaskingOrchestrator) ExportMaskAddVolumeCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddVolumeCompleter) HashSet(java.util.HashSet)

Example 4 with ExportMaskAddVolumeCompleter

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

the class VPlexDeviceController method storageViewAddVolumes.

/**
 * Method for adding volumes to a single ExportMask.
 *
 * @param vplexURI
 * @param exportGroupURI
 * @param exportMaskURI
 * @param volumeMap
 * @param opId
 * @throws ControllerException
 */
public void storageViewAddVolumes(URI vplexURI, URI exportGroupURI, URI exportMaskURI, Map<URI, Integer> volumeMap, String opId) throws ControllerException {
    String volListStr = "";
    ExportMaskAddVolumeCompleter completer = null;
    try {
        WorkflowStepCompleter.stepExecuting(opId);
        completer = new ExportMaskAddVolumeCompleter(exportGroupURI, exportMaskURI, volumeMap, opId);
        ExportOperationContext context = new VplexExportOperationContext();
        // Prime the context object
        completer.updateWorkflowStepContext(context);
        volListStr = Joiner.on(',').join(volumeMap.keySet());
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportMask exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_001);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        // Need to massage the map to fit the API
        List<BlockObject> volumes = new ArrayList<BlockObject>();
        Map<String, Integer> deviceLabelToHLU = new HashMap<String, Integer>();
        boolean duplicateHLU = false;
        List<URI> volumesToAdd = new ArrayList<URI>();
        String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
        VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
        VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName), _networkDeviceController);
        exportMask = getDataObject(ExportMask.class, exportMaskURI, _dbClient);
        for (Map.Entry<URI, Integer> entry : volumeMap.entrySet()) {
            if (exportMask.hasVolume(entry.getKey())) {
                _log.info(String.format("Volume %s is already in Exportmask %s %s hence skipping adding volume again. This must be shared exportmask. ", entry.getKey(), exportMask.getMaskName(), exportMask.getId()));
                continue;
            }
            Integer requestedHLU = entry.getValue();
            // If user have provided specific HLU for volume, then check if its already in use
            if (requestedHLU.intValue() != VPlexApiConstants.LUN_UNASSIGNED && exportMask.anyVolumeHasHLU(requestedHLU.toString())) {
                String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
                _log.error(message);
                String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
                ServiceError serviceError = VPlexApiException.errors.exportHasExistingVolumeWithRequestedHLU(entry.getKey().toString(), requestedHLU.toString(), opName);
                failStep(completer, opId, serviceError);
                duplicateHLU = true;
                break;
            }
            BlockObject vol = Volume.fetchExportMaskBlockObject(_dbClient, entry.getKey());
            volumes.add(vol);
            deviceLabelToHLU.put(vol.getDeviceLabel(), requestedHLU);
            volumesToAdd.add(entry.getKey());
        }
        // If duplicate HLU are found then return, completer is set to error above
        if (duplicateHLU) {
            return;
        }
        // If deviceLabelToHLU map is empty then volumes already exists in the storage view hence return.
        if (deviceLabelToHLU.isEmpty()) {
            completer.ready(_dbClient);
            return;
        }
        VPlexStorageViewInfo svInfo = client.addVirtualVolumesToStorageView(exportMask.getMaskName(), vplexClusterName, deviceLabelToHLU);
        ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_VOLUMES_TO_STORAGE_VIEW, volumesToAdd);
        // When VPLEX volumes are exported to a storage view, they get a WWN,
        // so set the WWN from the returned storage view information.
        Map<URI, Integer> updatedVolumeMap = new HashMap<URI, Integer>();
        for (BlockObject volume : volumes) {
            String deviceLabel = volume.getDeviceLabel();
            String wwn = svInfo.getWWNForStorageViewVolume(volume.getDeviceLabel());
            volume.setWWN(wwn);
            _dbClient.updateObject(volume);
            updatedVolumeMap.put(volume.getId(), svInfo.getHLUForStorageViewVolume(deviceLabel));
            // user.
            if (exportMask.hasExistingVolume(wwn)) {
                _log.info("wwn {} has been added to the storage view {} by the user, but it " + "was already in existing volumes, removing from existing volumes.", wwn, exportMask.forDisplay());
                exportMask.removeFromExistingVolumes(wwn);
            }
            exportMask.addToUserCreatedVolumes(volume);
        }
        // We also need to update the volume/lun id map in the export mask
        // to those assigned by the VPLEX.
        _log.info("Updating volume/lun map in export mask {}", exportMask.getId());
        exportMask.addVolumes(updatedVolumeMap);
        _dbClient.updateObject(exportMask);
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_002);
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
        _log.error(message, vae);
        failStep(completer, opId, vae);
    } catch (Exception ex) {
        String message = String.format("Failed to add Volumes %s to ExportMask %s", volListStr, exportMaskURI);
        _log.error(message, ex);
        String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
        ServiceError serviceError = VPlexApiException.errors.exportGroupAddVolumesFailed(volListStr, exportGroupURI.toString(), opName, ex);
        failStep(completer, opId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) HashMap(java.util.HashMap) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) ExportMaskAddVolumeCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddVolumeCompleter) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

ExportMaskAddVolumeCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskAddVolumeCompleter)4 URI (java.net.URI)4 Workflow (com.emc.storageos.workflow.Workflow)3 ArrayList (java.util.ArrayList)3 BlockObject (com.emc.storageos.db.client.model.BlockObject)2 ExportMask (com.emc.storageos.db.client.model.ExportMask)2 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)2 StringMap (com.emc.storageos.db.client.model.StringMap)2 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)2 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)2 ExportTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter)2 HashSet (java.util.HashSet)2 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)1 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)1 ExportPathParams (com.emc.storageos.db.client.model.ExportPathParams)1 Initiator (com.emc.storageos.db.client.model.Initiator)1 NamedURI (com.emc.storageos.db.client.model.NamedURI)1 OpStatusMap (com.emc.storageos.db.client.model.OpStatusMap)1 StoragePortGroup (com.emc.storageos.db.client.model.StoragePortGroup)1 StringSet (com.emc.storageos.db.client.model.StringSet)1