use of com.emc.storageos.volumecontroller.impl.StorageGroupPolicyLimitsParam in project coprhd-controller by CoprHD.
the class VmaxExportOperations method createOrSelectSLOBasedStorageGroup.
/**
* This is used only for VMAX3.
*/
private CIMObjectPath createOrSelectSLOBasedStorageGroup(StorageSystem storage, URI exportMaskURI, Collection<Initiator> initiators, VolumeURIHLU[] volumeURIHLUs, String parentGroupName, Map<StorageGroupPolicyLimitsParam, CIMObjectPath> newlyCreatedChildVolumeGroups, TaskCompleter taskCompleter) throws Exception {
List<CIMObjectPath> childVolumeGroupsToBeAddedToParentGroup = new ArrayList<CIMObjectPath>();
String groupName = null;
CIMObjectPath groupPath = null;
ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
// group volumes based on policy
ListMultimap<StorageGroupPolicyLimitsParam, VolumeURIHLU> policyToVolumeGroup = ArrayListMultimap.create();
WBEMClient client = _helper.getConnection(storage).getCimClient();
for (VolumeURIHLU volumeUriHLU : volumeURIHLUs) {
StorageGroupPolicyLimitsParam sgPolicyLimitsParam = null;
URI boUri = volumeUriHLU.getVolumeURI();
BlockObject bo = BlockObject.fetch(_dbClient, boUri);
String policyName = volumeUriHLU.getAutoTierPolicyName();
boolean fastAssociatedAlready = false;
// Also note that Volumes with Compression set to true are also fast managed below is for vmax3.
if (_helper.isFastPolicy(policyName) || volumeUriHLU.getCompression()) {
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 {
sgPolicyLimitsParam = new StorageGroupPolicyLimitsParam(volumeUriHLU, storage, _helper);
}
policyToVolumeGroup.put(sgPolicyLimitsParam, volumeUriHLU);
}
_log.info("{} Groups generated based on grouping volumes by fast policy", policyToVolumeGroup.size());
/**
* Grouped Volumes based on Fast Policy
*/
for (Entry<StorageGroupPolicyLimitsParam, Collection<VolumeURIHLU>> policyToVolumeGroupEntry : policyToVolumeGroup.asMap().entrySet()) {
List<CIMObjectPath> childVolumeGroupsToBeAdded = new ArrayList<CIMObjectPath>();
StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = policyToVolumeGroupEntry.getKey();
ListMultimap<String, VolumeURIHLU> expectedVolumeHluMap = ControllerUtils.getVolumeNativeGuids(policyToVolumeGroupEntry.getValue(), _dbClient);
Map<String, Set<String>> existingGroupPaths;
/**
* Find any existing Storage Groups can be reused, in
* case of Fast Enabled volumes
*/
_log.info("Running Storage Group Selection Process");
existingGroupPaths = _helper.findAnyStorageGroupsCanBeReUsed(storage, expectedVolumeHluMap, storageGroupPolicyLimitsParam);
_log.info("Existing Storage Groups Found :" + Joiner.on("\t").join(existingGroupPaths.keySet()));
if (existingGroupPaths.size() > 0) {
if (existingGroupPaths.size() > 0) {
childVolumeGroupsToBeAdded.addAll(_helper.constructMaskingGroupPathsFromNames(existingGroupPaths.keySet(), storage));
}
}
Set<String> volumesInExistingStorageGroups = _helper.constructVolumeNativeGuids(existingGroupPaths.values());
_log.debug("Volumes part of existing reusable Storage Groups {}", Joiner.on("\t").join(volumesInExistingStorageGroups));
// Storage Group needs to be created for those volumes,
// which doesn't fit into
// existing groups.
Set<String> diff = Sets.difference(expectedVolumeHluMap.asMap().keySet(), volumesInExistingStorageGroups);
_log.debug("Remaining Volumes, for which new Storage Group needs to be created", Joiner.on("\t").join(diff));
// need to construct a new group for remaining volumes.
if (!diff.isEmpty()) {
VolumeURIHLU[] volumeURIHLU = ControllerUtils.constructVolumeUriHLUs(diff, expectedVolumeHluMap);
// TODO: VMAX3 customized names
groupName = generateStorageGroupName(storage, mask, initiators, storageGroupPolicyLimitsParam);
_log.debug("Group Name Created :", groupName);
groupPath = createVolumeGroup(storage, groupName, volumeURIHLU, taskCompleter, true);
_log.info("{} Volume Group created on Array {}", storage.getSerialNumber());
}
if (null != groupPath) {
/**
* used later in deleting created groups on failure
*/
newlyCreatedChildVolumeGroups.put(storageGroupPolicyLimitsParam, groupPath);
childVolumeGroupsToBeAdded.add(groupPath);
}
childVolumeGroupsToBeAddedToParentGroup.addAll(childVolumeGroupsToBeAdded);
}
// Avoid duplicate names for the Cascaded VolumeGroup
parentGroupName = _helper.generateGroupName(_helper.getExistingStorageGroupsFromArray(storage), parentGroupName);
CIMObjectPath cascadedGroupPath = createCascadedVolumeGroup(storage, parentGroupName, childVolumeGroupsToBeAddedToParentGroup, taskCompleter);
// for proper roll back , that is volume removal, if exception is thrown during update
for (Entry<StorageGroupPolicyLimitsParam, CIMObjectPath> createdChildVolumeGroupEntry : newlyCreatedChildVolumeGroups.entrySet()) {
CIMObjectPath childGroupPath = createdChildVolumeGroupEntry.getValue();
StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = createdChildVolumeGroupEntry.getKey();
if (storageGroupPolicyLimitsParam.isHostIOLimitBandwidthSet()) {
_helper.updateHostIOLimitBandwidth(client, childGroupPath, storageGroupPolicyLimitsParam.getHostIOLimitBandwidth());
}
if (storageGroupPolicyLimitsParam.isHostIOLimitIOPsSet()) {
_helper.updateHostIOLimitIOPs(client, childGroupPath, storageGroupPolicyLimitsParam.getHostIOLimitIOPs());
}
}
return cascadedGroupPath;
}
use of com.emc.storageos.volumecontroller.impl.StorageGroupPolicyLimitsParam 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.StorageGroupPolicyLimitsParam in project coprhd-controller by CoprHD.
the class VmaxExportOperations method deleteMaskingView.
private boolean deleteMaskingView(StorageSystem storage, URI exportMaskURI, Map<StorageGroupPolicyLimitsParam, List<String>> childrenStorageGroupMap, TaskCompleter taskCompleter) throws Exception {
boolean maskingWasDeleted = false;
_log.debug("{} deleteMaskingView START...", storage.getSerialNumber());
String groupName = _helper.getExportMaskName(exportMaskURI);
CIMInstance maskingViewInstance = maskingViewExists(storage, groupName);
if (maskingViewInstance == null) {
_log.info("{} deleteMaskingView END...Masking view already deleted: {}", storage.getSerialNumber(), groupName);
return true;
}
try {
// get parent ig from masking view
CIMObjectPath igPath = _helper.getInitiatorGroupForGivenMaskingView(maskingViewInstance.getObjectPath(), storage);
// 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;
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
for (String volURI : exportMask.getUserAddedVolumes().values()) {
forceFlag = ExportUtils.useEMCForceFlag(_dbClient, URI.create(volURI));
if (forceFlag) {
break;
}
}
CIMArgument[] inArgs = _helper.getDeleteMaskingViewInputArguments(storage, exportMaskURI, forceFlag);
CIMArgument[] outArgs = new CIMArgument[5];
// Collect the current list of associated IGs for the MaskingView. This
// will include cascaded and child IGs.
List<CIMObjectPath> igPaths = new ArrayList<CIMObjectPath>();
getInitiatorGroupsFromMvOrIg(storage, maskingViewInstance.getObjectPath(), igPaths);
// remove parent IG
igPaths.remove(igPath);
WBEMClient client = _helper.getConnection(storage).getCimClient();
// if SG is associated with other MVs/parent groups, set IO Limits back on it at the end
for (Entry<StorageGroupPolicyLimitsParam, List<String>> storageGroupEntry : childrenStorageGroupMap.entrySet()) {
for (String storageGroupName : storageGroupEntry.getValue()) {
CIMObjectPath storageGroupPath = _cimPath.getMaskingGroupPath(storage, storageGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
_helper.resetHostIOLimits(client, storage, storageGroupPath);
}
}
// Invoke operation to delete the MaskingView. This should clean up
// IG that are directly related to the MV. We will have to check if any
// others that may be child IGs are left dangling. If they are and not
// associated with other IGs or MVs, we shall have to delete them.
SmisSynchSubTaskJob deleteJob = new SmisSynchSubTaskJob(null, storage.getId(), "DeleteMaskingView");
_helper.invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "DeleteMaskingView", inArgs, outArgs, deleteJob);
if (deleteJob.isSuccess()) {
if (_helper.checkExists(storage, igPath, true, false) != null) {
List<CIMObjectPath> associatedMaskingViews = getAssociatedMaskingViews(storage, igPath);
List<CIMObjectPath> associatedIGs = getAssociatedParentIGs(storage, igPath);
if (associatedMaskingViews.isEmpty() && (associatedIGs.isEmpty() || _helper.isCascadedIG(storage, igPath))) {
// parentIGs has associated IGs, not the parent
// delete CIG if it is not associated with any MV (CTRL-9662)
// CTRL-9323 : deleting Parent IG associated with masking view.
deleteInitiatorGroup(storage, igPath);
} else {
_log.info(String.format("Did not delete %s as it is still associated to MaskingViews [%s] and/or AssociatedIGs [%s]", igPath.toString(), Joiner.on(',').join(associatedMaskingViews), Joiner.on(',').join(associatedIGs)));
}
} else {
_log.info("IG already deleted {}", igPath);
}
// CTRL-9323 : only child IGs will be processed, as parent is deleted already we will not hit the cyclic
// issue
maskingWasDeleted = checkIGsAndDeleteIfUnassociated(storage, igPaths);
if (!maskingWasDeleted) {
taskCompleter.error(_dbClient, DeviceControllerException.errors.unableToDeleteIGs(groupName));
return false;
}
} else {
String opName = ResourceOperationTypeEnum.DELETE_EXPORT_GROUP.getName();
ServiceError serviceError = DeviceControllerException.errors.jobFailedOp(opName);
taskCompleter.error(_dbClient, serviceError);
return maskingWasDeleted;
}
_log.debug("{} deleteMaskingView END...", storage.getSerialNumber());
} catch (WBEMException we) {
_log.error(String.format("Problem when trying to delete masking view - array: %s, view: %s", storage.getSerialNumber(), groupName), we);
String opName = ResourceOperationTypeEnum.DELETE_EXPORT_GROUP.getName();
ServiceError serviceError = DeviceControllerException.errors.jobFailed(we);
taskCompleter.error(_dbClient, serviceError);
throw we;
}
_log.debug("{} deleteMaskingView END...", storage.getSerialNumber());
return maskingWasDeleted;
}
use of com.emc.storageos.volumecontroller.impl.StorageGroupPolicyLimitsParam in project coprhd-controller by CoprHD.
the class VmaxExportOperations method createExportMask.
/**
* This implementation will attempt to create a MaskingView on the VMAX with the
* associated elements. The goal of this is to create a MaskingView per compute
* resource. A compute resource is either a host or a cluster. A host is a single
* entity with multiple initiators. A cluster is an entity consisting of multiple
* hosts.
*
* The idea is to maintain 1 MaskingView to 1 compute resource,
* regardless of the number of ViPR Export*Groups* that are created. An
* Export*Mask* will map to a MaskingView.
*
* @param storage
* @param exportMaskURI
* @param volumeURIHLUs
* @param targetURIList
* @param initiatorList
* @param taskCompleter
* @throws DeviceControllerException
*/
@Override
public void createExportMask(StorageSystem storage, URI exportMaskURI, VolumeURIHLU[] volumeURIHLUs, List<URI> targetURIList, List<Initiator> initiatorList, TaskCompleter taskCompleter) throws DeviceControllerException {
_log.info("{} createExportMask START...", storage.getSerialNumber());
Map<StorageGroupPolicyLimitsParam, CIMObjectPath> newlyCreatedChildVolumeGroups = new HashMap<StorageGroupPolicyLimitsParam, CIMObjectPath>();
ExportOperationContext context = new VmaxExportOperationContext();
// Prime the context object
taskCompleter.updateWorkflowStepContext(context);
try {
_log.info("Export mask id: {}", exportMaskURI);
_log.info("createExportMask: volume-HLU pairs: {}", Joiner.on(',').join(volumeURIHLUs));
_log.info("createExportMask: initiators: {}", Joiner.on(',').join(initiatorList));
_log.info("createExportMask: assignments: {}", Joiner.on(',').join(targetURIList));
ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
String maskingViewName = generateMaskViewName(storage, mask);
// Fill this in now so we have it in case of exceptions
String cascadedIGCustomTemplateName = CustomConfigConstants.VMAX_HOST_CASCADED_IG_MASK_NAME;
String initiatorGroupCustomTemplateName = CustomConfigConstants.VMAX_HOST_INITIATOR_GROUP_MASK_NAME;
String cascadedSGCustomTemplateName = CustomConfigConstants.VMAX_HOST_CASCADED_SG_MASK_NAME;
String portGroupCustomTemplateName = CustomConfigConstants.VMAX_HOST_PORT_GROUP_MASK_NAME;
String exportType = ExportMaskUtils.getExportType(_dbClient, mask);
if (ExportGroupType.Cluster.name().equals(exportType)) {
cascadedIGCustomTemplateName = CustomConfigConstants.VMAX_CLUSTER_CASCADED_IG_MASK_NAME;
initiatorGroupCustomTemplateName = CustomConfigConstants.VMAX_CLUSTER_INITIATOR_GROUP_MASK_NAME;
cascadedSGCustomTemplateName = CustomConfigConstants.VMAX_CLUSTER_CASCADED_SG_MASK_NAME;
portGroupCustomTemplateName = CustomConfigConstants.VMAX_CLUSTER_PORT_GROUP_MASK_NAME;
}
// 1. InitiatorGroup (IG)
DataSource cascadedIGDataSource = ExportMaskUtils.getExportDatasource(storage, initiatorList, dataSourceFactory, cascadedIGCustomTemplateName);
String cigName = customConfigHandler.getComputedCustomConfigValue(cascadedIGCustomTemplateName, storage.getSystemType(), cascadedIGDataSource);
cigName = _helper.generateGroupName(_helper.getExistingInitiatorGroupsFromArray(storage), cigName);
CIMObjectPath cascadedIG = createOrUpdateInitiatorGroups(storage, exportMaskURI, cigName, initiatorGroupCustomTemplateName, initiatorList, taskCompleter);
if (cascadedIG == null) {
// return from here.
return;
}
// 2. StorageGroup (SG)
DataSource cascadedSGDataSource = ExportMaskUtils.getExportDatasource(storage, initiatorList, dataSourceFactory, cascadedSGCustomTemplateName);
String csgName = customConfigHandler.getComputedCustomConfigValue(cascadedSGCustomTemplateName, storage.getSystemType(), cascadedSGDataSource);
// 3. PortGroup (PG)
// check if port group name is specified
URI portGroupURI = mask.getPortGroup();
String portGroupName = null;
CIMObjectPath targetPortGroupPath = null;
if (!NullColumnValueGetter.isNullURI(portGroupURI) && isUsePortGroupEnabled()) {
StoragePortGroup pg = _dbClient.queryObject(StoragePortGroup.class, portGroupURI);
portGroupName = pg.getLabel();
_log.info(String.format("port group name: %s", portGroupName));
// Check if the port group existing in the array
targetPortGroupPath = _cimPath.getMaskingGroupPath(storage, portGroupName, SmisConstants.MASKING_GROUP_TYPE.SE_TargetMaskingGroup);
List<URI> ports = _helper.getPortGroupMembers(storage, targetPortGroupPath);
if (!ports.containsAll(targetURIList)) {
String targets = Joiner.on(',').join(targetURIList);
_log.error(String.format("The port group %s does not contain all the storage ports in the target list %s", pg.getNativeGuid(), targets));
taskCompleter.error(_dbClient, DeviceControllerException.exceptions.portGroupNotUptodate(pg.getNativeGuid(), targets));
return;
}
} else {
DataSource portGroupDataSource = ExportMaskUtils.getExportDatasource(storage, initiatorList, dataSourceFactory, portGroupCustomTemplateName);
portGroupName = customConfigHandler.getComputedCustomConfigValue(portGroupCustomTemplateName, storage.getSystemType(), portGroupDataSource);
// CTRL-9054 Always create unique port Groups.
portGroupName = _helper.generateGroupName(_helper.getExistingPortGroupsFromArray(storage), portGroupName);
targetPortGroupPath = createTargetPortGroup(storage, portGroupName, mask, targetURIList, taskCompleter);
}
// 4. ExportMask = MaskingView (MV) = IG + SG + PG
CIMObjectPath volumeParentGroupPath = storage.checkIfVmax3() ? // TODO: Customized name for SLO based group
createOrSelectSLOBasedStorageGroup(storage, exportMaskURI, initiatorList, volumeURIHLUs, csgName, newlyCreatedChildVolumeGroups, taskCompleter) : createOrSelectStorageGroup(storage, exportMaskURI, initiatorList, volumeURIHLUs, csgName, newlyCreatedChildVolumeGroups, taskCompleter);
createMaskingView(storage, exportMaskURI, maskingViewName, volumeParentGroupPath, volumeURIHLUs, targetPortGroupPath, cascadedIG, taskCompleter);
} catch (Exception e) {
_log.error(String.format("createExportMask failed - maskName: %s", exportMaskURI.toString()), e);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
taskCompleter.error(_dbClient, serviceError);
}
_log.info("{} createExportMask END...", storage.getSerialNumber());
}
use of com.emc.storageos.volumecontroller.impl.StorageGroupPolicyLimitsParam in project coprhd-controller by CoprHD.
the class VmaxExportOperations method validateAndUpdateStorageGroupPolicyAndLimits.
/**
* Validates and updates fast policy in storage group.
*
* @param storage
* the storage system
* @param exportMask
* exportMask
* @param childGroupName
* the child group name
* @param volumeURIs
* the volume uris
* @param newVirtualPool
* the new virtual pool where new policy name and host limits can be obtained
* @param phantomSGNames
* the phantom SG names if any
* @param taskCompleter
* task completer
* @return true, if successfully updated policy for SG
* @throws WBEMException
* the wBEM exception
* @throws Exception
* the exception
*/
private boolean validateAndUpdateStorageGroupPolicyAndLimits(StorageSystem storage, ExportMask exportMask, String childGroupName, List<URI> volumeURIs, VirtualPool newVirtualPool, Set<String> phantomSGNames, TaskCompleter taskCompleter) throws WBEMException, Exception {
boolean policyUpdated = false;
boolean isVmax3 = storage.checkIfVmax3();
_log.info("Checking on Storage Group {}", childGroupName);
WBEMClient client = _helper.getConnection(storage).getCimClient();
// we need auto tiering policy object to get its name.
String newPolicyName = ControllerUtils.getFastPolicyNameFromVirtualPool(_dbClient, storage, newVirtualPool);
if (isVmax3) {
newPolicyName = _helper.getVMAX3FastSettingForVolume(volumeURIs.get(0), newPolicyName);
}
StorageGroupPolicyLimitsParam newVirtualPoolPolicyLimits = new StorageGroupPolicyLimitsParam(newPolicyName, newVirtualPool.getHostIOLimitBandwidth(), newVirtualPool.getHostIOLimitIOPs(), newVirtualPool.getCompressionEnabled(), storage);
CIMObjectPath childGroupPath = _cimPath.getMaskingGroupPath(storage, childGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
if (isVmax3) {
/**
* VMAX3 part of multiple exports: volumes will be part of multiple SGs
* One as FAST SG and others as non-FAST SG.
* If the requested SG is non FAST, do nothing. Other export mask's call
* will take care of updating FAST setting.
*/
BlockObject bo = BlockObject.fetch(_dbClient, volumeURIs.get(0));
if (_helper.isVolumePartOfMoreThanOneExport(storage, bo)) {
String currentPolicyName = _helper.getVMAX3FastSettingAssociatedWithVolumeGroup(storage, childGroupPath);
if (Constants.NONE.equalsIgnoreCase(currentPolicyName) && _helper.checkVolumeAssociatedWithAnyFASTSG(bo.getNativeId(), storage)) {
Map<ExportMask, ExportGroup> maskToGroupMap = ExportUtils.getExportMasks(bo, _dbClient);
if (maskToGroupMap.size() > 1) {
_log.info("Volumes {} are part of multiple storage groups. " + "FAST Policy will be (or might already be) changed during other export mask's call.", Joiner.on("\t").join(volumeURIs));
return true;
} else {
_log.error("FAST Policy cannot be updated on this storage group" + " since volumes are already part of another FAST managed storage group.");
return false;
}
}
}
}
if (!isVmax3 && !phantomSGNames.isEmpty() && !_helper.isFastPolicy(_helper.getAutoTieringPolicyNameAssociatedWithVolumeGroup(storage, childGroupPath)) && !_helper.isCascadedSG(storage, childGroupPath)) {
/**
* Phantom SG will be taken into consideration only if MV contains Non-cascaded Non-FAST SG
*/
_log.info("**** Phantom Storage Group ****");
/**
* For Volumes in Phantom SG - Volumes part of Phantom SG will be in Non-cascaded Non-FAST Storage Group
* (CTRL-9064)
*
* We have the phantom SGs having volumes which are part of this Masking view
* Group requested volumes by SG
* volumes in each Phantom SG
* also add an entry with volumes to Non-FAST SG (volumes requested minus volumes already in phantom SG)
*
* For each SG,
* If Phantom SG:
* If it is requested for all volumes
* change the policy associated with phantom SG
* else
* Remove the volumes from that phantom SG
* add them to new/existing phantom SG which is associated with new policy
* Note: if new policy is NONE, we just remove the volumes from phantom SG, no need to add them to another
* phantom SG.
* Since these volumes are already part of Non-FAST SG, they are part of MV.
* Else if it is Non-FAST SG:
* place those volumes in new/existing Phantom SG which is associated with new Policy
*/
Map<String, List<URI>> volumeGroup = new HashMap<String, List<URI>>();
List<URI> volumeURIsOfNonFASTSG = new ArrayList<URI>();
volumeURIsOfNonFASTSG.addAll(volumeURIs);
for (String phantomSGName : phantomSGNames) {
List<URI> volURIs = _helper.findVolumesInStorageGroup(storage, phantomSGName, volumeURIs);
if (!volURIs.isEmpty()) {
volumeGroup.put(phantomSGName, volURIs);
volumeURIsOfNonFASTSG.removeAll(volURIs);
}
}
// put Non-FAST SG with volumes (volumes requested minus volumes already in phantom SG)
if (!volumeURIsOfNonFASTSG.isEmpty()) {
volumeGroup.put(childGroupName, volumeURIsOfNonFASTSG);
}
for (Entry<String, List<URI>> sgNameToVolumes : volumeGroup.entrySet()) {
String sgName = sgNameToVolumes.getKey();
List<URI> volumesInSG = sgNameToVolumes.getValue();
CIMObjectPath sgPath = _cimPath.getMaskingGroupPath(storage, sgName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
// 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) {
// The force flag only needs to be set once
if (!forceFlag) {
forceFlag = ExportUtils.useEMCForceFlag(_dbClient, volURI);
}
}
/**
* update Policy on this SG. We don't use Phantom SG for IO Limits
*/
String currentPolicyName = _helper.getAutoTieringPolicyNameAssociatedWithVolumeGroup(storage, sgPath);
_log.info("FAST policy name associated with Storage Group {} : {}", sgName, currentPolicyName);
if (!_helper.isFastPolicy(currentPolicyName)) {
/**
* Not a Phantom SG. Create new or use existing Phantom SG for the requested volumes
* Request: non-FAST volumes in SG (associated with MV) to FAST volumes
*/
addVolumesToPhantomStorageGroup(storage, exportMask, volumesInSG, newPolicyName, childGroupName, taskCompleter, forceFlag);
} else {
/**
* phantom SG
*/
_log.info("Checking on Phantom Storage Group {}", sgName);
// check if phantom SG has the same set of volumes as the volume list provided
if (isGivenVolumeListSameAsInStorageGroup(storage, sgPath, volumesInSG)) {
_log.info("Changing Policy on Phantom Storage Group {} since it is requested " + "for all the volumes in the Group.", sgName);
if (!currentPolicyName.equalsIgnoreCase(newPolicyName)) {
if (_helper.isFastPolicy(currentPolicyName)) {
_helper.removeVolumeGroupFromAutoTieringPolicy(storage, sgPath);
}
if (_helper.isFastPolicy(newPolicyName)) {
_log.info("Adding Storage Group {} to FAST Policy {}", sgName, newPolicyName);
addVolumeGroupToAutoTieringPolicy(storage, newPolicyName, sgPath, taskCompleter);
StorageGroupPolicyLimitsParam phantomStorageGroupPolicyLimitsParam = new StorageGroupPolicyLimitsParam(newPolicyName);
String newSGName = generateNewNameForPhantomSG(storage, childGroupName, phantomStorageGroupPolicyLimitsParam);
// update SG name according to new policy
_helper.updateStorageGroupName(client, sgPath, newSGName);
}
} else {
_log.info("Current and new policy names are same '{}'." + " No need to update it on SG.", currentPolicyName);
}
/**
* if new policy is NONE & all volumes in request
* remove phantom SG since it won't be needed anymore
* (because volumes are already part of Non-FAST SG associated with MV)
* Request: FAST volumes to Non-FAST
*/
if (!_helper.isFastPolicy(newPolicyName)) {
removePhantomStorageGroup(storage, client, exportMask.getId(), sgName, sgPath, volumesInSG, forceFlag);
}
} else {
/**
* remove requested volumes from this phantom SG
* add them to the new/existing phantom SG which is associated with target policy
*/
_log.info("Request is made for part of volumes in the Group");
removePhantomStorageGroup(storage, client, exportMask.getId(), sgName, sgPath, volumesInSG, forceFlag);
if (_helper.isFastPolicy(newPolicyName)) {
addVolumesToPhantomStorageGroup(storage, exportMask, volumesInSG, newPolicyName, childGroupName, taskCompleter, forceFlag);
}
}
}
policyUpdated = true;
}
} else {
/**
* Usual flow for regular SGs
*
* check if SG has the same set of volumes as the volume list provided.
*/
if (isGivenVolumeListSameAsInStorageGroup(storage, childGroupPath, volumeURIs)) {
/**
* update Policy and Limits on this SG
*/
_log.info("Request is made for all volumes in the Group. Updating Policy and Limits on this Storage Group..");
CIMInstance childGroupInstance = null;
if (isVmax3) {
childGroupInstance = _helper.getInstance(storage, childGroupPath, false, false, SmisConstants.PS_V3_STORAGE_GROUP_PROPERTIES);
} else {
childGroupInstance = _helper.checkExists(storage, childGroupPath, false, false);
}
StorageGroupPolicyLimitsParam currentStorageGroupPolicyLimits = _helper.createStorageGroupPolicyLimitsParam(storage, childGroupInstance);
String currentPolicyName = currentStorageGroupPolicyLimits.getAutoTierPolicyName();
if (!currentPolicyName.equalsIgnoreCase(newPolicyName)) {
_log.info("FAST policy name associated with Storage Group {} : {}", childGroupName, currentPolicyName);
if (isVmax3) {
newPolicyName = _helper.getVMAX3FastSettingWithRightNoneString(storage, newPolicyName);
CIMInstance toUpdate = new CIMInstance(childGroupInstance.getObjectPath(), _helper.getV3FastSettingProperties(newPolicyName));
_helper.modifyInstance(storage, toUpdate, SmisConstants.PS_V3_FAST_SETTING_PROPERTIES);
_log.info("Modified Storage Group {} FAST Setting to {}", childGroupName, newPolicyName);
} else {
if (_helper.isFastPolicy(currentPolicyName)) {
_helper.removeVolumeGroupFromAutoTieringPolicy(storage, childGroupPath);
}
if (_helper.isFastPolicy(newPolicyName)) {
_log.info("Adding Storage Group {} to FAST Policy {}", childGroupName, newPolicyName);
addVolumeGroupToAutoTieringPolicy(storage, newPolicyName, childGroupPath, taskCompleter);
}
}
} else {
_log.info("Current and new policy names are same '{}'." + " No need to update it on Storage Group.", currentPolicyName);
}
// Even if we don't change policy name on device
// we need to set policyUpdated = true else rollback kicks in
policyUpdated = true;
// Update the compression attributes if it needs to be
if (isVmax3) {
// refresh the SG instance since compression property is enabled by default
// when SG becomes FAST managed.
childGroupInstance = _helper.getInstance(storage, childGroupPath, false, false, SmisConstants.PS_EMC_COMPRESSION);
boolean currentCompressionSetting = SmisUtils.getEMCCompressionForStorageGroup(childGroupInstance);
boolean newCompressionSetting = newVirtualPoolPolicyLimits.getCompression();
if (currentCompressionSetting != newCompressionSetting) {
CIMInstance toUpdate = new CIMInstance(childGroupInstance.getObjectPath(), _helper.getV3CompressionProperties(newCompressionSetting));
_helper.modifyInstance(storage, toUpdate, SmisConstants.PS_EMC_COMPRESSION);
_log.info("Modified Storage Group {} Compression setting to {}", childGroupName, newCompressionSetting);
} else {
_log.info("Current and new compression values are same '{}'." + " No need to update it on Storage Group.", newCompressionSetting);
}
}
// update host io limits if need be
if (!HostIOLimitsParam.isEqualsLimit(currentStorageGroupPolicyLimits.getHostIOLimitBandwidth(), newVirtualPoolPolicyLimits.getHostIOLimitBandwidth())) {
_helper.updateHostIOLimitBandwidth(client, childGroupPath, newVirtualPoolPolicyLimits.getHostIOLimitBandwidth());
policyUpdated = true;
}
if (!HostIOLimitsParam.isEqualsLimit(currentStorageGroupPolicyLimits.getHostIOLimitIOPs(), newVirtualPoolPolicyLimits.getHostIOLimitIOPs())) {
_helper.updateHostIOLimitIOPs(client, childGroupPath, newVirtualPoolPolicyLimits.getHostIOLimitIOPs());
policyUpdated = true;
}
if (policyUpdated) {
Set<Initiator> initiators = ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null);
_helper.updateStorageGroupName(client, childGroupPath, generateStorageGroupName(storage, exportMask, initiators, newVirtualPoolPolicyLimits));
}
} else if (isVmax3) {
/**
* Requested for fewer members in a SG
*
* V3 supports moveMembers from one SG to another, provided some conditions met.
* see #helper.moveVolumesFromOneStorageGroupToAnother() for criteria.
*
* validate that current SG is not a parent SG and it is not associated with MV
* check if there is another SG under CSG with new fastSetting & limits
* else create new SG (with new fastSetting, IO limits) and associate it with CSG
* call 'moveMembers' to move volumes from current SG to new SG
*/
_log.info("Request is made for part of volumes in the Group (VMAX3). Moving those volumes to new Storage Group..");
if (!_helper.isCascadedSG(storage, childGroupPath) && !_helper.findStorageGroupsAssociatedWithOtherMaskingViews(storage, childGroupName)) {
String parentGroupName = _helper.getStorageGroupForGivenMaskingView(exportMask.getMaskName(), storage);
Map<StorageGroupPolicyLimitsParam, List<String>> childGroupsByFast = _helper.groupStorageGroupsByAssociation(storage, parentGroupName);
List<String> newChildGroups = childGroupsByFast.get(newVirtualPoolPolicyLimits);
if (newChildGroups != null) {
// remove CSG
newChildGroups.remove(parentGroupName);
}
boolean newGroup = false;
CIMObjectPath newChildGroupPath = null;
String newChildGroupName = null;
if (newChildGroups != null && !newChildGroups.isEmpty()) {
newChildGroupName = newChildGroups.iterator().next();
newChildGroupPath = _cimPath.getMaskingGroupPath(storage, newChildGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup);
} else {
newGroup = true;
newPolicyName = _helper.getVMAX3FastSettingWithRightNoneString(storage, newPolicyName);
String[] tokens = newPolicyName.split(Constants.SMIS_PLUS_REGEX);
newChildGroupPath = _helper.createVolumeGroupBasedOnSLO(storage, storage, tokens[0], tokens[1], tokens[2]);
// 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 : volumeURIs) {
if (!forceFlag) {
forceFlag = ExportUtils.useEMCForceFlag(_dbClient, volURI);
}
}
addGroupsToCascadedVolumeGroup(storage, parentGroupName, newChildGroupPath, null, null, forceFlag);
}
// We could enter the same situation if any of the SG characteristics were modified without ViPR knowledge.
if (childGroupName.equalsIgnoreCase(newChildGroupName)) {
_log.info("Current Storage Group {} has the required charcteristics" + "No need to invoke SMI-S moveMembers method. Performing NO-OP", newChildGroupName);
} else {
SmisJob moveVolumesToSGJob = new SmisSynchSubTaskJob(null, storage.getId(), SmisConstants.MOVE_MEMBERS);
_helper.moveVolumesFromOneStorageGroupToAnother(storage, childGroupPath, newChildGroupPath, volumeURIs, moveVolumesToSGJob);
}
if (newGroup) {
// update host IO limits if need be
if (newVirtualPoolPolicyLimits.isHostIOLimitBandwidthSet()) {
_helper.updateHostIOLimitBandwidth(client, newChildGroupPath, newVirtualPoolPolicyLimits.getHostIOLimitBandwidth());
}
if (newVirtualPoolPolicyLimits.isHostIOLimitIOPsSet()) {
_helper.updateHostIOLimitIOPs(client, newChildGroupPath, newVirtualPoolPolicyLimits.getHostIOLimitIOPs());
}
// Honor the compression settings if needed..
if (!newVirtualPoolPolicyLimits.getCompression()) {
// If the user opted out of compression, and the created SG has compression enabled by default,
// we need to opt out..
CIMInstance newChildGroupInstance = _helper.getInstance(storage, newChildGroupPath, false, false, SmisConstants.PS_EMC_COMPRESSION);
if (SmisUtils.getEMCCompressionForStorageGroup(newChildGroupInstance)) {
CIMInstance toUpdate = new CIMInstance(newChildGroupInstance.getObjectPath(), _helper.getV3CompressionProperties(false));
_helper.modifyInstance(storage, toUpdate, SmisConstants.PS_EMC_COMPRESSION);
}
}
Set<Initiator> initiators = ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null);
_helper.updateStorageGroupName(client, newChildGroupPath, generateStorageGroupName(storage, exportMask, initiators, newVirtualPoolPolicyLimits));
}
policyUpdated = true;
} else {
_log.info("Conditions for 'moveMembers' didn't meet for Storage Group {}." + " Hence, cannot move volumes to new Storage Group with new policy and limits.", childGroupName);
}
} else {
_log.info("Given Volume list is not same as the one in Storage Group {}." + " Hence, FAST policy change won't be done on it.", childGroupName);
}
}
return policyUpdated;
}
Aggregations