use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.
the class ScaleIOMaskingOrchestrator method exportGroupAddVolumes.
@Override
public void exportGroupAddVolumes(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap, String token) throws Exception {
/*
* foreach volume in list
* foreach initiator in ExportGroup
* scli map --volume volid --sdc initiator.sdcid
*/
ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
try {
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
List<URI> initiatorURIs = StringSetUtil.stringSetToUriList(exportGroup.getInitiators());
if (initiatorURIs != null && !initiatorURIs.isEmpty()) {
// Set up workflow steps.
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupAddVolumes", true, token);
// Create a mapping of ExportMasks to Add Volumes to or
// add to a list of new Exports to create
Map<URI, Map<URI, Integer>> exportMaskToVolumesToAdd = new HashMap<>();
List<URI> initiatorsToPlace = new ArrayList<>(initiatorURIs);
// Need to figure out which ExportMasks to add volumes to.
for (ExportMask exportMask : ExportMaskUtils.getExportMasks(_dbClient, exportGroup, storageURI)) {
if (exportMask.hasAnyInitiators()) {
exportMaskToVolumesToAdd.put(exportMask.getId(), volumeMap);
for (String uriString : exportMask.getInitiators()) {
URI initiatorURI = URI.create(uriString);
initiatorsToPlace.remove(initiatorURI);
}
}
}
Map<String, List<URI>> computeResourceToInitiators = mapInitiatorsToComputeResource(exportGroup, initiatorsToPlace);
log.info(String.format("Need to create ExportMasks for these compute resources %s", Joiner.on(',').join(computeResourceToInitiators.entrySet())));
// volumes from 'storage' StorageSystem to this ExportGroup
for (Map.Entry<String, List<URI>> toCreate : computeResourceToInitiators.entrySet()) {
generateExportMaskCreateWorkflow(workflow, null, storage, exportGroup, toCreate.getValue(), volumeMap, token);
}
log.info(String.format("Need to add volumes for these ExportMasks %s", exportMaskToVolumesToAdd.entrySet()));
// We already know about the ExportMask, so we just add volumes to it
for (Map.Entry<URI, Map<URI, Integer>> toAddVolumes : exportMaskToVolumesToAdd.entrySet()) {
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, toAddVolumes.getKey());
generateExportMaskAddVolumesWorkflow(workflow, null, storage, exportGroup, exportMask, toAddVolumes.getValue(), null);
}
String successMessage = String.format("ExportGroup add volumes successfully applied for StorageArray %s", storage.getLabel());
workflow.executePlan(taskCompleter, successMessage);
} else {
taskCompleter.ready(_dbClient);
}
} catch (DeviceControllerException dex) {
taskCompleter.error(_dbClient, DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("exportGroupAddVolumes", dex.getMessage()));
} catch (Exception ex) {
_log.error("ExportGroup Orchestration failed.", ex);
taskCompleter.error(_dbClient, DeviceControllerErrors.scaleio.encounteredAnExceptionFromScaleIOOperation("exportGroupAddVolumes", ex.getMessage()));
}
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.
the class AbstractBasicMaskingOrchestrator method exportGroupChangePathParams.
@Override
public void exportGroupChangePathParams(URI storageURI, URI exportGroupURI, URI volumeURI, String token) throws Exception {
ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
ExportPathUpdater updater = new ExportPathUpdater(_dbClient);
try {
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupChangePathParams", true, token);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
BlockObject volume = BlockObject.fetch(_dbClient, volumeURI);
_log.info(String.format("Changing path parameters for volume %s (%s)", volume.getLabel(), volume.getId()));
// Call the ExportPathUpdater to generate Workflow steps necessary to change
// the path parameters. It will analyze the ExportGroups versus the ExportParams in
// the VPool of the volume, and call increaseMaxPaths if necessary.
updater.generateExportGroupChangePathParamsWorkflow(workflow, _blockScheduler, this, storage, exportGroup, volume, token);
if (!workflow.getAllStepStatus().isEmpty()) {
_log.info("The changePathParams workflow has {} steps. Starting the workflow.", workflow.getAllStepStatus().size());
workflow.executePlan(taskCompleter, "Update the export group on all export masks successfully.");
} else {
taskCompleter.ready(_dbClient);
}
} catch (Exception ex) {
_log.error("ExportGroup Orchestration failed.", ex);
ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(ex.getMessage(), ex);
taskCompleter.error(_dbClient, serviceError);
}
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.
the class AbstractBasicMaskingOrchestrator method exportGroupAddInitiators.
@Override
public void exportGroupAddInitiators(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, String token) throws Exception {
BlockStorageDevice device = getDevice();
String previousStep = null;
ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
logExportGroup(exportGroup, storageURI);
// Set up workflow steps.
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupAddInitiators", true, token);
Map<URI, List<URI>> zoneMasksToInitiatorsURIs = new HashMap<URI, List<URI>>();
Map<URI, Map<URI, Integer>> zoneNewMasksToVolumeMap = new HashMap<URI, Map<URI, Integer>>();
Map<URI, ExportMask> refreshedMasks = new HashMap<URI, ExportMask>();
List<URI> hostURIs = new ArrayList<URI>();
Map<String, URI> portNameToInitiatorURI = new HashMap<String, URI>();
List<String> portNames = new ArrayList<String>();
// Populate the port WWN/IQNs (portNames) and the
// mapping of the WWN/IQNs to Initiator URIs
processInitiators(exportGroup, initiatorURIs, portNames, portNameToInitiatorURI, hostURIs);
// Populate a map of volumes on the storage device
List<BlockObject> blockObjects = new ArrayList<BlockObject>();
Map<URI, Integer> volumeMap = new HashMap<URI, Integer>();
if (exportGroup.getVolumes() != null) {
for (Map.Entry<String, String> entry : exportGroup.getVolumes().entrySet()) {
URI boURI = URI.create(entry.getKey());
Integer hlu = Integer.valueOf(entry.getValue());
BlockObject bo = BlockObject.fetch(_dbClient, boURI);
if (bo.getStorageController().equals(storageURI)) {
volumeMap.put(boURI, hlu);
blockObjects.add(bo);
}
}
}
// We always want to have the full list of initiators for the hosts involved in
// this export. This will allow the export operation to always find any
// existing exports for a given host.
queryHostInitiatorsAndAddToList(portNames, portNameToInitiatorURI, initiatorURIs, hostURIs);
boolean anyOperationsToDo = false;
Map<String, Set<URI>> matchingExportMaskURIs = device.findExportMasks(storage, portNames, false);
if (matchingExportMaskURIs != null && !matchingExportMaskURIs.isEmpty()) {
// There were some exports out there that already have some or all of the
// initiators that we are attempting to add. We need to only add
// volumes to those existing exports.
List<URI> initiatorURIsCopy = new ArrayList<URI>();
initiatorURIsCopy.addAll(initiatorURIs);
// This loop will determine a list of volumes to update per export mask
Map<URI, Map<URI, Integer>> existingMasksToUpdateWithNewVolumes = new HashMap<URI, Map<URI, Integer>>();
Map<URI, Set<Initiator>> existingMasksToUpdateWithNewInitiators = new HashMap<URI, Set<Initiator>>();
for (Map.Entry<String, Set<URI>> entry : matchingExportMaskURIs.entrySet()) {
URI initiatorURI = portNameToInitiatorURI.get(entry.getKey());
Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
initiatorURIsCopy.remove(initiatorURI);
// Get a list of the ExportMasks that were matched to the initiator
List<URI> exportMaskURIs = new ArrayList<URI>();
exportMaskURIs.addAll(entry.getValue());
List<ExportMask> masks = _dbClient.queryObject(ExportMask.class, exportMaskURIs);
_log.info(String.format("initiator %s is in these masks {%s}", initiator.getInitiatorPort(), Joiner.on(',').join(exportMaskURIs)));
for (ExportMask mask : masks) {
// Check for NO_VIPR. If found, avoid this mask.
if (mask.getMaskName() != null && mask.getMaskName().toUpperCase().contains(ExportUtils.NO_VIPR)) {
_log.info(String.format("ExportMask %s disqualified because the name contains %s (in upper or lower case) to exclude it", mask.getMaskName(), ExportUtils.NO_VIPR));
continue;
}
if (!refreshedMasks.containsKey(mask.getId())) {
mask = getDevice().refreshExportMask(storage, mask);
refreshedMasks.put(mask.getId(), mask);
}
_log.info(String.format("mask %s has initiator %s", mask.getMaskName(), initiator.getInitiatorPort()));
if (!mask.getInactive() && mask.getStorageDevice().equals(storageURI)) {
// already in the masks to the placement list
for (BlockObject blockObject : blockObjects) {
if (!mask.hasExistingVolume(blockObject.getWWN()) && !mask.hasUserAddedVolume(blockObject.getWWN())) {
Map<URI, Integer> newVolumesMap = existingMasksToUpdateWithNewVolumes.get(mask.getId());
if (newVolumesMap == null) {
newVolumesMap = new HashMap<URI, Integer>();
existingMasksToUpdateWithNewVolumes.put(mask.getId(), newVolumesMap);
}
newVolumesMap.put(blockObject.getId(), volumeMap.get(blockObject.getId()));
}
}
// in our export group, because we would simply add to them.
if (mask.getInitiators() != null) {
for (String existingMaskInitiatorStr : mask.getInitiators()) {
// Now look at it from a different angle. Which one of our export group initiators
// are NOT in the current mask? And if so, if it belongs to the same host as an existing one,
// we should add it to this mask.
Iterator<URI> initiatorIter = initiatorURIsCopy.iterator();
while (initiatorIter.hasNext()) {
Initiator initiatorCopy = _dbClient.queryObject(Initiator.class, initiatorIter.next());
if (!mask.hasInitiator(initiatorCopy.getId().toString())) {
Initiator existingMaskInitiator = _dbClient.queryObject(Initiator.class, URI.create(existingMaskInitiatorStr));
if (initiatorCopy.getHost().equals(existingMaskInitiator.getHost())) {
// Add to the list of initiators we need to add to this mask
Set<Initiator> existingMaskInitiators = existingMasksToUpdateWithNewInitiators.get(mask.getId());
if (existingMaskInitiators == null) {
existingMaskInitiators = new HashSet<Initiator>();
existingMasksToUpdateWithNewInitiators.put(mask.getId(), existingMaskInitiators);
}
if (!existingMaskInitiators.contains(initiatorCopy)) {
existingMaskInitiators.add(initiatorCopy);
}
// remove this from the list of initiators we'll make a new mask from
initiatorIter.remove();
}
}
}
}
}
}
updateZoningMap(exportGroup, mask, true);
}
}
// The initiatorURIsCopy was used in the foreach initiator loop to see
// which initiators already exist in a mask. If it is non-empty,
// then it means there are initiators that are new,
// so let's add them to the main tracker
Map<URI, List<URI>> hostInitiatorMap = new HashMap<URI, List<URI>>();
if (!initiatorURIsCopy.isEmpty()) {
for (URI newExportMaskInitiator : initiatorURIsCopy) {
Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
List<URI> initiatorSet = hostInitiatorMap.get(initiator.getHost());
if (initiatorSet == null) {
initiatorSet = new ArrayList<URI>();
hostInitiatorMap.put(initiator.getHost(), initiatorSet);
}
initiatorSet.add(initiator.getId());
_log.info(String.format("host = %s, " + "initiators to add: %d, " + "existingMasksToUpdateWithNewVolumes.size = %d", initiator.getHost(), hostInitiatorMap.get(initiator.getHost()).size(), existingMasksToUpdateWithNewVolumes.size()));
}
}
for (URI host : hostInitiatorMap.keySet()) {
// Create two steps, one for Zoning, one for the ExportGroup actions.
// This step is for zoning. It is not specific to a single NetworkSystem,
// as it will look at all the initiators and targets and compute the
// zones required (which might be on multiple NetworkSystems.)
GenExportMaskCreateWorkflowResult result = generateExportMaskCreateWorkflow(workflow, previousStep, storage, exportGroup, hostInitiatorMap.get(host), volumeMap, token);
previousStep = result.getStepId();
zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
anyOperationsToDo = true;
previousStep = result.getStepId();
}
_log.info(String.format("existingMasksToUpdateWithNewVolumes.size = %d", existingMasksToUpdateWithNewVolumes.size()));
_log.info(String.format("existingMasksToUpdateWithNewInitiators.size = %d", existingMasksToUpdateWithNewInitiators.size()));
previousStep = checkForSnapshotsToCopyToTarget(workflow, storage, previousStep, volumeMap, existingMasksToUpdateWithNewVolumes.values());
// stepMap [URI, String] => [Export Mask URI, StepId of previous task i.e. Add volumes work flow.]
for (Map.Entry<URI, Map<URI, Integer>> entry : existingMasksToUpdateWithNewVolumes.entrySet()) {
ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
Map<URI, Integer> volumesToAdd = entry.getValue();
_log.info(String.format("adding these volumes %s to mask %s", Joiner.on(",").join(volumesToAdd.keySet()), mask.getMaskName()));
List<URI> volumeURIs = new ArrayList<URI>();
volumeURIs.addAll(volumesToAdd.keySet());
previousStep = generateDeviceSpecificAddVolumeWorkFlow(workflow, previousStep, storage, exportGroup, mask, volumesToAdd, volumeURIs, null);
anyOperationsToDo = true;
}
// At this point we have a mapping of all the masks that we need to update with new initiators
for (Entry<URI, Set<Initiator>> entry : existingMasksToUpdateWithNewInitiators.entrySet()) {
ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
Set<Initiator> initiatorsToAdd = entry.getValue();
List<URI> initiatorsURIs = new ArrayList<URI>();
for (Initiator initiator : initiatorsToAdd) {
initiatorsURIs.add(initiator.getId());
}
_log.info(String.format("adding these initiators %s to mask %s", Joiner.on(",").join(initiatorsURIs), mask.getMaskName()));
Map<URI, List<URI>> maskToInitiatorsMap = new HashMap<URI, List<URI>>();
maskToInitiatorsMap.put(mask.getId(), initiatorURIs);
previousStep = generateDeviceSpecificAddInitiatorWorkFlow(workflow, previousStep, storage, exportGroup, mask, null, initiatorsURIs, maskToInitiatorsMap, token);
anyOperationsToDo = true;
}
} else {
// None of the initiators that we're trying to add exist on the
// array in some export. We need to find the ExportMask that was created by
// the system and add the new initiator(s) to it.
boolean foundASystemCreatedMask = false;
Map<String, List<URI>> hostInitiatorMap = new HashMap<String, List<URI>>();
if (!initiatorURIs.isEmpty()) {
for (URI newExportMaskInitiator : initiatorURIs) {
Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
if (initiator != null) {
String hostURIString = initiator.getHost().toString();
List<URI> initiatorSet = hostInitiatorMap.get(hostURIString);
if (initiatorSet == null) {
hostInitiatorMap.put(initiator.getHost().toString(), new ArrayList<URI>());
initiatorSet = hostInitiatorMap.get(hostURIString);
}
initiatorSet.add(initiator.getId());
_log.info(String.format("host = %s, " + "initiators to add: %d, ", initiator.getHost(), hostInitiatorMap.get(hostURIString).size()));
}
}
}
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
if (!exportMasks.isEmpty()) {
_log.info("There are export masks for this group. Adding initiators.");
// the storage system that were created by Bourne and are still active.
for (ExportMask exportMask : exportMasks) {
if (exportMask != null && !exportMask.getInactive() && exportMask.getStorageDevice().equals(storageURI) && exportMask.getCreatedBySystem()) {
List<URI> newInitiators = hostInitiatorMap.get(exportMask.getResource());
if (newInitiators != null && !newInitiators.isEmpty()) {
zoneMasksToInitiatorsURIs.put(exportMask.getId(), newInitiators);
previousStep = generateDeviceSpecificExportMaskAddInitiatorsWorkflow(workflow, previousStep, storage, exportGroup, exportMask, null, newInitiators, token);
foundASystemCreatedMask = true;
anyOperationsToDo = true;
}
}
}
}
if (!foundASystemCreatedMask) {
List<String> volumeURIsWithoutHLUs = ExportUtils.findVolumesWithoutHLUs(exportGroup);
if (!volumeURIsWithoutHLUs.isEmpty()) {
// will get consistent HLUs applied for their volumes
for (ExportMask exportMask : ExportMaskUtils.getExportMasks(_dbClient, exportGroup)) {
Map<URI, Integer> refreshedVolumeMap = device.getExportMaskHLUs(storage, exportMask);
if (!refreshedVolumeMap.isEmpty()) {
ExportUtils.reconcileHLUs(_dbClient, exportGroup, exportMask, volumeMap);
_dbClient.updateObject(exportGroup);
for (URI uri : refreshedVolumeMap.keySet()) {
Integer hlu = refreshedVolumeMap.get(uri);
if (volumeMap.containsKey(uri)) {
volumeMap.put(uri, hlu);
}
}
_log.info(String.format("ExportMask %s (%s) will be updated with these volumes %s", exportMask.getMaskName(), exportMask.getId(), CommonTransformerFunctions.collectionString(volumeMap.entrySet())));
// Do the reconciliation once, based on the first non-empty refreshedVolumeMap that's found
break;
}
}
}
_log.info("There are no masks for this export. Need to create anew.");
for (String host : hostInitiatorMap.keySet()) {
// Zoning is done for the new masks identified i.e. zoneNewMasksToVolumeMap.
GenExportMaskCreateWorkflowResult result = generateDeviceSpecificExportMaskCreateWorkFlow(workflow, previousStep, storage, exportGroup, hostInitiatorMap.get(host), volumeMap, token);
previousStep = result.getStepId();
zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
anyOperationsToDo = true;
}
}
}
if (anyOperationsToDo) {
if (!zoneNewMasksToVolumeMap.isEmpty()) {
List<URI> exportMaskList = new ArrayList<URI>();
exportMaskList.addAll(zoneNewMasksToVolumeMap.keySet());
Map<URI, Integer> overallVolumeMap = new HashMap<URI, Integer>();
for (Map<URI, Integer> oneVolumeMap : zoneNewMasksToVolumeMap.values()) {
overallVolumeMap.putAll(oneVolumeMap);
}
previousStep = generateDeviceSpecificZoningCreateWorkflow(workflow, previousStep, exportGroup, exportMaskList, overallVolumeMap);
}
if (!zoneMasksToInitiatorsURIs.isEmpty()) {
previousStep = generateDeviceSpecificZoningAddInitiatorsWorkflow(workflow, previousStep, exportGroup, zoneMasksToInitiatorsURIs);
}
String successMessage = String.format("Successfully exported to initiators on StorageArray %s", storage.getLabel());
workflow.executePlan(taskCompleter, successMessage);
} else {
_log.info("There were no operations to perform. Mask may already be in desired state.");
taskCompleter.ready(_dbClient);
}
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.
the class AbstractBasicMaskingOrchestrator method portRebalance.
@Override
public void portRebalance(URI storageSystem, URI exportGroupURI, URI varray, URI exportMaskURI, Map<URI, List<URI>> adjustedPaths, Map<URI, List<URI>> removedPaths, boolean isAdd, String token) throws Exception {
String workflowKey = "exportMaskExportPathAdjustment";
if (_workflowService.hasWorkflowBeenCreated(token, workflowKey)) {
return;
}
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), workflowKey, false, token);
ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
try {
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageSystem);
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
if (isAdd) {
Map<URI, List<URI>> newPaths = getNewPathsForExportMask(exportMask, adjustedPaths);
generateExportMaskAddPathsWorkflow(workflow, storage, exportGroupURI, exportMaskURI, newPaths, null);
} else {
generateExportMaskRemovePathsWorkflow(workflow, storage, exportGroupURI, exportMaskURI, adjustedPaths, removedPaths, null);
}
if (!workflow.getAllStepStatus().isEmpty()) {
_log.info("The port rebalance workflow has {} steps. Starting the workflow.", workflow.getAllStepStatus().size());
workflow.executePlan(taskCompleter, "Update the export group on all export masks successfully.");
_workflowService.markWorkflowBeenCreated(token, workflowKey);
} else {
taskCompleter.ready(_dbClient);
}
} catch (Exception ex) {
_log.error("ExportGroup port rebalance failed.", ex);
ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(ex.getMessage(), ex);
taskCompleter.error(_dbClient, serviceError);
}
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportOrchestrationTask in project coprhd-controller by CoprHD.
the class AbstractBasicMaskingOrchestrator method exportGroupRemoveVolumes.
@Override
public void exportGroupRemoveVolumes(URI storageURI, URI exportGroupURI, List<URI> volumeURIs, String token) throws Exception {
ExportOrchestrationTask taskCompleter = null;
try {
BlockStorageDevice device = getDevice();
taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
logExportGroup(exportGroup, storageURI);
String previousStep = null;
boolean generatedWorkFlowSteps = false;
if (!ExportMaskUtils.getExportMasks(_dbClient, exportGroup).isEmpty()) {
// Set up workflow steps.
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupRemoveVolumes", true, token);
List<ExportMask> exportMasksToZoneDelete = new ArrayList<ExportMask>();
List<ExportMask> exportMasksToZoneRemoveVolumes = new ArrayList<ExportMask>();
List<ExportMask> exportMasksToDelete = new ArrayList<ExportMask>();
List<URI> volumesToZoneRemoveVolumes = new ArrayList<URI>();
List<ExportMask> tempMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
for (ExportMask tempMask : tempMasks) {
_log.info(String.format("Checking mask %s", tempMask.getMaskName()));
if (!tempMask.getInactive() && tempMask.getStorageDevice().equals(storageURI)) {
tempMask = device.refreshExportMask(storage, tempMask);
// BlockStorageDevice level, so that it has up-to-date
// info from the array
Set<URI> volumesToRemove = new HashSet<URI>();
// If they specify to delete all volumes, we qualify to delete the whole mask.
// Otherwise, no chance of us deleting masks as part of this operation because
// each mask will still have at least one volume in it.
boolean removingLastVolumeFromMask = removingLastExportMaskVolumes(tempMask, new ArrayList<>(volumeURIs));
boolean anyVolumesFoundInAnotherExportGroup = false;
// check to see if the export mask has other initiators that aren't being removed.
for (URI egVolumeID : volumeURIs) {
String volumeIdStr = egVolumeID.toString();
BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, egVolumeID);
if (bo != null && tempMask.hasUserCreatedVolume(bo.getId())) {
if (exportGroup.getInitiators() != null) {
for (String initiatorIdStr : exportGroup.getInitiators()) {
if (tempMask.hasInitiator(initiatorIdStr)) {
// In here, we're looking at an initiator that is both in our export group and in the export
// mask we're looking at,
// so it needs further scrutiny. Is this combo in more than one export group? If so, leave it
// alone.
Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(initiatorIdStr));
List<ExportGroup> exportGroupList2 = ExportUtils.getInitiatorVolumeExportGroups(initiator, egVolumeID, _dbClient);
if (exportGroupList2 != null && exportGroupList2.size() > 1) {
_log.info(String.format("Found that my volume %s is in another export group with this initiator %s, so we shouldn't remove it from the mask", volumeIdStr, initiator.getInitiatorPort()));
anyVolumesFoundInAnotherExportGroup = true;
} else {
if (!volumesToRemove.contains(egVolumeID)) {
_log.info(String.format("We can remove volume %s from mask %s", volumeIdStr, tempMask.getMaskName()));
volumesToRemove.add(egVolumeID);
}
}
} else if (tempMask.getCreatedBySystem()) {
_log.info(String.format("Export Mask %s does not contain initiator %s, so we will not modify this export mask", tempMask.getId().toString(), initiatorIdStr));
} else {
// system.
if (!volumesToRemove.contains((egVolumeID))) {
_log.info(String.format("We can remove volume %s from mask %s", volumeIdStr, tempMask.getMaskName()));
volumesToRemove.add(egVolumeID);
}
}
}
}
} else {
_log.info(String.format("Export mask %s does not contain system-created volume %s, so it will not be removed from this export mask", tempMask.getId().toString(), volumeIdStr));
}
}
// Determine if we are removing the last volume from the ExportGroup
Map<URI, Integer> exportGroupVolumeMap = ExportUtils.getExportGroupVolumeMap(_dbClient, storage, exportGroup);
Set<URI> exportGroupVolumeURIs = exportGroupVolumeMap.keySet();
exportGroupVolumeURIs.removeAll(volumesToRemove);
boolean exportGroupHasMoreVolumes = !exportGroupVolumeURIs.isEmpty();
boolean exportMaskIsShared = ExportUtils.isExportMaskShared(_dbClient, tempMask.getId(), null);
List<URI> allExportMaskInitiators = ExportUtils.getExportMaskAllInitiators(tempMask, _dbClient);
_log.info(String.format("ExportMask %s(%s) - exportGroupHasMoreVolumes=%s exportMaskIsShared=%s " + "removingLastVolumeFromMask=%s anyVolumesFoundInAnotherExportGroup=%s", tempMask.getMaskName(), tempMask.getId(), exportGroupHasMoreVolumes, exportMaskIsShared, removingLastVolumeFromMask, anyVolumesFoundInAnotherExportGroup));
// Assume that we cannot delete the ExportMask
boolean canDeleteExportMask = false;
if (tempMask.getCreatedBySystem()) {
// We should only delete ViPR created ExportMasks
if (exportMaskIsShared) {
// Shared ExportMask, need to evaluate the volumes
if (!anyVolumesFoundInAnotherExportGroup && removingLastVolumeFromMask) {
// None of the volumes are being shared by another ExportGroup and
// we're removing the last volume from the ExportMask
canDeleteExportMask = true;
_log.info(String.format("ExportMask %s(%s) - Determined that this mask is shared, " + "but volumes are exclusive to the ExportGroup %s, so we can delete it", tempMask.getMaskName(), tempMask.getId(), exportGroup.getId()));
}
} else if (!anyVolumesFoundInAnotherExportGroup) {
// Evaluate the situation with the volumes
if (!exportGroupHasMoreVolumes && removingLastVolumeFromMask) {
// The remove will empty the ExportGroup or ExportMask of volumes
canDeleteExportMask = true;
_log.info(String.format("ExportMask %s(%s) - Determined that this mask is not shared and meets the criteria for deletion", tempMask.getMaskName(), tempMask.getId()));
}
} else {
_log.info("Checks have determined that the ExportMask %s(%s) should not be deleted", tempMask.getMaskName(), tempMask.getId());
}
}
if (canDeleteExportMask) {
_log.info(String.format("Determined that we can delete mask %s", tempMask.getMaskName()));
exportMasksToZoneDelete.add(tempMask);
exportMasksToDelete.add(tempMask);
generatedWorkFlowSteps = true;
} else {
// We have determined that we cannot delete the ExportMask. We have to determine if we
// should remove initiators or volumes
@SuppressWarnings("unchecked") List<URI> userAddedVolumes = (tempMask.getUserAddedVolumes() != null) ? StringSetUtil.stringSetToUriList(tempMask.getUserAddedVolumes().values()) : Collections.EMPTY_LIST;
userAddedVolumes.removeAll(volumesToRemove);
boolean removingAllUserAddedVolumes = userAddedVolumes.isEmpty();
boolean canRemoveVolumes = (!volumesToRemove.isEmpty() && !removingLastVolumeFromMask);
if (storage.getSystemType().equals(DiscoveredDataObject.Type.hds.name())) {
// Fix for COP-25152 as a part of COP-23625
/*
* Hitachi arrays can have HostStorageDomains (HSD's) without volumes associated with it.
* In case if the mask which was not created by VIPR and having no volumes has chosen for export,
* while un exporting if we even consider !removingLastVolumeFromMask condition the export mask will
* not be deleted (since it was not created by VIPR) and the lun path continue to be exist.
*/
canRemoveVolumes = !volumesToRemove.isEmpty();
}
_log.info(String.format("ExportMask %s(%s) - canRemoveVolumes=%s " + "allExportMaskInitiators=%d removingLastVolumeFromMask=%s removingAllUserAddedVolumes=%s", tempMask.getMaskName(), tempMask.getId(), canRemoveVolumes, allExportMaskInitiators.size(), removingLastVolumeFromMask, removingAllUserAddedVolumes));
if (canRemoveVolumes) {
// If we got here it means that:
// -- ExportMask was not created by ViPR
// -- We're not dealing with a subset of initiators for the ExportMask
// Then we will just schedule the removal of the volumes
_log.info(String.format("Determined that we can remove volumes from mask %s (%s): %s", tempMask.getMaskName(), tempMask.getId(), CommonTransformerFunctions.collectionString(volumesToRemove)));
exportMasksToZoneRemoveVolumes.add(tempMask);
volumesToZoneRemoveVolumes.addAll(volumesToRemove);
List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, tempMask, null), CommonTransformerFunctions.fctnDataObjectToID()));
List<URI> volumesToRemoveList = new ArrayList<>();
volumesToRemoveList.addAll(volumesToRemove);
previousStep = generateDeviceSpecificExportMaskRemoveVolumesWorkflow(workflow, previousStep, exportGroup, tempMask, storage, volumesToRemoveList, maskInitiatorURIs, null);
generatedWorkFlowSteps = true;
}
}
}
}
if (!exportMasksToDelete.isEmpty()) {
for (ExportMask exportMaskToDelete : exportMasksToDelete) {
_log.info("generating workflow to remove exportmask {}", exportMaskToDelete.getMaskName());
List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(exportMaskToDelete);
List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMaskToDelete, null), CommonTransformerFunctions.fctnDataObjectToID()));
previousStep = generateDeviceSpecificExportMaskDeleteWorkflow(workflow, previousStep, exportGroup, exportMaskToDelete, maskVolumeURIs, maskInitiatorURIs, storage);
}
}
if (!exportMasksToZoneRemoveVolumes.isEmpty()) {
_log.info("generating workflow for exportmask to zoneRemoveVolumes.");
// Remove all the indicated volumes from the indicated export masks.
previousStep = generateDeviceSpecificZoningRemoveVolumesWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneRemoveVolumes, volumesToZoneRemoveVolumes);
}
if (!exportMasksToZoneDelete.isEmpty()) {
_log.info("generating workflow to remove all zones in exportmask");
// Add the zone ExportMask delete operations
previousStep = generateDeviceSpecificZoningDeleteWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneDelete);
}
if (generatedWorkFlowSteps) {
// Add a task to clean up the export group when the export masks remove their volumes
previousStep = generateDeviceSpecificExportGroupRemoveVolumesCleanup(workflow, previousStep, storage, exportGroup, volumeURIs, null);
}
String successMessage = String.format("Successfully removed volumes from export on StorageArray %s", storage.getLabel());
workflow.executePlan(taskCompleter, successMessage);
}
if (!generatedWorkFlowSteps) {
taskCompleter.ready(_dbClient);
}
} catch (Exception ex) {
_log.error("ExportGroup Orchestration failed.", ex);
// TODO add service code here
if (taskCompleter != null) {
ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(ex.getMessage(), ex);
taskCompleter.error(_dbClient, serviceError);
}
}
}
Aggregations