use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.RollbackExportGroupCreateCompleter in project coprhd-controller by CoprHD.
the class MaskingWorkflowEntryPoints method rollbackExportGroupCreate.
/**
* Rollback entry point. This is a wrapper around the exportGroupDelete operation,
* which requires that we create a specific completer using the token that's passed
* in. This token is generated by the rollback processing.
*
* @param storageURI
* [in] - StorageSystem URI
* @param exportGroupURI
* [in] - ExportGroup URI
* @param exportMaskURI
* [in] - ExportMask URI
* @param contextKey
* [in] - context token
* @param token
* [in] - String token generated by the rollback processing
*
* @throws ControllerException
*/
public void rollbackExportGroupCreate(URI storageURI, URI exportGroupURI, URI exportMaskURI, String contextKey, String token) throws ControllerException {
ExportTaskCompleter taskCompleter = new RollbackExportGroupCreateCompleter(exportGroupURI, exportMaskURI, token);
// Take the context of the step in flight and feed it into our current step
// in order to only perform rollback of operations we successfully performed.
ExportOperationContext context = null;
try {
context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(contextKey);
WorkflowService.getInstance().storeStepData(token, context);
} catch (ClassCastException e) {
_log.info("Step {} has stored step data other than ExportOperationContext. Exception: {}", token, e);
}
_log.info("Rolling back operations: " + context);
doExportGroupDelete(storageURI, exportGroupURI, exportMaskURI, null, null, taskCompleter, token);
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.RollbackExportGroupCreateCompleter in project coprhd-controller by CoprHD.
the class VmaxExportOperations method deleteExportMask.
@Override
public void deleteExportMask(StorageSystem storage, URI exportMaskURI, List<URI> volumeURIList, List<URI> targetURIList, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} deleteExportMask START...", storage.getSerialNumber());
try {
_log.info("Export mask id: {}", exportMaskURI);
if (volumeURIList != null) {
_log.info("deleteExportMask: volumes: {}", Joiner.on(',').join(volumeURIList));
}
if (targetURIList != null) {
_log.info("deleteExportMask: assignments: {}", Joiner.on(',').join(targetURIList));
}
if (initiatorList != null) {
_log.info("deleteExportMask: initiators: {}", Joiner.on(',').join(initiatorList));
}
boolean isVmax3 = storage.checkIfVmax3();
WBEMClient client = _helper.getConnection(storage).getCimClient();
String maskingViewName = _helper.getExportMaskName(exportMaskURI);
// Always get the Storage Group from masking View, rather than depending on the name to find out SG.
String groupName = _helper.getStorageGroupForGivenMaskingView(maskingViewName, storage);
/*
* The idea is to remove orphaned child Groups, after deleting masking view. We're getting
* the list of childGroups here because once we call deleteMaskingView, the parent group
* will be automatically deleted.
*
* Run Associator Names to get details of child Storage Groups ,and group them based on
* Fast Policy.
*/
Map<StorageGroupPolicyLimitsParam, List<String>> childGroupsByFast = new HashMap<StorageGroupPolicyLimitsParam, List<String>>();
// if SGs are already removed from masking view manually, then skip this part
if (null != groupName) {
childGroupsByFast = _helper.groupStorageGroupsByAssociation(storage, groupName);
} else {
_log.info("Masking View {} doesn't have any SGs associated, probably removed manually from Array", maskingViewName);
if (isVmax3) {
// If we did not find the storage group associated with the masking view it could be
// the case that were were unexporting volumes and successfully deleted the masking
// but failed at some point thereafter, and now the operation is being retried. If
// that is the case, then for VMAX3 we want to make sure that none of the volumes being
// unexported are still in non parking storage groups. If we find such volume we remove
// them and add them to the parking storage group.
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
if (exportMask == null) {
// If we can't find the mask, there is really no cleanup we can do.
_log.warn("ExportMask {} no longer exists", exportMaskURI);
taskCompleter.ready(_dbClient);
return;
}
// See if any of the mask's volumes are still in a non-parking storage group. Map the
// volumes by group name.
List<URI> volumeURIs = ExportMaskUtils.getVolumeURIs(exportMask);
Map<String, List<URI>> volumesInNonParkingStorageGroup = _helper.getVolumesInNonParkingStorageGroup(storage, volumeURIs);
if (!volumesInNonParkingStorageGroup.isEmpty()) {
Map<String, Set<String>> volumeDeviceIdsMap = new HashMap<>();
for (Entry<String, List<URI>> storageGroupEntry : volumesInNonParkingStorageGroup.entrySet()) {
String storageGroupName = storageGroupEntry.getKey();
List<URI> storageGroupVolumeURIs = storageGroupEntry.getValue();
// then just skip the volume, we cannot clean it up as we may impact other exports.
if (_helper.findStorageGroupsAssociatedWithMultipleParents(storage, storageGroupName) || _helper.findStorageGroupsAssociatedWithOtherMaskingViews(storage, storageGroupName)) {
_log.info("Storage group {} is associated with multiple paranets or other masking views", storageGroupName);
continue;
}
// Otherwise, remove the volumes from the storage group.
_log.info("Removing volumes {} from non parking storage group {}", storageGroupVolumeURIs, storageGroupName);
_helper.removeVolumesFromStorageGroup(storage, storageGroupName, storageGroupVolumeURIs, true);
// parking storage group.
for (URI storageGroupVolumeURI : storageGroupVolumeURIs) {
Volume storageGroupVolume = _dbClient.queryObject(Volume.class, storageGroupVolumeURI);
if (storageGroupVolume != null) {
String policyName = ControllerUtils.getAutoTieringPolicyName(storageGroupVolumeURI, _dbClient);
String policyKey = _helper.getVMAX3FastSettingForVolume(storageGroupVolumeURI, policyName);
if (volumeDeviceIdsMap.containsKey(policyKey)) {
volumeDeviceIdsMap.get(policyKey).add(storageGroupVolume.getNativeId());
} else {
Set<String> volumeDeviceIds = new HashSet<>();
volumeDeviceIds.add(storageGroupVolume.getNativeId());
volumeDeviceIdsMap.put(policyKey, volumeDeviceIds);
}
}
}
}
// Finally for each parking storage group policy, add the volumes associated parking storage group.
for (Entry<String, Set<String>> volumeDeviceIdsMapEntry : volumeDeviceIdsMap.entrySet()) {
_log.info("Adding volumes {} on system {} to parking storage group for policy {}", volumeDeviceIdsMapEntry.getValue(), storage.getNativeGuid(), volumeDeviceIdsMapEntry.getKey());
addVolumesToParkingStorageGroup(storage, volumeDeviceIdsMapEntry.getKey(), volumeDeviceIdsMapEntry.getValue());
}
}
}
taskCompleter.ready(_dbClient);
return;
}
/*
* If a maskingView was created by other instance, can not delete it here during roll back. Hence,
* set task as done.
*/
if (taskCompleter instanceof RollbackExportGroupCreateCompleter) {
/*
* The purpose of rollback is to delete the masking view created by this very ViPR instance as
* part of this workflow, and it should not delete masking view created externally or another ViPR
*/
// Get the context from the task completer, in case this is a rollback.
ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
if (context != null) {
exportMaskRollback(storage, context, taskCompleter);
}
} else {
ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
List<URI> volumeURIs = ExportMaskUtils.getVolumeURIs(exportMask);
ExportMaskValidationContext ctx = new ExportMaskValidationContext();
ctx.setStorage(storage);
ctx.setExportMask(exportMask);
ctx.setBlockObjects(volumeURIList, _dbClient);
ctx.setInitiators(initiatorList);
ctx.setAllowExceptions(context == null);
validator.exportMaskDelete(ctx).validate();
if (!deleteMaskingView(storage, exportMaskURI, childGroupsByFast, taskCompleter)) {
// deleteMaskingView call. Simply return from here.
return;
}
for (Map.Entry<StorageGroupPolicyLimitsParam, List<String>> entry : childGroupsByFast.entrySet()) {
_log.info(String.format("Mask %s FAST Policy %s associated with %d Storage Group(s)", maskingViewName, entry.getKey(), entry.getValue().size()));
}
if (groupName != null) {
_log.info("storage group name : {}", groupName);
// delete the CSG explicitly (CTRL-9236)
CIMObjectPath storageGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
// check if the storage group is shared before delete it
if (_helper.checkExists(storage, storageGroupPath, false, false) != null && _helper.checkMaskingGroupShared(storage, storageGroupPath, exportMask.getMaskName())) {
// if the storage group is shared, don't delete the storage group
_log.info("The Storage group {} is shared, so it will not be deleted", groupName);
taskCompleter.ready(_dbClient);
return;
}
if (_helper.isCascadedSG(storage, storageGroupPath)) {
_helper.deleteMaskingGroup(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
}
/**
* After successful deletion of masking view, try to remove the child Storage Groups ,which were
* part of cascaded
* Parent Group. If Fast Policy is not enabled, then those child groups can be removed.
* If Fast enabled, then try to find if this child Storage Group is associated with more than 1
* Parent Cascaded
* Group, if yes, then we cannot delete the child Storage Group.
*/
for (Entry<StorageGroupPolicyLimitsParam, List<String>> childGroupByFastEntry : childGroupsByFast.entrySet()) {
for (String childGroupName : childGroupByFastEntry.getValue()) {
_log.info("Processing Group {} deletion with Fast Policy {}", childGroupName, childGroupByFastEntry.getKey());
CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, childGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
if (!_helper.isFastPolicy(childGroupByFastEntry.getKey().getAutoTierPolicyName())) {
/**
* Remove the volumes from any phantom storage group (CTRL-8217).
*
* Volumes part of Phantom Storage Group will be in Non-CSG Non-FAST Storage Group
*/
if (!_helper.isCascadedSG(storage, maskingGroupPath)) {
// Get volumes which are part of this Storage Group
List<URI> volumesInSG = _helper.findVolumesInStorageGroup(storage, childGroupName, volumeURIs);
// 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 : volumesInSG) {
forceFlag = ExportUtils.useEMCForceFlag(_dbClient, volURI);
if (forceFlag) {
break;
}
}
removeVolumesFromPhantomStorageGroup(storage, client, exportMaskURI, volumesInSG, childGroupName, forceFlag);
}
// Delete the Storage Group
_helper.deleteMaskingGroup(storage, childGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
} else if (!_helper.findStorageGroupsAssociatedWithMultipleParents(storage, childGroupName) && !_helper.findStorageGroupsAssociatedWithOtherMaskingViews(storage, childGroupName)) {
// volumeDeviceIds and policyName are required in case of VMAX3 to add volumes back
// to parking to storage group.
Set<String> volumeDeviceIds = new HashSet<String>();
String policyName = childGroupByFastEntry.getKey().getAutoTierPolicyName();
if (isVmax3) {
volumeDeviceIds = _helper.getVolumeDeviceIdsFromStorageGroup(storage, childGroupName);
}
// holds the group, if yes, then we should not delete this group
if (!isVmax3) {
_log.debug("Removing Storage Group {} from Fast Policy {}", childGroupName, childGroupByFastEntry.getKey());
_helper.removeVolumeGroupFromPolicyAndLimitsAssociation(client, storage, maskingGroupPath);
}
_log.debug("Deleting Storage Group {}", childGroupName);
_helper.deleteMaskingGroup(storage, childGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
if (isVmax3 && !volumeDeviceIds.isEmpty()) {
// We need to add volumes back to appropriate parking storage group.
addVolumesToParkingStorageGroup(storage, policyName, volumeDeviceIds);
}
} else {
_log.info("Storage Group {} is either having more than one parent Storage Group or its part of another existing masking view", childGroupName);
// set Host IO Limits on SG which we reseted before deleting MV
if (childGroupByFastEntry.getKey().isHostIOLimitIOPsSet()) {
_helper.updateHostIOLimitIOPs(client, maskingGroupPath, childGroupByFastEntry.getKey().getHostIOLimitIOPs());
}
if (childGroupByFastEntry.getKey().isHostIOLimitBandwidthSet()) {
_helper.updateHostIOLimitBandwidth(client, maskingGroupPath, childGroupByFastEntry.getKey().getHostIOLimitBandwidth());
}
}
}
}
}
}
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error(String.format("deleteExportMask failed - maskName: %s", exportMaskURI.toString()), e);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
taskCompleter.error(_dbClient, serviceError);
}
_log.info("{} deleteExportMask END...", storage.getSerialNumber());
}
Aggregations