Search in sources :

Example 6 with ExportOperationContext

use of com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext in project coprhd-controller by CoprHD.

the class VNXeExportOperations method addVolumes.

@Override
public void addVolumes(StorageSystem storage, URI exportMaskUri, VolumeURIHLU[] volumeURIHLUs, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
    _logger.info("{} addVolume START...", storage.getSerialNumber());
    List<URI> mappedVolumes = new ArrayList<URI>();
    ExportMask exportMask = null;
    try {
        _logger.info("addVolumes: Export mask id: {}", exportMaskUri);
        _logger.info("addVolumes: volume-HLU pairs: {}", Joiner.on(',').join(volumeURIHLUs));
        if (initiatorList != null) {
            _logger.info("addVolumes: initiators impacted: {}", Joiner.on(',').join(initiatorList));
        }
        ExportOperationContext context = new VNXeExportOperationContext();
        taskCompleter.updateWorkflowStepContext(context);
        VNXeApiClient apiClient = getVnxeClient(storage);
        exportMask = _dbClient.queryObject(ExportMask.class, exportMaskUri);
        if (exportMask == null || exportMask.getInactive()) {
            throw new DeviceControllerException("Invalid ExportMask URI: " + exportMaskUri);
        }
        List<Initiator> initiators = ExportUtils.getExportMaskInitiators(exportMask, _dbClient);
        Collection<VNXeHostInitiator> vnxeInitiators = prepareInitiators(initiators).values();
        VNXeBase host = apiClient.prepareHostsForExport(vnxeInitiators);
        String opId = taskCompleter.getOpId();
        Set<String> processedCGs = new HashSet<String>();
        for (VolumeURIHLU volURIHLU : volumeURIHLUs) {
            URI volUri = volURIHLU.getVolumeURI();
            String hlu = volURIHLU.getHLU();
            _logger.info(String.format("hlu %s", hlu));
            BlockObject blockObject = BlockObject.fetch(_dbClient, volUri);
            VNXeExportResult result = null;
            Integer newhlu = -1;
            if (hlu != null && !hlu.isEmpty() && !hlu.equals(ExportGroup.LUN_UNASSIGNED_STR)) {
                newhlu = Integer.valueOf(hlu);
            }
            // COP-25254 this method could be called when create vplex volumes from snapshot. in this case
            // the volume passed in is an internal volume, representing the snapshot. we need to find the snapshot
            // with the same nativeGUID, then export the snapshot.
            BlockObject snapshot = findSnapshotByInternalVolume(blockObject);
            boolean isVplexVolumeFromSnap = false;
            URI vplexBackendVol = null;
            if (snapshot != null) {
                blockObject = snapshot;
                exportMask.addVolume(volUri, newhlu);
                isVplexVolumeFromSnap = true;
                vplexBackendVol = volUri;
                volUri = blockObject.getId();
            }
            String cgName = VNXeUtils.getBlockObjectCGName(blockObject, _dbClient);
            if (cgName != null && !processedCGs.contains(cgName)) {
                processedCGs.add(cgName);
                VNXeUtils.getCGLock(workflowService, storage, cgName, opId);
            }
            String nativeId = blockObject.getNativeId();
            if (URIUtil.isType(volUri, Volume.class)) {
                result = apiClient.exportLun(host, nativeId, newhlu);
                exportMask.addVolume(volUri, result.getHlu());
                if (result.isNewAccess()) {
                    mappedVolumes.add(volUri);
                }
            } else if (URIUtil.isType(volUri, BlockSnapshot.class)) {
                result = apiClient.exportSnap(host, nativeId, newhlu);
                exportMask.addVolume(volUri, result.getHlu());
                if (result.isNewAccess()) {
                    mappedVolumes.add(volUri);
                }
                String snapWWN = setSnapWWN(apiClient, blockObject, nativeId);
                if (isVplexVolumeFromSnap) {
                    Volume backendVol = _dbClient.queryObject(Volume.class, vplexBackendVol);
                    backendVol.setWWN(snapWWN);
                    _dbClient.updateObject(backendVol);
                }
            }
        }
        ExportOperationContext.insertContextOperation(taskCompleter, VNXeExportOperationContext.OPERATION_ADD_VOLUMES_TO_HOST_EXPORT, mappedVolumes);
        _dbClient.updateObject(exportMask);
        // Test mechanism to invoke a failure. No-op on production systems.
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_002);
        taskCompleter.ready(_dbClient);
    } catch (Exception e) {
        _logger.error("Add volumes error: ", e);
        ServiceError error = DeviceControllerErrors.vnxe.jobFailed("addVolume", e.getMessage());
        taskCompleter.error(_dbClient, error);
    }
    _logger.info("{} addVolumes 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) VNXeBase(com.emc.storageos.vnxe.models.VNXeBase) Initiator(com.emc.storageos.db.client.model.Initiator) VNXeHostInitiator(com.emc.storageos.vnxe.models.VNXeHostInitiator) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) 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) VNXeExportResult(com.emc.storageos.vnxe.models.VNXeExportResult) VNXeException(com.emc.storageos.vnxe.VNXeException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) Volume(com.emc.storageos.db.client.model.Volume) VolumeURIHLU(com.emc.storageos.volumecontroller.impl.VolumeURIHLU)

Example 7 with ExportOperationContext

use of com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext in project coprhd-controller by CoprHD.

the class VNXeExportOperations method removeVolumes.

@Override
public void removeVolumes(StorageSystem storage, URI exportMaskUri, List<URI> volumes, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
    _logger.info("{} removeVolumes: START...", storage.getSerialNumber());
    try {
        _logger.info("removeVolumes: Export mask id: {}", exportMaskUri);
        _logger.info("removeVolumes: volumes: {}", Joiner.on(',').join(volumes));
        if (initiatorList != null) {
            _logger.info("removeVolumes: impacted initiators: {}", Joiner.on(",").join(initiatorList));
        }
        boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId());
        if (isRollback) {
            List<URI> addedVolumes = new ArrayList<URI>();
            // 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 removeVolumes 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));
                    }
                }
            }
            volumes = addedVolumes;
            if (volumes == null || volumes.isEmpty()) {
                _logger.info("There was no context found for add volumes. So there is nothing to rollback.");
                taskCompleter.ready(_dbClient);
                return;
            }
        }
        if (volumes == null || volumes.isEmpty()) {
            taskCompleter.ready(_dbClient);
            _logger.warn("{} removeVolumes invoked with zero volumes, resulting in no-op....", storage.getSerialNumber());
            return;
        }
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskUri);
        if (exportMask == null || exportMask.getInactive()) {
            throw new DeviceControllerException("Invalid ExportMask URI: " + exportMaskUri);
        }
        List<Initiator> initiators = ExportUtils.getExportMaskInitiators(exportMask, _dbClient);
        VNXeApiClient apiClient = getVnxeClient(storage);
        String hostId = getHostIdFromInitiators(initiators, apiClient);
        if (hostId != null) {
            ExportMaskValidationContext ctx = new ExportMaskValidationContext();
            ctx.setStorage(storage);
            ctx.setExportMask(exportMask);
            ctx.setInitiators(initiatorList);
            // Allow exceptions to be thrown when not rolling back
            ctx.setAllowExceptions(!isRollback);
            AbstractVNXeValidator removeVolumesValidator = (AbstractVNXeValidator) validator.removeVolumes(ctx);
            removeVolumesValidator.setHostId(hostId);
            removeVolumesValidator.validate();
        }
        String opId = taskCompleter.getOpId();
        Set<String> processedCGs = new HashSet<String>();
        StringMap volsMap = exportMask.getVolumes();
        for (URI volUri : volumes) {
            if (hostId != null && volsMap != null && !volsMap.isEmpty() && volsMap.keySet().contains(volUri.toString())) {
                BlockObject blockObject = BlockObject.fetch(_dbClient, volUri);
                // COP-25254 this method could be called when delete vplex volume created from snapshot. in this case
                // the volume passed in is an internal volume, representing the snapshot. we need to find the snapshot
                // with the same nativeGUID, then unexport the snapshot.
                BlockObject snapshot = findSnapshotByInternalVolume(blockObject);
                if (snapshot != null) {
                    blockObject = snapshot;
                    exportMask.removeVolume(volUri);
                    volUri = blockObject.getId();
                }
                String cgName = VNXeUtils.getBlockObjectCGName(blockObject, _dbClient);
                if (cgName != null && !processedCGs.contains(cgName)) {
                    processedCGs.add(cgName);
                    VNXeUtils.getCGLock(workflowService, storage, cgName, opId);
                }
                String nativeId = blockObject.getNativeId();
                if (URIUtil.isType(volUri, Volume.class)) {
                    apiClient.unexportLun(hostId, nativeId);
                } else if (URIUtil.isType(volUri, BlockSnapshot.class)) {
                    apiClient.unexportSnap(hostId, nativeId);
                    setSnapWWN(apiClient, blockObject, nativeId);
                }
            }
            // update the exportMask object
            exportMask.removeVolume(volUri);
        }
        _dbClient.updateObject(exportMask);
        taskCompleter.ready(_dbClient);
    } catch (Exception e) {
        _logger.error("Unexpected error: removeVolumes failed.", e);
        ServiceError error = DeviceControllerErrors.vnxe.jobFailed("remove volumes failed", e.getMessage());
        taskCompleter.error(_dbClient, error);
    }
    _logger.info("{} removeVolumes END...", storage.getSerialNumber());
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) StringMap(com.emc.storageos.db.client.model.StringMap) VNXeApiClient(com.emc.storageos.vnxe.VNXeApiClient) ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) BlockSnapshot(com.emc.storageos.db.client.model.BlockSnapshot) ListIterator(java.util.ListIterator) URI(java.net.URI) 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) 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)

Example 8 with ExportOperationContext

use of com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext in project coprhd-controller by CoprHD.

the class VNXeExportOperations method addInitiators.

@Override
public void addInitiators(StorageSystem storage, URI exportMaskUri, List<URI> volumeURIs, List<Initiator> initiatorList, List<URI> targets, TaskCompleter taskCompleter) throws DeviceControllerException {
    _logger.info("{} addInitiator START...", storage.getSerialNumber());
    List<Initiator> createdInitiators = new ArrayList<Initiator>();
    ExportMask exportMask = null;
    try {
        ExportOperationContext context = new VNXeExportOperationContext();
        taskCompleter.updateWorkflowStepContext(context);
        exportMask = _dbClient.queryObject(ExportMask.class, exportMaskUri);
        if (exportMask == null || exportMask.getInactive()) {
            throw new DeviceControllerException("Invalid ExportMask URI: " + exportMaskUri);
        }
        VNXeApiClient apiClient = getVnxeClient(storage);
        List<Initiator> initiators = ExportUtils.getExportMaskInitiators(exportMask, _dbClient);
        // Finding existing host from the array
        Collection<VNXeHostInitiator> vnxeInitiators = prepareInitiators(initiators).values();
        String hostId = null;
        for (VNXeHostInitiator init : vnxeInitiators) {
            VNXeHostInitiator foundInit = apiClient.getInitiatorByWWN(init.getInitiatorId());
            if (foundInit != null) {
                VNXeBase host = foundInit.getParentHost();
                if (host != null) {
                    hostId = host.getId();
                    break;
                }
            }
        }
        if (hostId == null) {
            String msg = String.format("No existing host found in the array for the existing exportMask %s", exportMask.getMaskName());
            _logger.error(msg);
            ServiceError error = DeviceControllerErrors.vnxe.jobFailed("addiniator", msg);
            taskCompleter.error(_dbClient, error);
            return;
        }
        validateInitiators(_dbClient, initiatorList, apiClient, hostId);
        Map<Initiator, VNXeHostInitiator> initiatorMap = prepareInitiators(initiatorList);
        for (Entry<Initiator, VNXeHostInitiator> entry : initiatorMap.entrySet()) {
            VNXeHostInitiator newInit = entry.getValue();
            VNXeHostInitiator init = apiClient.getInitiatorByWWN(newInit.getInitiatorId());
            // COP-27752 - fresh deleted initiator may not be deleted completely
            int retry = 0;
            while (retry <= MAX_REMOVE_INITIATOR_RETRIES && init != null && init.getParentHost() == null) {
                try {
                    Thread.sleep(WAIT_FOR_RETRY);
                } catch (InterruptedException e1) {
                    Thread.currentThread().interrupt();
                }
                init = apiClient.getInitiatorByWWN(newInit.getInitiatorId());
            }
            if (init != null) {
                // found it
                VNXeBase host = init.getParentHost();
                if (host != null && host.getId().equals(hostId)) {
                    // do nothing. it is already in the array
                    _logger.info("The initiator exist in the host in the array");
                } else if (host == null) {
                    // initiator without parent host, add parent host
                    apiClient.setInitiatorHost(init.getId(), hostId);
                } else {
                    String msg = String.format("Initiator %s belongs to %s, but other initiator belongs to %s. Please move initiator to the correct host", init.getInitiatorId(), host.getId(), hostId);
                    _logger.error(msg);
                    if (!createdInitiators.isEmpty()) {
                        for (Initiator initiator : createdInitiators) {
                            exportMask.getInitiators().add(initiator.getId().toString());
                        }
                        _dbClient.updateObject(exportMask);
                        ExportOperationContext.insertContextOperation(taskCompleter, VNXeExportOperationContext.OPERATION_ADD_INITIATORS_TO_HOST, createdInitiators);
                    }
                    ServiceError error = DeviceControllerErrors.vnxe.jobFailed("addiniator", msg);
                    taskCompleter.error(_dbClient, error);
                    return;
                }
            } else {
                apiClient.createInitiator(newInit, hostId);
                createdInitiators.add(entry.getKey());
            }
        }
        for (Initiator initiator : initiatorList) {
            exportMask.getInitiators().add(initiator.getId().toString());
        }
        _dbClient.updateObject(exportMask);
        ExportOperationContext.insertContextOperation(taskCompleter, VNXeExportOperationContext.OPERATION_ADD_INITIATORS_TO_HOST, createdInitiators);
        // Test mechanism to invoke a failure. No-op on production systems.
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_003);
        taskCompleter.ready(_dbClient);
    } catch (Exception e) {
        _logger.error("Add initiators error: ", e);
        ServiceError error = DeviceControllerErrors.vnxe.jobFailed("addInitiator", e.getMessage());
        taskCompleter.error(_dbClient, error);
    }
}
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) VNXeHostInitiator(com.emc.storageos.vnxe.models.VNXeHostInitiator) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint) ContainmentConstraint(com.emc.storageos.db.client.constraint.ContainmentConstraint) VNXeException(com.emc.storageos.vnxe.VNXeException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) VNXeBase(com.emc.storageos.vnxe.models.VNXeBase) Initiator(com.emc.storageos.db.client.model.Initiator) VNXeHostInitiator(com.emc.storageos.vnxe.models.VNXeHostInitiator) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException)

Example 9 with ExportOperationContext

use of com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext in project coprhd-controller by CoprHD.

the class VmaxExportOperations method removeInitiators.

@Override
public void removeInitiators(StorageSystem storage, URI exportMaskURI, List<URI> volumeURIList, List<Initiator> initiatorList, List<URI> targetURIList, TaskCompleter taskCompleter) throws DeviceControllerException {
    _log.info("{} removeInitiators START...", storage == null ? null : storage.getSerialNumber());
    String clusterName = getClusterNameFromInitiators(initiatorList);
    if (clusterName == null) {
        final String logMsg = "All initiators should belong to the same cluster or not have a cluster name at all";
        _log.error(String.format("removeInitiator failed - maskName: %s", exportMaskURI.toString()), logMsg);
        String opName = ResourceOperationTypeEnum.DELETE_EXPORT_INITIATOR.getName();
        ServiceError serviceError = DeviceControllerException.errors.jobFailedOp(opName);
        taskCompleter.error(_dbClient, serviceError);
        return;
    } else {
        CloseableIterator<CIMInstance> cigInstances = null;
        try {
            _log.info("removeInitiators: Export mask id: {}", exportMaskURI);
            if (volumeURIList != null) {
                _log.info("removeInitiators: volumes : {}", Joiner.on(',').join(volumeURIList));
            }
            _log.info("removeInitiators: initiators : {}", Joiner.on(',').join(initiatorList));
            if (targetURIList != null) {
                _log.info("removeInitiators: targets : {}", Joiner.on(',').join(targetURIList));
            }
            boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId());
            ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
            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);
            validator.removeInitiators(ctx).validate();
            if (isRollback) {
                // Get the context from the task completer as this is a rollback.
                ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
                exportMaskRollback(storage, context, taskCompleter);
            } else {
                CIMArgument[] inArgs;
                CIMArgument[] outArgs;
                _log.info("Removing initiators ...");
                // Create a mapping of the InitiatorPort String to Initiator.
                Map<String, Initiator> nameToInitiator = new HashMap<String, Initiator>();
                for (Initiator initiator : initiatorList) {
                    String normalizedName = Initiator.normalizePort(initiator.getInitiatorPort());
                    nameToInitiator.put(normalizedName, initiator);
                }
                // We're going to get a mapping of which InitiatorGroups the initiators belong.
                // With this mapping we can remove initiators from their associated IGs sequentially
                ListMultimap<CIMObjectPath, String> igToInitiators = ArrayListMultimap.create();
                mapInitiatorsToInitiatorGroups(igToInitiators, storage, initiatorList);
                for (CIMObjectPath igPath : igToInitiators.keySet()) {
                    List<String> initiatorPorts = igToInitiators.get(igPath);
                    List<Initiator> initiatorsForIG = new ArrayList<Initiator>();
                    // Using the mapping, create a list of Initiator objects
                    for (String port : initiatorPorts) {
                        Initiator initiator = nameToInitiator.get(port);
                        if (initiator != null) {
                            initiatorsForIG.add(initiator);
                        }
                    }
                    boolean removingAllPortsInIG = initiatorPorts.size() == initiatorsForIG.size();
                    if (removingAllPortsInIG) {
                        // We are apparently trying to remove all the initiators in an Initiator Group.
                        // This is a special condition. It is not a case of removing the initiators
                        // from an individual group, we will instead treat this as a removal of the
                        // IG from the cascade-IG (thereby preventing access to the host pointed to
                        // by this IG).
                        _log.info(String.format("Request to remove all the initiators from IG %s, so we will remove the IG from the cascaded-IG", igPath.toString()));
                        ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
                        CIMObjectPath cigInMVPath = null;
                        CIMInstance mvInstance = _helper.getSymmLunMaskingView(storage, mask);
                        cigInstances = _helper.getAssociatorInstances(storage, mvInstance.getObjectPath(), null, SmisConstants.SE_INITIATOR_MASKING_GROUP, null, null, SmisConstants.PS_ELEMENT_NAME);
                        if (cigInstances.hasNext()) {
                            cigInMVPath = cigInstances.next().getObjectPath();
                        }
                        // Find the cascaded initiator group that this belongs to and remove the IG from it.
                        // Note: we should not be in here if the IG was associated directly to the MV. If the
                        // IG were related to the MV, then the masking orchestrator should have generated
                        // a workflow to delete the MV.
                        cigInstances = _helper.getAssociatorInstances(storage, igPath, null, SmisConstants.SE_INITIATOR_MASKING_GROUP, null, null, SmisConstants.PS_ELEMENT_NAME);
                        while (cigInstances.hasNext()) {
                            CIMObjectPath cigPath = cigInstances.next().getObjectPath();
                            if (!cigPath.equals(cigInMVPath)) {
                                // to remove the initiators from.
                                continue;
                            }
                            _log.info(String.format("Removing IG %s from CIG %s", igPath.toString(), cigPath.toString()));
                            inArgs = _helper.getRemoveIGFromCIG(igPath, cigPath);
                            outArgs = new CIMArgument[5];
                            _helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, null);
                            // Determine if the IG contains all initiators that were added by user/ViPR, and if
                            // the IG is no longer referenced by masking views or parent IGs. If so, it can be
                            // removed.
                            boolean removeIG = true;
                            for (Initiator initiator : initiatorsForIG) {
                                if (!mask.hasUserInitiator(initiator.getId())) {
                                    removeIG = false;
                                }
                            }
                            if (removeIG) {
                                List<CIMObjectPath> igList = new ArrayList<>();
                                igList.add(igPath);
                                this.checkIGsAndDeleteIfUnassociated(storage, igList);
                            }
                        }
                    } else {
                        inArgs = _helper.getRemoveInitiatorsFromMaskingGroupInputArguments(storage, igPath, initiatorsForIG);
                        outArgs = new CIMArgument[5];
                        _helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, null);
                    }
                }
                if (targetURIList != null && !targetURIList.isEmpty()) {
                    _log.info("Removing targets...");
                    URI pgURI = exportMask.getPortGroup();
                    if (!NullColumnValueGetter.isNullURI(pgURI)) {
                        StoragePortGroup portGroup = _dbClient.queryObject(StoragePortGroup.class, pgURI);
                        if (!portGroup.getMutable()) {
                            _log.info(String.format("The port group %s is immutable, done", portGroup.getNativeGuid()));
                            taskCompleter.ready(_dbClient);
                            return;
                        }
                    }
                    CIMInstance portGroupInstance = _helper.getPortGroupInstance(storage, exportMask.getMaskName());
                    if (null == portGroupInstance) {
                        String errMsg = String.format("removeInitiators failed - maskName %s : Port group not found ", exportMask.getMaskName());
                        ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(errMsg, null);
                        taskCompleter.error(_dbClient, serviceError);
                        return;
                    }
                    String pgGroupName = (String) portGroupInstance.getPropertyValue(SmisConstants.CP_ELEMENT_NAME);
                    // Get the current ports off of the storage group; only add the ones that aren't there already.
                    WBEMClient client = _helper.getConnection(storage).getCimClient();
                    List<String> storagePorts = _helper.getStoragePortsFromLunMaskingInstance(client, portGroupInstance);
                    Set<URI> storagePortURIs = new HashSet<>();
                    storagePortURIs.addAll(transform(ExportUtils.storagePortNamesToURIs(_dbClient, storagePorts), CommonTransformerFunctions.FCTN_STRING_TO_URI));
                    Set<URI> portsToRemove = intersection(newHashSet(targetURIList), storagePortURIs);
                    boolean removingLast = portsToRemove.size() == storagePortURIs.size();
                    if (!portsToRemove.isEmpty() && !removingLast) {
                        inArgs = _helper.getRemoveTargetPortsFromMaskingGroupInputArguments(storage, pgGroupName, Lists.newArrayList(portsToRemove));
                        outArgs = new CIMArgument[5];
                        _helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, null);
                    } else if (!removingLast) {
                        _log.info(String.format("Target ports already removed fom port group %s, likely by a previous operation.", pgGroupName));
                    } else {
                        // In this case, some programming, orchestration, or
                        // user-fiddling-with-things-outside-of-ViPR situation led us
                        // to this scenario.
                        // It's best to just print the ports and port group and leave it alone.
                        _log.error(String.format("Removing target ports would cause an empty port group %s, which is not allowed on VMAX.  Manual port removal may be required.", pgGroupName));
                    // This can lead to an inaccuracy in the ExportMask object, but may be recitified next time
                    // it's refreshed.
                    }
                }
            }
            _log.info(String.format("removeInitiators succeeded - maskName: %s", exportMaskURI.toString()));
            taskCompleter.ready(_dbClient);
        } catch (Exception e) {
            _log.error(String.format("removeInitiators failed - maskName: %s", exportMaskURI.toString()), e);
            String opName = ResourceOperationTypeEnum.DELETE_EXPORT_INITIATOR.getName();
            ServiceError serviceError = DeviceControllerException.errors.jobFailedOpMsg(opName, e.getMessage());
            taskCompleter.error(_dbClient, serviceError);
        } finally {
            if (cigInstances != null) {
                cigInstances.close();
            }
        }
    }
    _log.info("{} removeInitiators END...", storage == null ? null : storage.getSerialNumber());
}
Also used : StoragePortGroup(com.emc.storageos.db.client.model.StoragePortGroup) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) URI(java.net.URI) CIMInstance(javax.cim.CIMInstance) Initiator(com.emc.storageos.db.client.model.Initiator) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) WBEMClient(javax.wbem.client.WBEMClient) Sets.newHashSet(com.google.common.collect.Sets.newHashSet) HashSet(java.util.HashSet) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) CIMObjectPath(javax.cim.CIMObjectPath) SmisException(com.emc.storageos.volumecontroller.impl.smis.SmisException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) WBEMException(javax.wbem.WBEMException) ExportMaskValidationContext(com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext) CIMArgument(javax.cim.CIMArgument)

Example 10 with ExportOperationContext

use of com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext in project coprhd-controller by CoprHD.

the class VPlexDeviceController method storageViewAddInitiators.

/**
 * Workflow Step to add initiator to Storage View.
 * Note arguments (except stepId) must match storageViewAddInitiatorsMethod above.
 *
 * @param vplexURI
 *            -- URI of VPlex StorageSystem
 * @param exportURI
 *            -- ExportGroup URI
 * @param maskURI
 *            -- ExportMask URI. Optional.
 *            If non-null, only the indicated ExportMask will be processed.
 *            Otherwise, all ExportMasks will be processed.
 * @param initiatorURIs
 *            -- List of initiator URIs to be added.
 * @param targetURIs
 *            -- optional list of additional targets URIs (VPLEX FE ports) to be added.
 *            If non null, the targets (VPlex front end ports) indicated by the targetURIs will be added
 *            to the Storage View.
 * @param completer the ExportMaskAddInitiatorCompleter
 * @param stepId
 *            -- Workflow step id.
 * @throws WorkflowException
 */
public void storageViewAddInitiators(URI vplexURI, URI exportURI, URI maskURI, List<URI> initiatorURIs, List<URI> targetURIs, boolean sharedExportMask, ExportMaskAddInitiatorCompleter completer, String stepId) throws DeviceControllerException {
    try {
        WorkflowStepCompleter.stepExecuting(stepId);
        ExportOperationContext context = new VplexExportOperationContext();
        // Prime the context object
        completer.updateWorkflowStepContext(context);
        StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
        List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplexURI);
        for (ExportMask exportMask : exportMasks) {
            // If a specific ExportMask is to be processed, ignore any others.
            if (maskURI != null && !exportMask.getId().equals(maskURI)) {
                continue;
            }
            _log.info("Refreshing ExportMask {}", exportMask.getMaskName());
            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);
            // Determine host of ExportMask
            Set<URI> exportMaskHosts = VPlexUtil.getExportMaskHosts(_dbClient, exportMask, sharedExportMask);
            List<Initiator> inits = _dbClient.queryObject(Initiator.class, initiatorURIs);
            if (sharedExportMask) {
                for (Initiator initUri : inits) {
                    URI hostUri = VPlexUtil.getInitiatorHost(initUri);
                    if (null != hostUri) {
                        exportMaskHosts.add(hostUri);
                    }
                }
            }
            // Invoke artificial failure to simulate invalid storageview name on vplex
            InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_060);
            // Add new targets if specified
            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 add a port twice.
                    if (exportMask.getStoragePorts().contains(target.toString())) {
                        continue;
                    }
                    // Log any ports not listed as a target in the Export Masks zoningMap
                    Set<String> zoningMapTargets = BlockStorageScheduler.getTargetIdsFromAssignments(exportMask.getZoningMap());
                    if (!zoningMapTargets.contains(target.toString())) {
                        _log.info(String.format("Target %s not in zoning map", target));
                    }
                    // 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()) {
                    // Add the targets on the VPLEX
                    client.addTargetsToStorageView(exportMask.getMaskName(), targetPortInfos);
                    // Add the targets to the database.
                    for (URI target : targetsAddedToStorageView) {
                        exportMask.addTarget(target);
                    }
                }
            }
            List<PortInfo> initiatorPortInfos = new ArrayList<PortInfo>();
            List<String> initiatorPortWwns = new ArrayList<String>();
            Map<PortInfo, Initiator> portInfosToInitiatorMap = new HashMap<PortInfo, Initiator>();
            for (Initiator initiator : inits) {
                // Only add this initiator if it's for the same host as other initiators in mask
                if (!exportMaskHosts.contains(VPlexUtil.getInitiatorHost(initiator))) {
                    continue;
                }
                // Only add this initiator if it's not in the mask already after refresh
                if (exportMask.hasInitiator(initiator.getId().toString())) {
                    continue;
                }
                PortInfo portInfo = new PortInfo(initiator.getInitiatorPort().toUpperCase().replaceAll(":", ""), initiator.getInitiatorNode().toUpperCase().replaceAll(":", ""), initiator.getLabel(), getVPlexInitiatorType(initiator));
                initiatorPortInfos.add(portInfo);
                initiatorPortWwns.add(initiator.getInitiatorPort());
                portInfosToInitiatorMap.put(portInfo, initiator);
            }
            if (!initiatorPortInfos.isEmpty()) {
                String lockName = null;
                boolean lockAcquired = false;
                try {
                    StringSet portIds = exportMask.getStoragePorts();
                    StoragePort exportMaskPort = getDataObject(StoragePort.class, URI.create(portIds.iterator().next()), _dbClient);
                    String clusterId = ConnectivityUtil.getVplexClusterOfPort(exportMaskPort);
                    lockName = _vplexApiLockManager.getLockName(vplexURI, clusterId);
                    lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
                    if (!lockAcquired) {
                        throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplex.getLabel());
                    }
                    // Add the initiators to the VPLEX
                    client.addInitiatorsToStorageView(exportMask.getMaskName(), vplexClusterName, initiatorPortInfos);
                    ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_INITIATORS_TO_STORAGE_VIEW, initiatorURIs);
                } finally {
                    if (lockAcquired) {
                        _vplexApiLockManager.releaseLock(lockName);
                    }
                }
            }
        }
        InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_003);
        completer.ready(_dbClient);
    } catch (VPlexApiException vae) {
        _log.error("VPlexApiException adding initiator to Storage View: " + vae.getMessage(), vae);
        failStep(completer, stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception adding initiator to Storage View: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.ADD_STORAGE_VIEW_INITIATOR.getName();
        ServiceError serviceError = VPlexApiException.errors.storageViewAddInitiatorFailed(opName, ex);
        failStep(completer, stepId, serviceError);
    }
}
Also used : VPlexStorageViewInfo(com.emc.storageos.vplex.api.VPlexStorageViewInfo) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) PortInfo(com.emc.storageos.vplex.api.clientdata.PortInfo) Initiator(com.emc.storageos.db.client.model.Initiator) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) StringSet(com.emc.storageos.db.client.model.StringSet) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) StoragePort(com.emc.storageos.db.client.model.StoragePort) 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) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient)

Aggregations

ExportOperationContext (com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext)39 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)33 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)33 ExportMask (com.emc.storageos.db.client.model.ExportMask)29 ArrayList (java.util.ArrayList)28 URI (java.net.URI)24 Initiator (com.emc.storageos.db.client.model.Initiator)17 ExportOperationContextOperation (com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext.ExportOperationContextOperation)14 SmisException (com.emc.storageos.volumecontroller.impl.smis.SmisException)13 ExportMaskValidationContext (com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext)13 WBEMException (javax.wbem.WBEMException)13 HashSet (java.util.HashSet)12 ListIterator (java.util.ListIterator)10 BlockObject (com.emc.storageos.db.client.model.BlockObject)9 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)7 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)7 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)7 ControllerException (com.emc.storageos.volumecontroller.ControllerException)7 VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)7 WorkflowException (com.emc.storageos.workflow.WorkflowException)7