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));
}
}
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();
}
}
}
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());
}
Aggregations