Search in sources :

Example 1 with SmisMaskingViewRemoveVolumeJob

use of com.emc.storageos.volumecontroller.impl.smis.job.SmisMaskingViewRemoveVolumeJob in project coprhd-controller by CoprHD.

the class VmaxExportOperations method removePhantomStorageGroup.

/**
 * Removes the volumes from phantom SG.
 * This is used internally for operation - change volume's policy by moving them from one vPool to another.
 * Request: to change FAST volumes in phantom SG to non-FAST volumes
 */
private void removePhantomStorageGroup(StorageSystem storage, WBEMClient client, URI exportMaskURI, String phantomSGName, CIMObjectPath phantomSGPath, List<URI> volumesToRemove, boolean forceFlag) throws Exception {
    /**
     * Though the volumes are associated with other non-fast, non-cascading masking views,
     * we can remove volumes from phantom SG as we are removing its Policy.
     */
    if (!volumesToRemove.isEmpty()) {
        _log.info(String.format("Going to remove volumes %s from phantom storage group %s", Joiner.on("\t").join(volumesToRemove), phantomSGName));
        /**
         * remove FAST policy associated with SG if change is requested for all volumes in that SG
         */
        if (isGivenVolumeListSameAsInStorageGroup(storage, phantomSGPath, volumesToRemove)) {
            _log.info("Storage Group has no more than {} volumes", volumesToRemove.size());
            _log.info("Storage Group {} will be disassociated from FAST because group can not be deleted if associated with FAST", phantomSGName);
            _helper.removeVolumeGroupFromPolicyAndLimitsAssociation(client, storage, phantomSGPath);
        }
        // Create a relatively empty completer associated with the export mask. We don't have the export group
        // at this level, so there's nothing decent to attach the completer to anyway.
        String task = UUID.randomUUID().toString();
        ExportMaskVolumeToStorageGroupCompleter completer = new ExportMaskVolumeToStorageGroupCompleter(null, exportMaskURI, task);
        List<CIMObjectPath> volumePaths = new ArrayList<CIMObjectPath>();
        // Remove the volumes from the phantom storage group
        CIMArgument[] inArgs = _helper.getRemoveVolumesFromMaskingGroupInputArguments(storage, phantomSGName, volumesToRemove, forceFlag);
        CIMArgument[] outArgs = new CIMArgument[5];
        _helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, new SmisMaskingViewRemoveVolumeJob(null, storage.getId(), volumePaths, null, phantomSGName, _cimPath, completer));
    }
}
Also used : SmisMaskingViewRemoveVolumeJob(com.emc.storageos.volumecontroller.impl.smis.job.SmisMaskingViewRemoveVolumeJob) ExportMaskVolumeToStorageGroupCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter) CIMObjectPath(javax.cim.CIMObjectPath) ArrayList(java.util.ArrayList) CIMArgument(javax.cim.CIMArgument)

Example 2 with SmisMaskingViewRemoveVolumeJob

use of com.emc.storageos.volumecontroller.impl.smis.job.SmisMaskingViewRemoveVolumeJob in project coprhd-controller by CoprHD.

the class VmaxExportOperations method removeVolumesFromPhantomStorageGroup.

/**
 * Removes the volumes from any phantom storage group.
 *
 * Determine if the volumes are associated with any phantom storage groups.
 * If so, we need to remove volumes from those storage groups and potentially remove them.
 */
private void removeVolumesFromPhantomStorageGroup(StorageSystem storage, WBEMClient client, URI exportMaskURI, List<URI> volumeURIList, String childGroupName, boolean forceFlag) throws Exception {
    CloseableIterator<CIMObjectPath> volumePathItr = null;
    try {
        Map<StorageGroupPolicyLimitsParam, List<URI>> policyVolumeMap = _helper.groupVolumesBasedOnFastPolicy(storage, volumeURIList);
        for (StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam : policyVolumeMap.keySet()) {
            if (!_helper.isFastPolicy(storageGroupPolicyLimitsParam.getAutoTierPolicyName())) {
                continue;
            }
            _log.info("Checking if volumes are associated with phantom storage groups with policy name: " + storageGroupPolicyLimitsParam);
            // See if there's a phantom group with this policy
            List<String> storageGroupNames = _helper.findPhantomStorageGroupAssociatedWithFastPolicy(storage, storageGroupPolicyLimitsParam);
            // We found a phantom storage group
            if (storageGroupNames != null) {
                for (String storageGroupName : storageGroupNames) {
                    List<URI> volumesToRemove = new ArrayList<URI>();
                    List<Volume> volumes = _dbClient.queryObject(Volume.class, policyVolumeMap.get(storageGroupPolicyLimitsParam));
                    // Get the volumes associated with this storage group. Match up with our volumes.
                    volumePathItr = _helper.getAssociatorNames(storage, _cimPath.getStorageGroupObjectPath(storageGroupName, storage), null, SmisConstants.CIM_STORAGE_VOLUME, null, null);
                    while (volumePathItr.hasNext()) {
                        CIMObjectPath volumePath = volumePathItr.next();
                        for (Volume volume : volumes) {
                            if (volume.getNativeGuid().equalsIgnoreCase(_helper.getVolumeNativeGuid(volumePath))) {
                                _log.info("Found volume " + volume.getLabel() + " is in phantom storage group " + storageGroupName);
                                volumesToRemove.add(volume.getId());
                            }
                        }
                    }
                    // Check to see if the volumes are associated with other non-fast, non-cascading masking views.
                    // If so, we should not remove that volume from the phantom storage group because another view
                    // is relying on
                    // it being there.
                    List<URI> inMoreViewsVolumes = new ArrayList<URI>();
                    for (URI volumeToRemove : volumesToRemove) {
                        if (_helper.isPhantomVolumeInMultipleMaskingViews(storage, volumeToRemove, childGroupName)) {
                            Volume volume = _dbClient.queryObject(Volume.class, volumeToRemove);
                            _log.info("Volume " + volume.getLabel() + " is in other masking views, so we will not remove it from storage group " + storageGroupName);
                            inMoreViewsVolumes.add(volume.getId());
                        }
                    }
                    volumesToRemove.removeAll(inMoreViewsVolumes);
                    // from the phantom storage group.
                    if (!volumesToRemove.isEmpty()) {
                        _log.info(String.format("Going to remove volumes %s from phantom storage group %s", Joiner.on("\t").join(volumesToRemove), storageGroupName));
                        Map<String, List<URI>> phantomGroupVolumeMap = _helper.groupVolumesBasedOnExistingGroups(storage, storageGroupName, volumesToRemove);
                        if (phantomGroupVolumeMap != null && phantomGroupVolumeMap.get(storageGroupName) != null && phantomGroupVolumeMap.get(storageGroupName).size() == volumesToRemove.size() && !_helper.isStorageGroupSizeGreaterThanGivenVolumes(storageGroupName, storage, volumesToRemove.size())) {
                            _log.info("Storage Group has no more than {} volumes", volumesToRemove.size());
                            URI blockURI = volumesToRemove.get(0);
                            BlockObject blockObj = BlockObject.fetch(_dbClient, blockURI);
                            CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, storageGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
                            String foundPolicyName = ControllerUtils.getAutoTieringPolicyName(blockObj.getId(), _dbClient);
                            if (_helper.isFastPolicy(foundPolicyName) && storageGroupPolicyLimitsParam.getAutoTierPolicyName().equalsIgnoreCase(foundPolicyName)) {
                                _log.info("Storage Group {} contains only 1 volume, so this group will be disassociated from FAST because group can not be deleted if associated with FAST", storageGroupName);
                                _helper.removeVolumeGroupFromPolicyAndLimitsAssociation(client, storage, maskingGroupPath);
                            }
                        }
                        // Create a relatively empty completer associated with the export mask. We don't have the
                        // export group
                        // at this level, so there's nothing decent to attach the completer to anyway.
                        String task = UUID.randomUUID().toString();
                        ExportMaskVolumeToStorageGroupCompleter completer = new ExportMaskVolumeToStorageGroupCompleter(null, exportMaskURI, task);
                        List<URI> volumesInSG = _helper.findVolumesInStorageGroup(storage, storageGroupName, volumesToRemove);
                        List<CIMObjectPath> volumePaths = new ArrayList<CIMObjectPath>();
                        // Remove the found volumes from the phantom storage group
                        if (volumesInSG != null && !volumesInSG.isEmpty()) {
                            CIMArgument[] inArgs = _helper.getRemoveVolumesFromMaskingGroupInputArguments(storage, storageGroupName, volumesInSG, forceFlag);
                            CIMArgument[] outArgs = new CIMArgument[5];
                            _helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, new SmisMaskingViewRemoveVolumeJob(null, storage.getId(), volumePaths, null, storageGroupName, _cimPath, completer));
                        }
                    }
                }
            }
        }
    } finally {
        if (volumePathItr != null) {
            volumePathItr.close();
        }
    }
}
Also used : SmisMaskingViewRemoveVolumeJob(com.emc.storageos.volumecontroller.impl.smis.job.SmisMaskingViewRemoveVolumeJob) CIMObjectPath(javax.cim.CIMObjectPath) ArrayList(java.util.ArrayList) URI(java.net.URI) ExportMaskVolumeToStorageGroupCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter) Volume(com.emc.storageos.db.client.model.Volume) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) StorageGroupPolicyLimitsParam(com.emc.storageos.volumecontroller.impl.StorageGroupPolicyLimitsParam) BlockObject(com.emc.storageos.db.client.model.BlockObject) CIMArgument(javax.cim.CIMArgument)

Example 3 with SmisMaskingViewRemoveVolumeJob

use of com.emc.storageos.volumecontroller.impl.smis.job.SmisMaskingViewRemoveVolumeJob in project coprhd-controller by CoprHD.

the class VmaxExportOperations method removeVolumes.

@Override
public void removeVolumes(StorageSystem storage, URI exportMaskURI, List<URI> volumeURIList, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
    _log.info("{} removeVolumes START...", storage.getSerialNumber());
    try {
        _log.info("removeVolumes: Export mask id: {}", exportMaskURI);
        _log.info("removeVolumes: volumes: {}", Joiner.on(',').join(volumeURIList));
        if (initiatorList != null) {
            _log.info("removeVolumes: impacted initiators: {}", Joiner.on(",").join(initiatorList));
        }
        List<? extends BlockObject> blockObjects = BlockObject.fetchAll(_dbClient, volumeURIList);
        ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
        boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId());
        ExportMaskValidationContext ctx = new ExportMaskValidationContext();
        ctx.setStorage(storage);
        ctx.setExportMask(exportMask);
        ctx.setBlockObjects(blockObjects);
        ctx.setInitiators(initiatorList);
        // Allow exceptions to be thrown when not rolling back
        ctx.setAllowExceptions(!isRollback);
        validator.removeVolumes(ctx).validate();
        boolean isVmax3 = storage.checkIfVmax3();
        WBEMClient client = _helper.getConnection(storage).getCimClient();
        if (isRollback) {
            // Get the context from the task completer for this rollback step. The stepId in this case
            // will correspond to the rollback step and not the primary execution step. We don't know
            // the rollback stepId until execution time, therefore there will be no step data in the
            // database corresponding to this stepId. The underlying call to loadStepData will take care
            // of finding the founding step (execution) step for this rollback stepId, from which the
            // step data can be found.
            ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
            exportMaskRollback(storage, context, taskCompleter);
            taskCompleter.ready(_dbClient);
            return;
        } else {
            String maskingViewName = _helper.getExportMaskName(exportMaskURI);
            // Always get the Storage Group from masking View, rather than depending on the name to find out SG.
            String parentGroupName = _helper.getStorageGroupForGivenMaskingView(maskingViewName, storage);
            // Storage Group does not exist, no operation on array side
            if (null == parentGroupName) {
                taskCompleter.ready(_dbClient);
                return;
            }
            Map<String, List<URI>> volumesByGroup = _helper.groupVolumesBasedOnExistingGroups(storage, parentGroupName, volumeURIList);
            _log.info("Group Volumes by Storage Group size : {}", volumesByGroup.size());
            if (volumesByGroup.size() == 0) {
                _log.info("Could not find any groups to which the volumes to remove belong.");
                taskCompleter.ready(_dbClient);
                return;
            }
            /**
             * For each child Group bucket, remove the volumes from those bucket
             */
            for (Entry<String, List<URI>> volumeByGroupEntry : volumesByGroup.entrySet()) {
                String childGroupName = volumeByGroupEntry.getKey();
                volumeURIList = volumeByGroupEntry.getValue();
                _log.info("Processing Group {} with volumes {}", childGroupName, Joiner.on("\t").join(volumeURIList));
                /**
                 * Empty child Storage Groups cannot be associated with Fast Policy.
                 * hence, verify if storage group size is > 1, if not, then remove the
                 * child group from Fast Policy, and then proceed with removing the volume from group
                 */
                if (volumesByGroup.get(childGroupName) != null && volumesByGroup.get(childGroupName).size() == volumeURIList.size() && !_helper.isStorageGroupSizeGreaterThanGivenVolumes(childGroupName, storage, volumeURIList.size())) {
                    _log.info("Storage Group has no more than {} volumes", volumeURIList.size());
                    URI blockURI = volumeURIList.get(0);
                    BlockObject blockObj = BlockObject.fetch(_dbClient, blockURI);
                    CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, childGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
                    String policyName = ControllerUtils.getAutoTieringPolicyName(blockObj.getId(), _dbClient);
                    if (!isVmax3 && !Constants.NONE.equalsIgnoreCase(policyName)) {
                        _log.info("Storage Group contains only 1 volume, hence this group will be disassociated from fast, as fast cannot be applied to empty group {}", childGroupName);
                        _helper.removeVolumeGroupFromPolicyAndLimitsAssociation(client, storage, maskingGroupPath);
                    }
                }
                Set<String> volumeDeviceIds = new HashSet<String>();
                // Flag to indicate whether or not we need to use the EMCForce flag on this operation.
                // We currently use this flag when dealing with RP Volumes as they are tagged for RP and the
                // operation on these volumes would fail otherwise.
                boolean forceFlag = false;
                for (URI volURI : volumeURIList) {
                    BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, volURI);
                    volumeDeviceIds.add(bo.getNativeId());
                    // The force flag only needs to be set once
                    if (!forceFlag) {
                        forceFlag = ExportUtils.useEMCForceFlag(_dbClient, volURI);
                    }
                }
                List<CIMObjectPath> volumePaths = new ArrayList<CIMObjectPath>();
                // Determine if the volumes are associated with any phantom storage groups.
                // If so, we need to remove volumes from those storage groups and potentially remove them.
                removeVolumesFromPhantomStorageGroup(storage, client, exportMaskURI, volumeURIList, childGroupName, forceFlag);
                // Create a relatively empty completer associated with the export mask. We don't have the export
                // group
                // at this level, so there's nothing decent to attach the completer to anyway.
                String task = UUID.randomUUID().toString();
                ExportMaskVolumeToStorageGroupCompleter completer = new ExportMaskVolumeToStorageGroupCompleter(null, exportMaskURI, task);
                List<URI> volumesInSG = _helper.findVolumesInStorageGroup(storage, childGroupName, volumeURIList);
                if (volumesInSG != null && !volumesInSG.isEmpty()) {
                    CIMArgument[] inArgs = _helper.getRemoveVolumesFromMaskingGroupInputArguments(storage, childGroupName, volumesInSG, forceFlag);
                    CIMArgument[] outArgs = new CIMArgument[5];
                    // If any of the volumes being removed are tied to RecoverPoint, we need to be aware that there
                    // might be some lag in terminating the remote copy session between VMAX and RP. So we need to
                    // catch a specific exception in this case and wait/retry.
                    boolean containsRPVolume = false;
                    // RecoverPoint related.
                    for (URI boUri : volumesInSG) {
                        if (URIUtil.isType(boUri, Volume.class)) {
                            Volume volume = _dbClient.queryObject(Volume.class, boUri);
                            if (volume != null && (volume.checkForRp() || RPHelper.isAssociatedToAnyRpVplexTypes(volume, _dbClient))) {
                                // Determined that the volume is RP related
                                containsRPVolume = true;
                                break;
                            }
                        }
                    }
                    // Initialize the retry/attempt variables
                    int attempt = 0;
                    int retries = 1;
                    if (containsRPVolume) {
                        // If we are dealing with an RP volume, we need to set the retry count appropriately
                        retries = MAX_RP_RETRIES;
                    }
                    while (attempt++ <= retries) {
                        try {
                            _helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, new SmisMaskingViewRemoveVolumeJob(null, storage.getId(), volumePaths, parentGroupName, childGroupName, _cimPath, completer));
                            // If the invoke succeeds without exception, break out of the retry loop.
                            break;
                        } catch (SmisException se) {
                            if (attempt != retries && containsRPVolume && se.getMessage().contains(COPY_SESSION_ERROR)) {
                                // There is some delay in terminating the remote copy session between VMAX and
                                // RecoverPoint
                                // so we need to wait and retry.
                                _log.warn(String.format("Encountered exception during attempt %s/%s to remove volumes %s from export group.  Waiting %s milliseconds before trying again.  Error: %s", attempt, MAX_RP_RETRIES, volumesInSG.toString(), RP_WAIT_FOR_RETRY, se.getMessage()));
                                try {
                                    Thread.sleep(RP_WAIT_FOR_RETRY);
                                } catch (InterruptedException e1) {
                                    Thread.currentThread().interrupt();
                                }
                            } else {
                                // This is not RP related so just re-throw the exception instead of retrying.
                                throw se;
                            }
                        }
                    }
                    if (isVmax3) {
                        // we need to add volumes to parking storage group
                        URI blockObjectURI = volumeURIList.get(0);
                        String policyName = _helper.getVMAX3FastSettingForVolume(blockObjectURI, null);
                        addVolumesToParkingStorageGroup(storage, policyName, volumeDeviceIds);
                    }
                } else {
                    completer.ready(_dbClient);
                }
            }
            taskCompleter.ready(_dbClient);
        }
    } catch (Exception e) {
        _log.error(String.format("removeVolumes failed - maskName: %s", exportMaskURI.toString()), e);
        ServiceError serviceError = null;
        if (null != e.getMessage() && e.getMessage().contains("FAST association cannot have an empty storage group")) {
            serviceError = DeviceControllerException.errors.concurrentRemoveFromSGCausesEmptySG(e);
        } else {
            serviceError = DeviceControllerException.errors.jobFailed(e);
        }
        taskCompleter.error(_dbClient, serviceError);
    }
    _log.info("{} removeVolumes END...", storage.getSerialNumber());
}
Also used : SmisMaskingViewRemoveVolumeJob(com.emc.storageos.volumecontroller.impl.smis.job.SmisMaskingViewRemoveVolumeJob) ArrayList(java.util.ArrayList) URI(java.net.URI) ExportMaskVolumeToStorageGroupCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter) ExportOperationContext(com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) WBEMClient(javax.wbem.client.WBEMClient) BlockObject(com.emc.storageos.db.client.model.BlockObject) Sets.newHashSet(com.google.common.collect.Sets.newHashSet) HashSet(java.util.HashSet) SmisException(com.emc.storageos.volumecontroller.impl.smis.SmisException) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) ExportMask(com.emc.storageos.db.client.model.ExportMask) CIMObjectPath(javax.cim.CIMObjectPath) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint) ContainmentConstraint(com.emc.storageos.db.client.constraint.ContainmentConstraint) 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) Volume(com.emc.storageos.db.client.model.Volume) CIMArgument(javax.cim.CIMArgument)

Aggregations

ExportMaskVolumeToStorageGroupCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter)3 SmisMaskingViewRemoveVolumeJob (com.emc.storageos.volumecontroller.impl.smis.job.SmisMaskingViewRemoveVolumeJob)3 ArrayList (java.util.ArrayList)3 CIMArgument (javax.cim.CIMArgument)3 CIMObjectPath (javax.cim.CIMObjectPath)3 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)2 BlockObject (com.emc.storageos.db.client.model.BlockObject)2 Volume (com.emc.storageos.db.client.model.Volume)2 URI (java.net.URI)2 List (java.util.List)2 AlternateIdConstraint (com.emc.storageos.db.client.constraint.AlternateIdConstraint)1 ContainmentConstraint (com.emc.storageos.db.client.constraint.ContainmentConstraint)1 ExportMask (com.emc.storageos.db.client.model.ExportMask)1 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)1 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)1 StorageGroupPolicyLimitsParam (com.emc.storageos.volumecontroller.impl.StorageGroupPolicyLimitsParam)1 SmisException (com.emc.storageos.volumecontroller.impl.smis.SmisException)1 ExportOperationContext (com.emc.storageos.volumecontroller.impl.utils.ExportOperationContext)1 ExportMaskValidationContext (com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext)1 Sets.newHashSet (com.google.common.collect.Sets.newHashSet)1