use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter 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.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter 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.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter in project coprhd-controller by CoprHD.
the class VmaxExportOperations method addVolumes.
@Override
public void addVolumes(StorageSystem storage, URI exportMaskURI, VolumeURIHLU[] volumeURIHLUs, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} addVolumes START...", storage.getSerialNumber());
try {
_log.info("addVolumes: Export mask id: {}", exportMaskURI);
_log.info("addVolumes: volume-HLU pairs: {}", Joiner.on(',').join(volumeURIHLUs));
if (initiatorList != null) {
_log.info("addVolumes: initiators impacted: {}", Joiner.on(',').join(initiatorList));
}
boolean isVmax3 = storage.checkIfVmax3();
ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
ExportOperationContext context = new VmaxExportOperationContext();
// Prime the context object
taskCompleter.updateWorkflowStepContext(context);
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, remove the volumes from the mask.
if (null == parentGroupName) {
List<URI> volumeURIList = new ArrayList<URI>();
for (VolumeURIHLU vuh : volumeURIHLUs) {
volumeURIList.add(vuh.getVolumeURI());
}
mask.removeVolumes(volumeURIList);
_dbClient.updateObject(mask);
taskCompleter.error(_dbClient, DeviceControllerException.errors.vmaxStorageGroupNameNotFound(maskingViewName));
return;
}
// For existing masking views on the array (co-existence),
// if it has stand alone storage group, convert it into cascaded storage group.
CIMObjectPath storageGroupPath = _cimPath.getMaskingGroupPath(storage, parentGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
if (_helper.isStandAloneSG(storage, storageGroupPath)) {
_log.info("Found Stand alone storage group, verifying the storage array version before converting it to Cascaded..");
if (storage.checkIfVmax3()) {
_log.info("Converting Stand alone storage group to Cascaded..");
_helper.convertStandAloneStorageGroupToCascaded(storage, storageGroupPath, parentGroupName);
} else {
_log.info("Converting Stand alone storage group to Cascaded is not supported for VMAX2. Proceeding provisioning without conversion.");
}
}
// Get the export mask initiator list. This is required to compute the storage group name
Set<Initiator> initiators = ExportMaskUtils.getInitiatorsForExportMask(_dbClient, mask, null);
// 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;
// Determine if the volume is already in the masking view.
// If so, log and remove from volumes we need to process.
parentGroupName = _helper.getStorageGroupForGivenMaskingView(maskingViewName, storage);
Set<String> deviceIds = _helper.getVolumeDeviceIdsFromStorageGroup(storage, parentGroupName);
List<VolumeURIHLU> removeURIs = new ArrayList<>();
for (VolumeURIHLU volumeUriHLU : volumeURIHLUs) {
BlockObject bo = BlockObject.fetch(_dbClient, volumeUriHLU.getVolumeURI());
if (deviceIds.contains(bo.getNativeId())) {
_log.info("Found volume {} is already associated with masking view. Assuming this is from a previous operation.", bo.getLabel());
removeURIs.add(volumeUriHLU);
}
}
// Create the new array of volumes that don't exist yet in the masking view.
VolumeURIHLU[] addVolumeURIHLUs = new VolumeURIHLU[volumeURIHLUs.length - removeURIs.size()];
int index = 0;
for (VolumeURIHLU volumeUriHLU : volumeURIHLUs) {
if (!removeURIs.contains(volumeUriHLU)) {
addVolumeURIHLUs[index++] = volumeUriHLU;
}
}
/**
* Group Volumes by Fast Policy and Host IO limit attributes
*
* policyToVolumeGroupEntry - this will essentially have multiple Groups
* E.g Group 1--> Fast Policy (FP1)+ FEBandwidth (100)
* Group 2--> Fast Policy (FP2)+ IOPS (100)
* Group 3--> FEBandwidth (100) + IOPS (100) ..
*/
ListMultimap<StorageGroupPolicyLimitsParam, VolumeURIHLU> policyToVolumeGroup = ArrayListMultimap.create();
for (VolumeURIHLU volumeUriHLU : addVolumeURIHLUs) {
StorageGroupPolicyLimitsParam sgPolicyLimitsParam = null;
URI boUri = volumeUriHLU.getVolumeURI();
BlockObject bo = BlockObject.fetch(_dbClient, boUri);
boolean fastAssociatedAlready = false;
// Always treat fast volumes as non-fast if fast is associated on these volumes already
// Export fast volumes to 2 different nodes.
// Also note that Volumes with Compression set to true are also fast managed for VMAX3 Arrays.
String policyName = volumeUriHLU.getAutoTierPolicyName();
if (_helper.isFastPolicy(policyName) || ((isVmax3) && volumeUriHLU.getCompression())) {
if (isVmax3) {
policyName = _helper.getVMAX3FastSettingForVolume(boUri, policyName);
}
fastAssociatedAlready = _helper.checkVolumeAssociatedWithAnySGWithPolicy(bo.getNativeId(), storage, policyName);
}
// should not be created with a FAST policy assigned.
if (fastAssociatedAlready || isRPJournalVolume(bo)) {
_log.info("Forcing policy name to NONE to prevent volume from using FAST policy.");
volumeUriHLU.setAutoTierPolicyName(Constants.NONE);
// Compression was applied on existing SG associated with policy!!
volumeUriHLU.setCompression(false);
sgPolicyLimitsParam = new StorageGroupPolicyLimitsParam(Constants.NONE, volumeUriHLU.getHostIOLimitBandwidth(), volumeUriHLU.getHostIOLimitIOPs(), storage);
} else {
if (isVmax3) {
sgPolicyLimitsParam = new StorageGroupPolicyLimitsParam(volumeUriHLU, storage, _helper);
} else {
sgPolicyLimitsParam = new StorageGroupPolicyLimitsParam(volumeUriHLU, storage);
}
}
policyToVolumeGroup.put(sgPolicyLimitsParam, volumeUriHLU);
// The force flag only needs to be set once
if (!forceFlag) {
forceFlag = ExportUtils.useEMCForceFlag(_dbClient, volumeUriHLU.getVolumeURI());
}
}
_log.info(" {} Groups generated based on grouping volumes by fast policy", policyToVolumeGroup.size());
String storageGroupCustomTemplateName = CustomConfigConstants.VMAX_HOST_STORAGE_GROUP_MASK_NAME;
String exportType = ExportMaskUtils.getExportType(_dbClient, mask);
if (ExportGroupType.Cluster.name().equals(exportType)) {
storageGroupCustomTemplateName = CustomConfigConstants.VMAX_CLUSTER_STORAGE_GROUP_MASK_NAME;
}
DataSource sgDataSource = ExportMaskUtils.getExportDatasource(storage, new ArrayList<Initiator>(initiators), dataSourceFactory, storageGroupCustomTemplateName);
// Group volumes by Storage Group
Map<String, Collection<VolumeURIHLU>> volumesByStorageGroup = _helper.groupVolumesByStorageGroup(storage, parentGroupName, sgDataSource, storageGroupCustomTemplateName, policyToVolumeGroup, customConfigHandler);
// associate it with fast if needed, then add the new Child Group to the existing Parent Cascaded Group
for (Entry<String, Collection<VolumeURIHLU>> volumesByStorageGroupEntry : volumesByStorageGroup.entrySet()) {
VolumeURIHLU[] volumeURIHLUArray = null;
// Even though policy and limits info are already in volumURIHLU, let's still extract to a holder for
// easy access
// Is it safe to not touch the below variable as it seems to be used by non VMAX3 cases only?
StorageGroupPolicyLimitsParam volumePolicyLimitsParam = new StorageGroupPolicyLimitsParam(Constants.NONE);
if (null != volumesByStorageGroupEntry.getValue()) {
volumeURIHLUArray = volumesByStorageGroupEntry.getValue().toArray(new VolumeURIHLU[0]);
volumePolicyLimitsParam = _helper.createStorageGroupPolicyLimitsParam(volumesByStorageGroupEntry.getValue(), storage, _dbClient);
}
String childGroupName = volumesByStorageGroupEntry.getKey().toString();
if (isVmax3) {
childGroupName = childGroupName.replaceAll(Constants.SMIS_PLUS_REGEX, Constants.UNDERSCORE_DELIMITER);
}
_log.info("Group Name : {} --- volume storage group name : {}", childGroupName, (volumeURIHLUArray != null ? Joiner.on("\t").join(volumeURIHLUArray) : ""));
CIMObjectPath childGroupPath = _cimPath.getMaskingGroupPath(storage, childGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
CIMInstance childGroupInstance = _helper.checkExists(storage, childGroupPath, false, false);
if (null == childGroupInstance) {
// For the newly created group, set policy, and other required properties bandwidth, iops as needed.
// Once child group created, add this child Group to existing Parent Cascaded Group.
// Empty child group is created to be able to add volumes with HLUs
// once this child group is added in the cascaded storage group.
_log.info("Group {} doesn't exist, creating a new group", childGroupName);
CIMObjectPath childGroupCreated = createVolumeGroup(storage, childGroupName, volumeURIHLUArray, taskCompleter, false);
_log.debug("Created Child Group {}", childGroupCreated);
// Get childGroupName from the child group path childGroupCreated as it
// could have been truncated in createVolumeGroup method
childGroupName = _cimPath.getMaskingGroupName(storage, childGroupCreated);
if (!isVmax3 && _helper.isFastPolicy(volumePolicyLimitsParam.getAutoTierPolicyName()) && !_helper.checkVolumeGroupAssociatedWithPolicy(storage, childGroupCreated, volumePolicyLimitsParam.getAutoTierPolicyName())) {
_log.debug("Adding Storage Group {} to Fast Policy {}", childGroupName, volumePolicyLimitsParam.getAutoTierPolicyName());
addVolumeGroupToAutoTieringPolicy(storage, volumePolicyLimitsParam.getAutoTierPolicyName(), childGroupCreated, taskCompleter);
}
// Add new Child Storage Group to Parent Cascaded Group
// NOTE: host IO limit is set during the first child SG created with cascaded group.
// Logically (or easy to follow) is to set limits after SG is created. However, because add job
// logic
// is executed in a queue. Hence, move update logic to SmisMaskingViewAddVolumeJob
addGroupsToCascadedVolumeGroup(storage, parentGroupName, childGroupCreated, null, taskCompleter, forceFlag);
_log.debug("Added newly created Storage Group {} to Parent Cascaded Group {}", childGroupName, parentGroupName);
// Add volumes to the newly created child group
_log.info("Adding Volumes to non cascaded Storage Group {} START", childGroupName);
// 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);
SmisMaskingViewAddVolumeJob job = new SmisMaskingViewAddVolumeJob(null, storage.getId(), exportMaskURI, volumeURIHLUArray, childGroupCreated, completer);
job.setCIMObjectPathfactory(_cimPath);
_helper.addVolumesToStorageGroup(volumeURIHLUArray, storage, childGroupName, job, forceFlag);
ExportOperationContext.insertContextOperation(taskCompleter, VmaxExportOperationContext.OPERATION_ADD_VOLUMES_TO_STORAGE_GROUP, childGroupName, volumeURIHLUArray, forceFlag);
_log.info("Adding Volumes to non cascaded Storage Group {} END", childGroupName);
} else // Only reusable groups will have null volumeURIHLUArray
if (null != volumeURIHLUArray) {
// Only add volumes that don't already exist in the StorageGroup
VolumeURIHLU[] newVolumesToAdd = getVolumesThatAreNotAlreadyInSG(storage, childGroupPath, childGroupName, volumesByStorageGroupEntry.getValue().toArray(new VolumeURIHLU[0]));
if (newVolumesToAdd != null) {
// We should not disturb any existing masking views on the Array. In this case, if the found
// storage group is not
// associated with expected fast policy, then we cannot proceed with neither of the below
// 1. Adding fast volumes to existing non fast storage group part of masking view
// 2. Creating a new Cascaded Group, and adding the existing storage group to it, as existing
// SG-->MV needs to be
// broken
StorageGroupPolicyLimitsParam childGroupKey = _helper.createStorageGroupPolicyLimitsParam(storage, childGroupInstance);
if (!isVmax3 && _helper.isFastPolicy(volumePolicyLimitsParam.getAutoTierPolicyName()) && !_helper.isFastPolicy(childGroupKey.getAutoTierPolicyName())) {
// Go through each volume associated with this storage group and pluck out by policy
for (StorageGroupPolicyLimitsParam phantomStorageGroupPolicyLimitsParam : policyToVolumeGroup.keySet()) {
String phantomPolicyName = phantomStorageGroupPolicyLimitsParam.getAutoTierPolicyName();
// If this is a non-FAST policy in the grouping, skip it.
if (!_helper.isFastPolicy(phantomPolicyName)) {
continue;
}
// Find the volumes in the volumeURIHLU associated with this policy
VolumeURIHLU[] phantomVolumesToAdd = getVolumesThatBelongToPolicy(newVolumesToAdd, phantomStorageGroupPolicyLimitsParam, storage);
_log.info(String.format("In order to add this volume to the masking view, we need to create/find a storage group " + "for the FAST policy %s and add the volume to the storage group and the existing storage group associated with the masking view", phantomStorageGroupPolicyLimitsParam));
// Check to see if there already is a phantom storage group with this policy on the
// array
List<String> phantomStorageGroupNames = _helper.findPhantomStorageGroupAssociatedWithFastPolicy(storage, phantomStorageGroupPolicyLimitsParam);
// If there's no existing phantom storage group, create one.
if (phantomStorageGroupNames == null || phantomStorageGroupNames.isEmpty()) {
// TODO: Probably need to use some name generator for this.
String phantomStorageGroupName = childGroupName + "_" + phantomStorageGroupPolicyLimitsParam;
// We need to create a new phantom storage group with our policy associated with it.
_log.info("phantom storage group {} doesn't exist, creating a new group", phantomStorageGroupName);
CIMObjectPath phantomStorageGroupCreated = createVolumeGroup(storage, phantomStorageGroupName, phantomVolumesToAdd, taskCompleter, true);
_log.info("Adding Storage Group {} to Fast Policy {}", phantomStorageGroupName, phantomPolicyName);
addVolumeGroupToAutoTieringPolicy(storage, phantomPolicyName, phantomStorageGroupCreated, taskCompleter);
} else {
// take the first matching phantom SG from the list
String phantomStorageGroupName = phantomStorageGroupNames.get(0);
// We found the phantom storage group, but we need to make sure the volumes aren't
// already in the
// storage
// group from a previous operation or manual intervention.
List<URI> phantomVolumeIds = new ArrayList<URI>();
for (VolumeURIHLU phantomVolume : phantomVolumesToAdd) {
phantomVolumeIds.add(phantomVolume.getVolumeURI());
}
phantomVolumeIds.removeAll(_helper.findVolumesInStorageGroup(storage, phantomStorageGroupName, phantomVolumeIds));
if (phantomVolumeIds.isEmpty()) {
_log.info("Found that the volume(s) we wanted to add to the phantom storage group are already added.");
} else {
// If we found a phantom storage group with our policy, use it.
_log.info("Found that we need to add volumes to the phantom storage group: " + phantomStorageGroupName);
// 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);
SmisMaskingViewAddVolumeJob job = new SmisMaskingViewAddVolumeJob(null, storage.getId(), exportMaskURI, phantomVolumesToAdd, null, completer);
job.setCIMObjectPathfactory(_cimPath);
_helper.addVolumesToStorageGroup(phantomVolumesToAdd, storage, phantomStorageGroupName, job, forceFlag);
ExportOperationContext.insertContextOperation(taskCompleter, VmaxExportOperationContext.OPERATION_ADD_VOLUMES_TO_STORAGE_GROUP, phantomStorageGroupName, phantomVolumesToAdd, forceFlag);
_log.info("Adding Volumes to non cascaded Storage Group {} END", phantomStorageGroupName);
}
}
}
}
if (isVmax3) {
// Remove volumes from the parking storage group
Set<String> nativeIds = new HashSet<String>();
for (VolumeURIHLU volURIHLU : newVolumesToAdd) {
nativeIds.add(_helper.getBlockObjectNativeId(volURIHLU.getVolumeURI()));
}
_helper.removeVolumeFromParkingSLOStorageGroup(storage, nativeIds.toArray(new String[] {}), forceFlag);
}
_log.info("Adding Volumes to non cascaded Storage Group {} START", childGroupName);
// 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);
SmisMaskingViewAddVolumeJob job = new SmisMaskingViewAddVolumeJob(null, storage.getId(), exportMaskURI, newVolumesToAdd, null, completer);
job.setCIMObjectPathfactory(_cimPath);
_helper.addVolumesToStorageGroup(newVolumesToAdd, storage, childGroupName, job, forceFlag);
ExportOperationContext.insertContextOperation(taskCompleter, VmaxExportOperationContext.OPERATION_ADD_VOLUMES_TO_STORAGE_GROUP, childGroupName, newVolumesToAdd, forceFlag);
_log.info("Adding Volumes to non cascaded Storage Group {} END", childGroupName);
} else {
// newVolumesToAdd == null, implying that all the requested
// volumes are already in the StorageGroup. This is a no-op.
_log.info("All volumes are already in the storage group");
}
} else // Else, we have existing groups which hold these volumes, hence add those groups to
// cascaded group.
{
_log.info("Adding Existing Storage Group {} to Cascaded Group {} START :", childGroupName, parentGroupName);
if (!isVmax3 && _helper.isFastPolicy(volumePolicyLimitsParam.getAutoTierPolicyName()) && !_helper.checkVolumeGroupAssociatedWithPolicy(storage, childGroupPath, volumePolicyLimitsParam.getAutoTierPolicyName())) {
_log.info("Adding Storage Group {} to Fast Policy {}", childGroupName, volumePolicyLimitsParam.getAutoTierPolicyName());
addVolumeGroupToAutoTieringPolicy(storage, volumePolicyLimitsParam.getAutoTierPolicyName(), childGroupPath, taskCompleter);
}
String task = UUID.randomUUID().toString();
ExportMaskVolumeToStorageGroupCompleter completer = new ExportMaskVolumeToStorageGroupCompleter(null, exportMaskURI, task);
SmisMaskingViewAddVolumeJob job = new SmisMaskingViewAddVolumeJob(null, storage.getId(), exportMaskURI, volumeURIHLUArray, null, completer);
job.setCIMObjectPathfactory(_cimPath);
addGroupsToCascadedVolumeGroup(storage, parentGroupName, childGroupPath, job, taskCompleter, forceFlag);
_log.debug("Adding Existing Storage Group {} to Cascaded Group {} END :", childGroupName, parentGroupName);
}
}
// Test mechanism to invoke a failure. No-op on production systems.
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_002);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error(String.format("addVolumes failed - maskName: %s", exportMaskURI.toString()), e);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
taskCompleter.error(_dbClient, serviceError);
}
_log.info("{} addVolumes END...", storage.getSerialNumber());
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter 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.block.taskcompleter.ExportMaskVolumeToStorageGroupCompleter in project coprhd-controller by CoprHD.
the class VmaxExportOperations method addVolumesToPhantomStorageGroup.
/**
* Adds the volumes to new or existing phantom storage group which is associated with given policy.
* This is used internally for operation - change volume's policy by moving them from one vPool to another.
*/
private void addVolumesToPhantomStorageGroup(StorageSystem storage, ExportMask exportMask, List<URI> volumesInSG, String newPolicyName, String childGroupName, TaskCompleter taskCompleter, boolean forceFlag) throws Exception {
// Check to see if there already is a phantom storage group with this policy on the array
StorageGroupPolicyLimitsParam phantomStorageGroupPolicyLimitsParam = new StorageGroupPolicyLimitsParam(newPolicyName);
List<String> phantomStorageGroupNames = _helper.findPhantomStorageGroupAssociatedWithFastPolicy(storage, phantomStorageGroupPolicyLimitsParam);
VolumeURIHLU[] volumeURIHlus = constructVolumeURIHLUFromURIList(volumesInSG, newPolicyName);
// If there's no existing phantom storage group, create one.
if (phantomStorageGroupNames == null || phantomStorageGroupNames.isEmpty()) {
String phantomStorageGroupName = generateNewNameForPhantomSG(storage, childGroupName, phantomStorageGroupPolicyLimitsParam);
// We need to create a new phantom storage group with our policy associated with it.
_log.info("phantom storage group {} doesn't exist, creating a new group", phantomStorageGroupName);
CIMObjectPath phantomStorageGroupCreated = createVolumeGroup(storage, phantomStorageGroupName, volumeURIHlus, taskCompleter, true);
_log.info("Adding Storage Group {} to Fast Policy {}", phantomStorageGroupName, newPolicyName);
addVolumeGroupToAutoTieringPolicy(storage, newPolicyName, phantomStorageGroupCreated, taskCompleter);
} else {
// take the first matching phantom SG from the list
String phantomStorageGroupName = phantomStorageGroupNames.get(0);
// We found a phantom storage group with our policy, use it.
_log.info("Found that we need to add volumes to the phantom storage group: {}", phantomStorageGroupName);
// 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, exportMask.getId(), task);
SmisMaskingViewAddVolumeJob job = new SmisMaskingViewAddVolumeJob(null, storage.getId(), exportMask.getId(), volumeURIHlus, null, completer);
job.setCIMObjectPathfactory(_cimPath);
_helper.addVolumesToStorageGroup(volumeURIHlus, storage, phantomStorageGroupName, job, forceFlag);
ExportOperationContext.insertContextOperation(taskCompleter, VmaxExportOperationContext.OPERATION_ADD_VOLUMES_TO_STORAGE_GROUP, phantomStorageGroupName, volumeURIHlus, forceFlag);
_log.info("Adding Volumes to Phantom Storage Group {}", phantomStorageGroupName);
}
}
Aggregations