Search in sources :

Example 16 with ExportMaskValidationContext

use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.

the class VNXeExportOperations method removeInitiators.

@Override
public void removeInitiators(StorageSystem storage, URI exportMask, List<URI> volumeURIList, List<Initiator> initiators, List<URI> targets, TaskCompleter taskCompleter) throws DeviceControllerException {
    _logger.info("{} removeInitiators START...", storage.getSerialNumber());
    ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMask);
    if (mask == null || mask.getInactive()) {
        _logger.error(String.format("The exportMask %s is invalid.", exportMask));
        throw DeviceControllerException.exceptions.invalidObjectNull();
    }
    boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId());
    if (isRollback) {
        List<Initiator> addedInitiators = new ArrayList<Initiator>();
        // Get the context from the task completer, in case this is a rollback.
        ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
        if (context != null && context.getOperations() != null) {
            _logger.info("Handling removeInitiators as a result of rollback");
            ListIterator li = context.getOperations().listIterator(context.getOperations().size());
            while (li.hasPrevious()) {
                ExportOperationContextOperation operation = (ExportOperationContextOperation) li.previous();
                if (operation != null && VNXeExportOperationContext.OPERATION_ADD_INITIATORS_TO_HOST.equals(operation.getOperation())) {
                    addedInitiators = (List<Initiator>) operation.getArgs().get(0);
                    _logger.info("Removing initiators {} as part of rollback", Joiner.on(',').join(addedInitiators));
                }
            }
        }
        // Update the initiators in the task completer such that we update the export mask/group correctly
        for (Initiator initiator : initiators) {
            if (addedInitiators == null || !addedInitiators.contains(initiator)) {
                ((ExportMaskRemoveInitiatorCompleter) taskCompleter).removeInitiator(initiator.getId());
            }
        }
        initiators = addedInitiators;
        if (initiators == null || initiators.isEmpty()) {
            _logger.info("There was no context found for add initiator. So there is nothing to rollback.");
            taskCompleter.ready(_dbClient);
            return;
        }
    }
    StringSet initiatorsInMask = mask.getInitiators();
    List<Initiator> initiatorToBeRemoved = new ArrayList<>();
    for (Initiator initiator : initiators) {
        if (initiatorsInMask.contains(initiator.getId().toString())) {
            initiatorToBeRemoved.add(initiator);
        }
    }
    try {
        VNXeApiClient apiClient = getVnxeClient(storage);
        List<Initiator> allInitiators = ExportUtils.getExportMaskInitiators(exportMask, _dbClient);
        String vnxeHostId = getHostIdFromInitiators(allInitiators, apiClient);
        if (vnxeHostId != null) {
            List<VNXeHostInitiator> vnxeInitiators = apiClient.getInitiatorsByHostId(vnxeHostId);
            // initiators is a subset of allInitiators
            Map<Initiator, VNXeHostInitiator> vnxeInitiatorsToBeRemoved = prepareInitiators(initiatorToBeRemoved);
            Set<String> initiatorIds = new HashSet<String>();
            for (VNXeHostInitiator vnxeInit : vnxeInitiators) {
                initiatorIds.add(vnxeInit.getInitiatorId());
            }
            Set<String> initiatorsToBeRemoved = new HashSet<String>();
            for (VNXeHostInitiator vnxeInit : vnxeInitiatorsToBeRemoved.values()) {
                String initiatorId = vnxeInit.getId();
                if (initiatorIds.remove(initiatorId)) {
                    initiatorsToBeRemoved.add(initiatorId);
                }
            }
            ExportMaskValidationContext ctx = new ExportMaskValidationContext();
            ctx.setStorage(storage);
            ctx.setExportMask(mask);
            ctx.setBlockObjects(volumeURIList, _dbClient);
            // Allow exceptions to be thrown when not rolling back
            ctx.setAllowExceptions(!isRollback);
            AbstractVNXeValidator removeInitiatorsValidator = (AbstractVNXeValidator) validator.removeInitiators(ctx);
            removeInitiatorsValidator.setHostId(vnxeHostId);
            removeInitiatorsValidator.validate();
            // 3. shared initiators, but all export masks have same set of initiators
            if (!isRollback) {
                boolean hasSharedInitiator = false;
                for (Initiator initiator : initiatorToBeRemoved) {
                    if (ExportUtils.isInitiatorSharedByMasks(_dbClient, mask, initiator.getId())) {
                        hasSharedInitiator = true;
                        break;
                    }
                }
                if (hasSharedInitiator) {
                    validateAllMasks(_dbClient, mask, apiClient, vnxeHostId);
                }
            }
        }
        List<String> initiatorIdList = new ArrayList<>();
        for (Initiator initiator : initiatorToBeRemoved) {
            _logger.info("Processing initiator {}", initiator.getLabel());
            if (vnxeHostId != null) {
                String initiatorId = initiator.getInitiatorPort();
                if (Protocol.FC.name().equals(initiator.getProtocol())) {
                    initiatorId = initiator.getInitiatorNode() + ":" + initiatorId;
                }
                initiatorIdList.add(initiatorId);
            }
            mask.removeFromExistingInitiators(initiator);
            mask.removeFromUserCreatedInitiators(initiator);
        }
        if (!initiatorIdList.isEmpty()) {
            apiClient.deleteInitiators(initiatorIdList);
        }
        _dbClient.updateObject(mask);
        taskCompleter.ready(_dbClient);
    } catch (Exception e) {
        _logger.error("Problem in removeInitiators: ", e);
        ServiceError serviceError = DeviceControllerErrors.vnxe.jobFailed("removeInitiator", e.getMessage());
        taskCompleter.error(_dbClient, serviceError);
    }
    _logger.info("{} removeInitiators END...", storage.getSerialNumber());
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VNXeApiClient(com.emc.storageos.vnxe.VNXeApiClient) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) ListIterator(java.util.ListIterator) VNXeHostInitiator(com.emc.storageos.vnxe.models.VNXeHostInitiator) ExportMaskRemoveInitiatorCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskRemoveInitiatorCompleter) VNXeException(com.emc.storageos.vnxe.VNXeException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) AbstractVNXeValidator(com.emc.storageos.volumecontroller.impl.validators.vnxe.AbstractVNXeValidator) Initiator(com.emc.storageos.db.client.model.Initiator) VNXeHostInitiator(com.emc.storageos.vnxe.models.VNXeHostInitiator) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) StringSet(com.emc.storageos.db.client.model.StringSet) ExportOperationContextOperation(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext.ExportOperationContextOperation) HashSet(java.util.HashSet)

Example 17 with ExportMaskValidationContext

use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.

the class VNXeExportOperations method deleteExportMask.

@Override
public void deleteExportMask(StorageSystem storage, URI exportMaskUri, List<URI> volumeURIList, List<URI> targetURIList, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
    _logger.info("{} deleteExportMask START...", storage.getSerialNumber());
    boolean removeLastInitiator = false;
    List<URI> volumesToBeUnmapped = new ArrayList<URI>();
    try {
        _logger.info("Export mask id: {}", exportMaskUri);
        if (volumeURIList != null) {
            _logger.info("deleteExportMask: volumes:  {}", Joiner.on(',').join(volumeURIList));
        }
        if (targetURIList != null) {
            _logger.info("deleteExportMask: assignments: {}", Joiner.on(',').join(targetURIList));
        }
        if (initiatorList != null) {
            if (!initiatorList.isEmpty()) {
                removeLastInitiator = true;
                _logger.info("deleteExportMask: initiators: {}", Joiner.on(',').join(initiatorList));
            }
        }
        // Get the context from the task completer, in case this is a rollback.
        boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId());
        if (isRollback) {
            List<URI> addedVolumes = new ArrayList<URI>();
            ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
            if (context != null && context.getOperations() != null) {
                _logger.info("Handling deleteExportMask as a result of rollback");
                ListIterator li = context.getOperations().listIterator(context.getOperations().size());
                while (li.hasPrevious()) {
                    ExportOperationContextOperation operation = (ExportOperationContextOperation) li.previous();
                    if (operation != null && VNXeExportOperationContext.OPERATION_ADD_VOLUMES_TO_HOST_EXPORT.equals(operation.getOperation())) {
                        addedVolumes = (List<URI>) operation.getArgs().get(0);
                        _logger.info("Removing volumes {} as part of rollback", Joiner.on(',').join(addedVolumes));
                    }
                }
            }
            volumesToBeUnmapped = addedVolumes;
            if (volumesToBeUnmapped == null || volumesToBeUnmapped.isEmpty()) {
                _logger.info("There was no context found for add volumes. So there is nothing to rollback.");
                taskCompleter.ready(_dbClient);
                return;
            }
        } else {
            volumesToBeUnmapped = volumeURIList;
        }
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskUri);
        if (exportMask == null || exportMask.getInactive()) {
            throw new DeviceControllerException("Invalid ExportMask URI: " + exportMaskUri);
        }
        if (initiatorList.isEmpty()) {
            initiatorList = ExportUtils.getExportMaskInitiators(exportMask, _dbClient);
        }
        VNXeApiClient apiClient = getVnxeClient(storage);
        String hostId = getHostIdFromInitiators(initiatorList, apiClient);
        Set<String> allExportedVolumes = new HashSet<>();
        if (hostId != null) {
            ExportMaskValidationContext ctx = new ExportMaskValidationContext();
            ctx.setStorage(storage);
            ctx.setExportMask(exportMask);
            ctx.setBlockObjects(volumeURIList, _dbClient);
            ctx.setInitiators(initiatorList);
            // Allow exceptions to be thrown when not rolling back
            ctx.setAllowExceptions(!isRollback);
            AbstractVNXeValidator deleteMaskValidator = (AbstractVNXeValidator) validator.exportMaskDelete(ctx);
            deleteMaskValidator.setHostId(hostId);
            deleteMaskValidator.validate();
            if (removeLastInitiator) {
                ctx = new ExportMaskValidationContext();
                ctx.setStorage(storage);
                ctx.setExportMask(exportMask);
                ctx.setBlockObjects(volumeURIList, _dbClient);
                ctx.setAllowExceptions(!isRollback);
                AbstractVNXeValidator removeInitiatorsValidator = (AbstractVNXeValidator) validator.removeInitiators(ctx);
                removeInitiatorsValidator.setHostId(hostId);
                removeInitiatorsValidator.validate();
                boolean hasSharedInitiator = false;
                for (String strUri : exportMask.getInitiators()) {
                    if (ExportUtils.isInitiatorSharedByMasks(_dbClient, exportMask, URI.create(strUri))) {
                        hasSharedInitiator = true;
                        _logger.info("Initiators are used by multiple export masks");
                        break;
                    }
                }
                if (hasSharedInitiator) {
                    // if any initiator is shared, all initiators have to be shared, and each mask should have same set of initiators
                    // Otherwise, removing initiator will not be allowed, user can delete individual export mask
                    Collection<ExportMask> masksWithSharedInitiators = validateAllMasks(_dbClient, exportMask, apiClient, hostId);
                    _logger.info("Masks use the same initiators {}", Joiner.on(", ").join(Collections2.transform(masksWithSharedInitiators, CommonTransformerFunctions.fctnDataObjectToForDisplay())));
                    // need to unexport all volumes of all export masks
                    // except shared export co-exists with exclusive export, don't touch exclusive export
                    // in case of multiple shared exports (e.g., with different projects), all exported LUNs will be unmapped, regardless exclusive export
                    String exportType = ExportMaskUtils.getExportType(_dbClient, exportMask);
                    if (ExportGroupType.Cluster.name().equals(exportType)) {
                        Iterator<ExportMask> maskIter = masksWithSharedInitiators.iterator();
                        while (maskIter.hasNext()) {
                            ExportMask mask = maskIter.next();
                            if (!ExportGroupType.Cluster.name().equals(ExportMaskUtils.getExportType(_dbClient, mask))) {
                                _logger.info("Ignore exclusive export {}", mask.getMaskName());
                                maskIter.remove();
                            }
                        }
                    }
                    volumesToBeUnmapped.addAll(getExportedVolumes(_dbClient, storage.getId(), masksWithSharedInitiators));
                }
            }
            allExportedVolumes = ExportUtils.getAllLUNsForHost(_dbClient, exportMask);
        }
        String opId = taskCompleter.getOpId();
        Set<String> processedCGs = new HashSet<String>();
        for (URI volUri : volumesToBeUnmapped) {
            if (hostId != null) {
                BlockObject blockObject = BlockObject.fetch(_dbClient, volUri);
                String nativeId = blockObject.getNativeId();
                String cgName = VNXeUtils.getBlockObjectCGName(blockObject, _dbClient);
                if (cgName != null && !processedCGs.contains(cgName)) {
                    processedCGs.add(cgName);
                    VNXeUtils.getCGLock(workflowService, storage, cgName, opId);
                }
                if (URIUtil.isType(volUri, Volume.class)) {
                    apiClient.unexportLun(hostId, nativeId);
                } else if (URIUtil.isType(volUri, BlockSnapshot.class)) {
                    if (BlockObject.checkForRP(_dbClient, volUri)) {
                        _logger.info(String.format("BlockObject %s is a RecoverPoint bookmark. Un-exporting associated lun %s instead of snap.", volUri, nativeId));
                        apiClient.unexportLun(hostId, nativeId);
                    } else {
                        apiClient.unexportSnap(hostId, nativeId);
                        setSnapWWN(apiClient, blockObject, nativeId);
                    }
                }
            }
            // update the exportMask object
            exportMask.removeVolume(volUri);
        }
        // check if there are LUNs on array
        // initiator will not be able to removed if there are LUNs belongs to other masks (if initiator is shared), or unknown to ViPR
        Set<String> lunIds = new HashSet<>();
        if (hostId != null) {
            lunIds = apiClient.getHostLUNIds(hostId);
            _logger.info("Mapped resources {}", Joiner.on(", ").join(lunIds));
        }
        boolean hasLUN = lunIds.isEmpty() ? false : true;
        lunIds.removeAll(allExportedVolumes);
        boolean hasUnknownLUN = lunIds.isEmpty() ? false : true;
        _logger.info("Export mask deletion - hasLUN {}, hasUnknownLUN {}", hasLUN, hasUnknownLUN);
        for (Initiator initiator : initiatorList) {
            _logger.info("Processing initiator {}", initiator.getLabel());
            if (hostId != null && (!hasLUN || (!hasUnknownLUN && !ExportUtils.isInitiatorSharedByMasks(_dbClient, exportMask, initiator.getId())))) {
                String initiatorId = initiator.getInitiatorPort();
                if (Protocol.FC.name().equals(initiator.getProtocol())) {
                    initiatorId = initiator.getInitiatorNode() + ":" + initiatorId;
                }
                try {
                    if (hasLUN) {
                        // move and delete initiator
                        apiClient.deleteInitiators(new ArrayList<String>(Arrays.asList(initiatorId)));
                    } else {
                        apiClient.deleteInitiator(initiatorId);
                    }
                } catch (VNXeException e) {
                    _logger.warn("Error on deleting initiator: {}", e.getMessage());
                }
            }
            exportMask.removeFromExistingInitiators(initiator);
            exportMask.removeFromUserCreatedInitiators(initiator);
        }
        _dbClient.updateObject(exportMask);
        if (hostId != null) {
            List<VNXeHostInitiator> vnxeInitiators = apiClient.getInitiatorsByHostId(hostId);
            if (vnxeInitiators.isEmpty()) {
                Set<String> vnxeLUNIds = apiClient.getHostLUNIds(hostId);
                if ((vnxeLUNIds.isEmpty())) {
                    try {
                        apiClient.deleteHost(hostId);
                    } catch (VNXeException e) {
                        _logger.warn("Error on deleting host: {}", e.getMessage());
                    }
                }
            }
        }
        List<ExportGroup> exportGroups = ExportMaskUtils.getExportGroups(_dbClient, exportMask);
        if (exportGroups != null) {
            // Remove the mask references in the export group
            for (ExportGroup exportGroup : exportGroups) {
                // Remove this mask from the export group
                exportGroup.removeExportMask(exportMask.getId().toString());
            }
            // Update all of the export groups in the DB
            _dbClient.updateObject(exportGroups);
        }
        taskCompleter.ready(_dbClient);
    } catch (Exception e) {
        _logger.error("Unexpected error: deleteExportMask failed.", e);
        ServiceError error = DeviceControllerErrors.vnxe.jobFailed("deleteExportMask", e.getMessage());
        taskCompleter.error(_dbClient, error);
    }
    _logger.info("{} deleteExportMask END...", storage.getSerialNumber());
}
Also used : VNXeApiClient(com.emc.storageos.vnxe.VNXeApiClient) ArrayList(java.util.ArrayList) VNXeHostInitiator(com.emc.storageos.vnxe.models.VNXeHostInitiator) URI(java.net.URI) Initiator(com.emc.storageos.db.client.model.Initiator) VNXeHostInitiator(com.emc.storageos.vnxe.models.VNXeHostInitiator) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) ExportOperationContextOperation(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext.ExportOperationContextOperation) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) 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) BlockSnapshot(com.emc.storageos.db.client.model.BlockSnapshot) ListIterator(java.util.ListIterator) VNXeException(com.emc.storageos.vnxe.VNXeException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) AbstractVNXeValidator(com.emc.storageos.volumecontroller.impl.validators.vnxe.AbstractVNXeValidator) VNXeException(com.emc.storageos.vnxe.VNXeException)

Example 18 with ExportMaskValidationContext

use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.

the class VPlexDeviceController method storageViewRemoveInitiators.

/**
 * Workflow step to remove an initiator from a single Storage View as given by the ExportMask URI.
 * Note there is a dependence on ExportMask name equaling the Storage View name.
 * Note that arguments must match storageViewRemoveInitiatorsMethod above (except stepId).
 *
 * @param vplexURI
 *            -- URI of Vplex Storage System.
 * @param exportGroupURI
 *            -- URI of Export Group.
 * @param exportMaskURI
 *            -- URI of one ExportMask. Call only processes indicaated mask.
 * @param initiatorURIs
 *            -- URIs of Initiators to be removed.
 * @param targetURIs
 *            -- optional targets to be removed from the Storage View.
 *            If non null, a list of URIs for VPlex front-end ports that will be removed from Storage View.
 * @param taskCompleter
 *            -- the task completer, used to find the rollback context,
 *               which will be non-null in the case of rollback
 * @param rollbackContextKey
 *            context key for rollback processing
 * @param stepId
 *            -- Workflow step id.
 * @throws WorkflowException
 */
public void storageViewRemoveInitiators(URI vplexURI, URI exportGroupURI, URI exportMaskURI, List<URI> initiatorURIs, List<URI> targetURIs, TaskCompleter taskCompleter, String rollbackContextKey, String stepId) throws WorkflowException {
    ExportMaskRemoveInitiatorCompleter completer = null;
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        List<URI> initiatorIdsToProcess = new ArrayList<>(initiatorURIs);
        completer = new ExportMaskRemoveInitiatorCompleter(exportGroupURI, exportMaskURI, initiatorURIs, stepId);
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
        Map<String, String> targetPortMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
        VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
        _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
        VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortMap, _networkDeviceController);
        // get the context from the task completer, in case this is a rollback.
        if (taskCompleter != null && rollbackContextKey != null) {
            ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(rollbackContextKey);
            if (context != null) {
                // a non-null context means this step is running as part of a rollback.
                List<URI> addedInitiators = new ArrayList<>();
                if (context.getOperations() != null) {
                    _log.info("Handling removeInitiators as a result of rollback");
                    ListIterator<ExportOperationContextOperation> li = context.getOperations().listIterator(context.getOperations().size());
                    while (li.hasPrevious()) {
                        ExportOperationContextOperation operation = (ExportOperationContextOperation) li.previous();
                        if (operation != null && VplexExportOperationContext.OPERATION_ADD_INITIATORS_TO_STORAGE_VIEW.equals(operation.getOperation())) {
                            addedInitiators = (List<URI>) operation.getArgs().get(0);
                            _log.info("Removing initiators {} as part of rollback", Joiner.on(',').join(addedInitiators));
                        }
                    }
                }
                // Update the initiators in the task completer such that we update the export mask/group correctly
                for (URI initiator : initiatorIdsToProcess) {
                    if (addedInitiators == null || !addedInitiators.contains(initiator)) {
                        completer.removeInitiator(initiator);
                    }
                }
                if (addedInitiators == null || addedInitiators.isEmpty()) {
                    _log.info("There was no context found for add initiator. So there is nothing to rollback.");
                    completer.ready(_dbClient);
                    return;
                }
                // Change the list of initiators to process to the list
                // that successfully were added during addInitiators.
                initiatorIdsToProcess.clear();
                initiatorIdsToProcess.addAll(addedInitiators);
            }
        }
        // validate the remove initiator operation against the export mask volumes
        List<URI> volumeURIList = (exportMask.getUserAddedVolumes() != null) ? URIUtil.toURIList(exportMask.getUserAddedVolumes().values()) : new ArrayList<URI>();
        if (volumeURIList.isEmpty()) {
            _log.warn("volume URI list for validating remove initiators is empty...");
        }
        ExportMaskValidationContext ctx = new ExportMaskValidationContext();
        ctx.setStorage(vplex);
        ctx.setExportMask(exportMask);
        ctx.setBlockObjects(volumeURIList, _dbClient);
        ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(stepId));
        validator.removeInitiators(ctx).validate();
        // Invoke artificial failure to simulate invalid storageview name on vplex
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_060);
        // removing all storage ports but leaving the existing initiators and volumes.
        if (!exportMask.hasAnyExistingInitiators() && !exportMask.hasAnyExistingVolumes()) {
            if (targetURIs != null && targetURIs.isEmpty() == false) {
                List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
                List<URI> targetsAddedToStorageView = new ArrayList<URI>();
                for (URI target : targetURIs) {
                    // Do not try to remove a port twice.
                    if (!exportMask.getStoragePorts().contains(target.toString())) {
                        continue;
                    }
                    // Build the PortInfo structure for the port to be added
                    StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
                    PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
                    targetPortInfos.add(pi);
                    targetsAddedToStorageView.add(target);
                }
                if (!targetPortInfos.isEmpty()) {
                    // Remove the targets from the VPLEX
                    client.removeTargetsFromStorageView(exportMask.getMaskName(), targetPortInfos);
                }
            }
        }
        // Update the initiators in the ExportMask.
        List<PortInfo> initiatorPortInfo = new ArrayList<PortInfo>();
        for (URI initiatorURI : initiatorIdsToProcess) {
            Initiator initiator = getDataObject(Initiator.class, initiatorURI, _dbClient);
            // We don't want to remove existing initiator, unless this is a rollback step
            if (exportMask.hasExistingInitiator(initiator) && !WorkflowService.getInstance().isStepInRollbackState(stepId)) {
                continue;
            }
            PortInfo portInfo = new PortInfo(initiator.getInitiatorPort().toUpperCase().replaceAll(":", ""), initiator.getInitiatorNode().toUpperCase().replaceAll(":", ""), initiator.getLabel(), getVPlexInitiatorType(initiator));
            initiatorPortInfo.add(portInfo);
        }
        // Remove the initiators if there aren't any existing volumes, unless this is a rollback step or validation is disabled.
        if (!initiatorPortInfo.isEmpty() && (!exportMask.hasAnyExistingVolumes() || !validatorConfig.isValidationEnabled() || WorkflowService.getInstance().isStepInRollbackState(stepId))) {
            String lockName = null;
            boolean lockAcquired = false;
            try {
                ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
                String clusterId = ConnectivityUtil.getVplexClusterForVarray(exportGroup.getVirtualArray(), vplexURI, _dbClient);
                lockName = _vplexApiLockManager.getLockName(vplexURI, clusterId);
                lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
                if (!lockAcquired) {
                    throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplex.getLabel());
                }
                // Remove the targets from the VPLEX
                // Test mechanism to invoke a failure. No-op on production systems.
                InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_016);
                client.removeInitiatorsFromStorageView(exportMask.getMaskName(), vplexClusterName, initiatorPortInfo);
            } finally {
                if (lockAcquired) {
                    _vplexApiLockManager.releaseLock(lockName);
                }
            }
        }
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        _log.error("Exception removing initiator from Storage View: " + vae.getMessage(), vae);
        failStep(completer, stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception removing initiator from Storage View: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.DELETE_STORAGE_VIEW_INITIATOR.getName();
        ServiceError serviceError = VPlexApiException.errors.storageViewRemoveInitiatorFailed(opName, ex);
        failStep(completer, stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) StoragePort(com.emc.storageos.db.client.model.StoragePort) ExportMaskRemoveInitiatorCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskRemoveInitiatorCompleter) 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) PortInfo(com.emc.storageos.vplex.api.clientdata.PortInfo) ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) Initiator(com.emc.storageos.db.client.model.Initiator) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) ExportOperationContextOperation(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext.ExportOperationContextOperation) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 19 with ExportMaskValidationContext

use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.

the class VPlexDeviceController method removeVolumesFromStorageViewAndMask.

/**
 * Remove the specified volumes from the VPlex Storage View.
 * If that is successful, remove the volumes from the ExportMask and persist it.
 *
 * @param client
 *            -- VPlexApiClient used for communication
 * @param exportMask
 *            -- ExportMask corresponding to the StorageView
 * @param volumeURIList
 *            -- URI of virtual volumes
 * @param parentStepId
 *            -- the parent step id
 * @throws Exception
 */
private void removeVolumesFromStorageViewAndMask(VPlexApiClient client, ExportMask exportMask, List<URI> volumeURIList, String parentStepId) throws Exception {
    // If no volumes to remove, just return.
    if (volumeURIList.isEmpty()) {
        return;
    }
    // validate the remove volume operation against the export mask initiators
    List<Initiator> initiators = new ArrayList<Initiator>();
    if (exportMask.getUserAddedInitiators() != null && !exportMask.getUserAddedInitiators().isEmpty()) {
        Iterator<Initiator> initItr = _dbClient.queryIterativeObjects(Initiator.class, URIUtil.toURIList(exportMask.getUserAddedInitiators().values()), true);
        while (initItr.hasNext()) {
            initiators.add(initItr.next());
        }
    }
    StorageSystem vplex = _dbClient.queryObject(StorageSystem.class, exportMask.getStorageDevice());
    ExportMaskValidationContext ctx = new ExportMaskValidationContext();
    ctx.setStorage(vplex);
    ctx.setExportMask(exportMask);
    ctx.setInitiators(initiators);
    ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(parentStepId));
    validator.removeVolumes(ctx).validate();
    // Determine the virtual volume names.
    List<String> blockObjectNames = new ArrayList<String>();
    for (URI boURI : volumeURIList) {
        BlockObject blockObject = Volume.fetchExportMaskBlockObject(_dbClient, boURI);
        blockObjectNames.add(blockObject.getDeviceLabel());
    }
    // Remove volumes from the storage view.
    String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplex.getId(), client, _dbClient);
    _log.info("about to remove {} from StorageView {} on cluster {}", blockObjectNames, exportMask.getMaskName(), vplexClusterName);
    client.removeVirtualVolumesFromStorageView(exportMask.getMaskName(), vplexClusterName, blockObjectNames);
    _log.info("successfully removed " + blockObjectNames + " from StorageView " + exportMask.getMaskName());
}
Also used : ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) Initiator(com.emc.storageos.db.client.model.Initiator) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 20 with ExportMaskValidationContext

use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.

the class VPlexDeviceController method storageViewRemoveStoragePorts.

/**
 * Workflow Step to remove storage ports from Storage View.
 * Note arguments (except stepId) must match storageViewRemoveStoragePortsMethod above.
 *
 * @param vplexURI
 *            -- URI of VPlex StorageSystem
 * @param exportURI
 *            -- ExportGroup URI
 * @param maskURI
 *            -- ExportMask URI.
 * @param targetURIs
 *            -- list of targets URIs (VPLEX FE ports) to be removed.
 *            If non null, the targets (VPlex front end ports) indicated by the targetURIs will be removed
 *            from the Storage View.
 * @param rollbackContextKey
 *            -- Context token for rollback processing
 * @param stepId
 *            -- Workflow step id.
 * @throws WorkflowException
 */
public void storageViewRemoveStoragePorts(URI vplexURI, URI exportURI, URI maskURI, List<URI> targetURIs, String rollbackContextKey, String stepId) throws DeviceControllerException {
    ExportMaskRemoveInitiatorCompleter completer = null;
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        completer = new ExportMaskRemoveInitiatorCompleter(exportURI, maskURI, new ArrayList<URI>(), stepId);
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, maskURI);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
        Map<String, String> targetPortMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
        VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
        _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
        VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortMap, _networkDeviceController);
        // get the context from the task completer, in case this is a rollback.
        if (rollbackContextKey != null) {
            ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(rollbackContextKey);
            if (context != null) {
                // a non-null context means this step is running as part of a rollback.
                List<URI> addedTargets = new ArrayList<>();
                if (context.getOperations() != null) {
                    _log.info("Handling storageViewRemoveStoragePorts as a result of rollback");
                    ListIterator<ExportOperationContextOperation> li = context.getOperations().listIterator(context.getOperations().size());
                    while (li.hasPrevious()) {
                        ExportOperationContextOperation operation = (ExportOperationContextOperation) li.previous();
                        if (operation != null && VplexExportOperationContext.OPERATION_ADD_TARGETS_TO_STORAGE_VIEW.equals(operation.getOperation())) {
                            addedTargets = (List<URI>) operation.getArgs().get(0);
                            _log.info(String.format("Removing target port(s) %s from storage view %s as part of rollback", Joiner.on(',').join(addedTargets), exportMask.getMaskName()));
                        }
                    }
                }
                if (addedTargets == null || addedTargets.isEmpty()) {
                    _log.info("There was no context found for add target. So there is nothing to rollback.");
                    completer.ready(_dbClient);
                    return;
                }
                // Change the list of targets to process to the list
                // that successfully were added during addStoragePorts.
                targetURIs.clear();
                targetURIs.addAll(addedTargets);
            }
        }
        // validate the remove storage port operation against the export mask volumes
        // this is conceptually the same as remove initiators, so will validate with volumes
        List<URI> volumeURIList = (exportMask.getUserAddedVolumes() != null) ? URIUtil.toURIList(exportMask.getUserAddedVolumes().values()) : new ArrayList<URI>();
        if (volumeURIList.isEmpty()) {
            _log.warn("volume URI list for validating remove initiators is empty...");
        }
        // removing all storage ports but leaving the existing initiators and volumes.
        if (!exportMask.hasAnyExistingInitiators() && !exportMask.hasAnyExistingVolumes()) {
            ExportMaskValidationContext ctx = new ExportMaskValidationContext();
            ctx.setStorage(vplex);
            ctx.setExportMask(exportMask);
            ctx.setBlockObjects(volumeURIList, _dbClient);
            ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(stepId));
            validator.removeInitiators(ctx).validate();
            if (targetURIs != null && targetURIs.isEmpty() == false) {
                List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
                List<URI> targetsToRemoveFromStorageView = new ArrayList<URI>();
                for (URI target : targetURIs) {
                    // Do not try to remove a port twice.
                    if (!exportMask.getStoragePorts().contains(target.toString())) {
                        continue;
                    }
                    // Build the PortInfo structure for the port to be added
                    StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
                    PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
                    targetPortInfos.add(pi);
                    targetsToRemoveFromStorageView.add(target);
                }
                if (!targetPortInfos.isEmpty()) {
                    // Remove the targets from the VPLEX
                    client.removeTargetsFromStorageView(exportMask.getMaskName(), targetPortInfos);
                    // Remove the targets to the database.
                    for (URI target : targetsToRemoveFromStorageView) {
                        exportMask.removeTarget(target);
                    }
                    _dbClient.updateObject(exportMask);
                }
            }
        }
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        _log.error("Exception removing storage ports from Storage View: " + vae.getMessage(), vae);
        failStep(completer, stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception removing storage ports from Storage View: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.DELETE_STORAGE_VIEW_STORAGEPORTS.getName();
        ServiceError serviceError = VPlexApiException.errors.storageViewRemoveStoragePortFailed(opName, ex);
        failStep(completer, stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) StoragePort(com.emc.storageos.db.client.model.StoragePort) ExportMaskRemoveInitiatorCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskRemoveInitiatorCompleter) 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) PortInfo(com.emc.storageos.vplex.api.clientdata.PortInfo) ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) ExportOperationContextOperation(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext.ExportOperationContextOperation) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

ExportMaskValidationContext (com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext)20 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)19 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)19 ArrayList (java.util.ArrayList)19 ExportMask (com.emc.storageos.db.client.model.ExportMask)17 URI (java.net.URI)15 Initiator (com.emc.storageos.db.client.model.Initiator)13 ExportOperationContext (com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext)13 ExportOperationContextOperation (com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext.ExportOperationContextOperation)10 HashSet (java.util.HashSet)9 ListIterator (java.util.ListIterator)8 BlockObject (com.emc.storageos.db.client.model.BlockObject)6 SmisException (com.emc.storageos.volumecontroller.impl.smis.SmisException)6 WBEMException (javax.wbem.WBEMException)6 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)5 NamedURI (com.emc.storageos.db.client.model.NamedURI)5 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)5 List (java.util.List)5 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)4 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)4