use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.
the class XtremIOExportOperations method runLunMapDeletionAlgorithm.
private void runLunMapDeletionAlgorithm(StorageSystem storage, ExportMask exportMask, List<URI> volumes, List<Initiator> initiators, TaskCompleter taskCompleter) throws DeviceControllerException {
// find LunMap associated with Volume
// Then find initiatorGroup associated with this lun map
// find initiators associated with IG, if the given list is of initiators is same, then run
// removeLunMap
XtremIOClient client = null;
// Default_IG;
try {
String hostName = null;
String clusterName = null;
client = XtremIOProvUtils.getXtremIOClient(dbClient, storage, xtremioRestClientFactory);
String xioClusterName = client.getClusterDetails(storage.getSerialNumber()).getName();
for (Initiator initiator : initiators) {
if (null != initiator.getHostName()) {
// initiators already grouped by Host
hostName = initiator.getHostName();
clusterName = initiator.getClusterName();
break;
}
}
ArrayListMultimap<String, Initiator> groupInitiatorsByIG = XtremIOProvUtils.mapInitiatorToInitiatorGroup(storage.getSerialNumber(), initiators, null, xioClusterName, client);
ExportMaskValidationContext ctx = new ExportMaskValidationContext();
ctx.setStorage(storage);
ctx.setExportMask(exportMask);
ctx.setInitiators(initiators);
ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId()));
XtremIOExportMaskInitiatorsValidator initiatorsValidator = (XtremIOExportMaskInitiatorsValidator) validator.removeVolumes(ctx);
initiatorsValidator.setInitiatorToIGMap(groupInitiatorsByIG);
initiatorsValidator.validate();
Set<String> igNames = groupInitiatorsByIG.keySet();
List<String> failedVolumes = new ArrayList<String>();
for (URI volumeUri : volumes) {
BlockObject blockObj = BlockObject.fetch(dbClient, volumeUri);
_log.info("Block Obj {} , wwn {}", blockObj.getId(), blockObj.getWWN());
XtremIOVolume xtremIOVolume = null;
if (URIUtil.isType(volumeUri, Volume.class)) {
xtremIOVolume = XtremIOProvUtils.isVolumeAvailableInArray(client, blockObj.getDeviceLabel(), xioClusterName);
// returned value is null, check the snapshots.
if (xtremIOVolume == null) {
xtremIOVolume = XtremIOProvUtils.isSnapAvailableInArray(client, blockObj.getDeviceLabel(), xioClusterName);
}
} else {
xtremIOVolume = XtremIOProvUtils.isSnapAvailableInArray(client, blockObj.getDeviceLabel(), xioClusterName);
}
if (null != xtremIOVolume) {
// I need lun map id and igName
// if iGName is available in the above group, then remove lunMap
_log.info("Volume Details {}", xtremIOVolume.toString());
_log.info("Volume lunMap details {}", xtremIOVolume.getLunMaps().toString());
Set<String> lunMaps = new HashSet<String>();
String volId = xtremIOVolume.getVolInfo().get(2);
if (xtremIOVolume.getLunMaps().isEmpty()) {
// handle scenarios where volumes gets unexported already
_log.info("Volume {} doesn't have any existing export available on Array, unexported already.", xtremIOVolume.toString());
exportMask.removeFromUserCreatedVolumes(blockObj);
exportMask.removeVolume(blockObj.getId());
continue;
}
for (List<Object> lunMapEntries : xtremIOVolume.getLunMaps()) {
@SuppressWarnings("unchecked") List<Object> igDetails = (List<Object>) lunMapEntries.get(0);
String igName = (String) igDetails.get(1);
// Ig details is actually transforming to A double by deofault, even though
// its modeled as List<String>
// hence this logic
Double IgIdDouble = (Double) igDetails.get(2);
String igId = String.valueOf(IgIdDouble.intValue());
_log.info("IG Name: {} Id: {} found in Lun Map", igName, igId);
if (!igNames.contains(igName)) {
_log.info("Volume is associated with IG {} which is not in the removal list requested, ignoring..", igName);
continue;
}
@SuppressWarnings("unchecked") List<Object> tgtGroupDetails = (List<Object>) lunMapEntries.get(1);
Double tgIdDouble = (Double) tgtGroupDetails.get(2);
String tgtid = String.valueOf(tgIdDouble.intValue());
String lunMapId = volId.concat(XtremIOConstants.UNDERSCORE).concat(igId).concat(XtremIOConstants.UNDERSCORE).concat(tgtid);
_log.info("LunMap Id {} Found associated with Volume {}", lunMapId, blockObj.getDeviceLabel());
lunMaps.add(lunMapId);
}
// there will be only one lun map always
for (String lunMap : lunMaps) {
try {
client.deleteLunMap(lunMap, xioClusterName);
} catch (Exception e) {
failedVolumes.add(volumeUri.toString().concat(XtremIOConstants.DASH).concat(e.getMessage()));
_log.warn("Deletion of Lun Map {} failed}", lunMap, e);
}
}
} else {
exportMask.removeFromUserCreatedVolumes(blockObj);
exportMask.removeVolume(blockObj.getId());
}
}
dbClient.updateObject(exportMask);
if (!failedVolumes.isEmpty()) {
String errMsg = "Export Operations failed for these volumes: ".concat(Joiner.on(", ").join(failedVolumes));
ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(errMsg, null);
taskCompleter.error(dbClient, serviceError);
return;
}
// Clean IGs if empty
deleteInitiatorGroup(groupInitiatorsByIG, client, xioClusterName);
// delete IG Folder as well if IGs are empty
deleteInitiatorGroupFolder(client, xioClusterName, clusterName, hostName, storage);
taskCompleter.ready(dbClient);
} catch (Exception e) {
_log.error(String.format("Export Operations failed - maskName: %s", exportMask.getId().toString()), e);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
taskCompleter.error(dbClient, serviceError);
}
}
use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.
the class HDSExportOperations 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());
List<HostStorageDomain> hsdToDeleteList = new ArrayList<HostStorageDomain>();
try {
log.info("deleteExportMask: 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));
}
// Get the context from the task completer, in case this is a rollback.
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);
AbstractHDSValidator deleteMaskValidator = (AbstractHDSValidator) validator.exportMaskDelete(ctx);
deleteMaskValidator.validate();
HDSApiClient hdsApiClient = hdsApiFactory.getClient(HDSUtils.getHDSServerManagementServerInfo(storage), storage.getSmisUserName(), storage.getSmisPassword());
HDSApiExportManager exportMgr = hdsApiClient.getHDSApiExportManager();
String systemObjectId = HDSUtils.getSystemObjectID(storage);
StringSetMap deviceDataMap = exportMask.getDeviceDataMap();
if (null != deviceDataMap && !deviceDataMap.isEmpty()) {
Set<String> hsdObjectIdList = deviceDataMap.keySet();
for (String hsdObjectIdFromDb : hsdObjectIdList) {
HostStorageDomain hsdObj = exportMgr.getHostStorageDomain(systemObjectId, hsdObjectIdFromDb);
if (null != hsdObj) {
hsdToDeleteList.add(hsdObj);
}
}
if (!hsdToDeleteList.isEmpty()) {
hdsApiClient.getHDSBatchApiExportManager().deleteBatchHostStorageDomains(systemObjectId, hsdToDeleteList, storage.getModel());
}
// By this time, we have removed all HSD's created in this mask.
taskCompleter.ready(dbClient);
} else {
String message = String.format("ExportMask %s does not have a configured HSD's, " + "indicating that this export may not have been created " + "successfully. Marking the delete operation ready.", exportMaskURI.toString());
log.info(message);
taskCompleter.ready(dbClient);
return;
}
} catch (Exception e) {
log.error("Unexpected error: deleteExportMask failed.", e);
ServiceError error = DeviceControllerErrors.hds.methodFailed("deleteExportMask", e.getMessage());
taskCompleter.error(dbClient, error);
}
log.info("{} deleteExportMask END...", storage.getSerialNumber());
}
use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext in project coprhd-controller by CoprHD.
the class VnxExportOperations method removeInitiators.
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.volumecontroller.impl.smis.ExportMaskOperations#removeInitiator(com.emc.storageos.db.client.
* model.StorageSystem, java.net.URI, java.util.List, java.util.List,
* com.emc.storageos.volumecontroller.TaskCompleter)
*
*/
@Override
public void removeInitiators(StorageSystem storage, URI exportMaskURI, List<URI> volumeURIList, List<Initiator> initiatorList, List<URI> targets, TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} removeInitiators START...", storage.getSerialNumber());
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 (targets != null) {
_log.info("removeInitiators: targets : {}", Joiner.on(',').join(targets));
}
boolean isRollback = WorkflowService.getInstance().isStepInRollbackState(taskCompleter.getOpId());
if (isRollback) {
_log.info("Handling removeInitiators as a result of rollback");
List<Initiator> addedInitiators = new ArrayList<Initiator>();
// Get the context from the task completer as this is a rollback.
ExportOperationContext context = (ExportOperationContext) WorkflowService.getInstance().loadStepData(taskCompleter.getOpId());
if (context != null && context.getOperations() != null) {
ListIterator li = context.getOperations().listIterator(context.getOperations().size());
while (li.hasPrevious()) {
ExportOperationContextOperation operation = (ExportOperationContextOperation) li.previous();
if (operation != null && VnxExportOperationContext.OPERATION_ADD_INITIATORS_TO_STORAGE_GROUP.equals(operation.getOperation())) {
addedInitiators = (List<Initiator>) operation.getArgs().get(0);
_log.info("Removing initiators {} as part of rollback", Joiner.on(',').join(addedInitiators));
}
}
}
initiatorList = addedInitiators;
if (initiatorList == null || initiatorList.isEmpty()) {
_log.info("There was no context found for add initiator. So there is nothing to rollback.");
taskCompleter.ready(_dbClient);
return;
}
}
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
ExportMaskValidationContext ctx = new ExportMaskValidationContext();
ctx.setStorage(storage);
ctx.setExportMask(exportMask);
ctx.setBlockObjects(volumeURIList, _dbClient);
ctx.setAllowExceptions(!isRollback);
validator.removeInitiators(ctx).validate();
deleteStorageHWIDs(storage, initiatorList);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Unexpected error: removeInitiators failed.", e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("removeInitiators", e.getMessage());
taskCompleter.error(_dbClient, error);
}
_log.info("{} removeInitiators END...", storage.getSerialNumber());
}
use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext 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());
}
use of com.emc.storageos.volumecontroller.impl.validators.contexts.ExportMaskValidationContext 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