use of com.emc.storageos.svcs.errorhandling.model.ServiceError in project coprhd-controller by CoprHD.
the class FileOrchestrationDeviceController method addStepsToReplicateDirectoryQuotaSettings.
/**
* Child workflow for replicating source file system directory quota settings to target system.
*
* @param systemTarget
* - URI of target StorageSystem where source quota directory settings have to be replicated.
* @param fsURI
* -URI of the source FileSystem
* @param taskId
*/
public void addStepsToReplicateDirectoryQuotaSettings(URI systemTarget, URI fsURI, String taskId) {
s_logger.info("Generating steps for replicating directory quota settings to target cluster.");
FileWorkflowCompleter completer = new FileWorkflowCompleter(fsURI, taskId);
FileShare targetFileShare = null;
Workflow workflow = null;
try {
FileShare sourceFileShare = s_dbClient.queryObject(FileShare.class, fsURI);
if (sourceFileShare.getPersonality().equals(PersonalityTypes.SOURCE.name())) {
List<String> targetfileUris = new ArrayList<String>();
targetfileUris.addAll(sourceFileShare.getMirrorfsTargets());
targetFileShare = s_dbClient.queryObject(FileShare.class, URI.create(targetfileUris.get(0)));
} else {
targetFileShare = s_dbClient.queryObject(FileShare.class, sourceFileShare.getParentFileShare());
}
targetFileShare.setSoftGracePeriod(sourceFileShare.getSoftGracePeriod());
targetFileShare.setSoftLimit(sourceFileShare.getSoftLimit());
targetFileShare.setNotificationLimit(sourceFileShare.getNotificationLimit());
s_dbClient.updateObject(targetFileShare);
workflow = this._workflowService.getNewWorkflow(this, REPLICATE_QUOTA_DIR_SETTINGS_TO_TARGET_WF_NAME, false, taskId, completer);
updateTargetFileSystem(workflow, systemTarget, targetFileShare);
String successMessage = String.format("Replicating source file system : %s, directory quota settings to target file system finished successfully.", sourceFileShare.getLabel());
workflow.executePlan(completer, successMessage);
} catch (Exception ex) {
s_logger.error("Could not replicate source filesystem directory quota settings: " + fsURI, ex);
String opName = ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_FAILOVER.getName();
ServiceError serviceError = DeviceControllerException.errors.unableToUpdateFileSystem(opName, ex);
completer.error(s_dbClient, this._locker, serviceError);
}
}
use of com.emc.storageos.svcs.errorhandling.model.ServiceError in project coprhd-controller by CoprHD.
the class FileOrchestrationDeviceController method createFileSystems.
/*
* (non-Javadoc)
*
* @see com.emc.storageos.fileorchestrationcontroller.FileOrchestrationController#createFileSystems(java.util.List,
* java.lang.String)
*/
/**
* Creates one or more filesystem
* (FileShare, FileMirroring). This method is responsible for creating
* a Workflow and invoking the FileOrchestrationInterface.addStepsForCreateFileSystems
*
* @param fileDescriptors
* @param taskId
* @throws ControllerException
*/
@Override
public void createFileSystems(List<FileDescriptor> fileDescriptors, String taskId) throws ControllerException {
// Generate the Workflow.
Workflow workflow = null;
List<URI> fsUris = FileDescriptor.getFileSystemURIs(fileDescriptors);
FileCreateWorkflowCompleter completer = new FileCreateWorkflowCompleter(fsUris, taskId, fileDescriptors);
try {
// Generate the Workflow.
workflow = _workflowService.getNewWorkflow(this, CREATE_FILESYSTEMS_WF_NAME, false, taskId);
// the wait for key returned by previous call
String waitFor = null;
s_logger.info("Generating steps for create FileSystem");
// First, call the FileDeviceController to add its methods.
waitFor = _fileDeviceController.addStepsForCreateFileSystems(workflow, waitFor, fileDescriptors, taskId);
// second, check for policies that has to applied on this file system..
waitFor = addStepsForApplyingPolicies(workflow, waitFor, fileDescriptors);
// Finish up and execute the plan.
// The Workflow will handle the TaskCompleter
String successMessage = "Create filesystems successful for: " + fsUris.toString();
Object[] callbackArgs = new Object[] { fsUris };
workflow.executePlan(completer, successMessage, new WorkflowCallback(), callbackArgs, null, null);
} catch (Exception ex) {
s_logger.error("Could not create filesystems: " + fsUris, ex);
releaseWorkflowLocks(workflow);
String opName = ResourceOperationTypeEnum.CREATE_FILE_SYSTEM.getName();
ServiceError serviceError = DeviceControllerException.errors.createFileSharesFailed(fsUris.toString(), opName, ex);
completer.error(s_dbClient, _locker, serviceError);
}
}
use of com.emc.storageos.svcs.errorhandling.model.ServiceError in project coprhd-controller by CoprHD.
the class AbstractBasicMaskingOrchestrator method exportGroupCreate.
/**
* Create storage level masking components to support the requested
* ExportGroup object. This operation will be flexible enough to take into
* account initiators that are in some already existent in some
* StorageGroup. In such a case, the underlying masking component will be
* "adopted" by the ExportGroup. Further operations against the "adopted"
* mask will only allow for addition and removal of those initiators/volumes
* that were added by a Bourne request. Existing initiators/volumes will be
* maintained.
*
* @param storageURI - URI referencing underlying storage array
* @param exportGroupURI - URI referencing Bourne-level masking, ExportGroup
* @param initiatorURIs - List of Initiator URIs
* @param volumeMap - Map of Volume URIs to requested Integer URI
* @param token - Identifier for operation
* @throws Exception
*/
@Override
public void exportGroupCreate(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, Map<URI, Integer> volumeMap, String token) throws Exception {
ExportOrchestrationTask taskCompleter = null;
try {
BlockStorageDevice device = getDevice();
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
logExportGroup(exportGroup, storageURI);
if (initiatorURIs != null && !initiatorURIs.isEmpty()) {
_log.info("export_create: initiator list non-empty");
// Set up workflow steps.
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupCreate", true, token);
// 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.)
String zoningStep = generateDeviceSpecificZoningCreateWorkflow(workflow, null, exportGroup, null, volumeMap);
boolean createdSteps = determineExportGroupCreateSteps(workflow, zoningStep, device, storage, exportGroup, initiatorURIs, volumeMap, false, token);
if (createdSteps) {
// Execute the plan and allow the WorkflowExecutor to fire the
// taskCompleter.
String successMessage = String.format("ExportGroup successfully applied for StorageArray %s", storage.getLabel());
workflow.executePlan(taskCompleter, successMessage);
} else {
_log.info("export_create: no steps created");
taskCompleter.ready(_dbClient);
}
} else {
_log.info("export_create: initiator list empty, no steps to create");
taskCompleter.ready(_dbClient);
}
} catch (DeviceControllerException dex) {
if (taskCompleter != null) {
taskCompleter.error(_dbClient, DeviceControllerException.errors.vmaxExportGroupCreateError(dex.getMessage()));
}
} 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);
}
}
}
use of com.emc.storageos.svcs.errorhandling.model.ServiceError in project coprhd-controller by CoprHD.
the class AbstractBasicMaskingOrchestrator method exportGroupRemoveInitiators.
@Override
public void exportGroupRemoveInitiators(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, 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);
StringBuffer errorMessage = new StringBuffer();
logExportGroup(exportGroup, storageURI);
// Set up workflow steps.
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupRemoveInitiators", true, token);
Initiator firstInitiator = _dbClient.queryObject(Initiator.class, initiatorURIs.get(0));
// No need to validate the orchestrator level validation for vplex/rp. Hence ignoring validation for vplex/rp initiators.
boolean isValidationNeeded = validatorConfig.isValidationEnabled() && !VPlexControllerUtils.isVplexInitiator(firstInitiator, _dbClient) && !ExportUtils.checkIfInitiatorsForRP(Arrays.asList(firstInitiator));
_log.info("Orchestration level validation needed : {}", isValidationNeeded);
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);
// Populate a map of volumes on the storage device associated with this ExportGroup
List<BlockObject> blockObjects = new ArrayList<BlockObject>();
if (exportGroup.getVolumes() != null) {
for (Map.Entry<String, String> entry : exportGroup.getVolumes().entrySet()) {
URI boURI = URI.create(entry.getKey());
BlockObject bo = BlockObject.fetch(_dbClient, boURI);
if (bo.getStorageController().equals(storageURI)) {
blockObjects.add(bo);
}
}
}
List<String> initiatorNames = new ArrayList<String>();
for (URI initiatorURI : initiatorURIs) {
Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
String normalizedName = Initiator.normalizePort(initiator.getInitiatorPort());
initiatorNames.add(normalizedName);
}
_log.info("Normalized initiator names :{}", initiatorNames);
device.findExportMasks(storage, initiatorNames, false);
Map<URI, Boolean> initiatorIsPartOfFullListFlags = flagInitiatorsThatArePartOfAFullList(exportGroup, initiatorURIs);
boolean anyOperationsToDo = false;
if (exportGroup != null && !ExportMaskUtils.getExportMasks(_dbClient, exportGroup).isEmpty()) {
// There were some exports out there that already have some or all of the
// initiators that we are attempting to remove. We need to only
// remove the volumes that the user added to these masks
Map<String, Set<URI>> matchingExportMaskURIs = getInitiatorToExportMaskMap(exportGroup);
// This loop will determine a list of volumes to update per export mask
Map<URI, List<URI>> existingMasksToRemoveInitiator = new HashMap<URI, List<URI>>();
Map<URI, List<URI>> existingMasksToRemoveVolumes = new HashMap<URI, List<URI>>();
for (Map.Entry<String, Set<URI>> entry : matchingExportMaskURIs.entrySet()) {
URI initiatorURI = portNameToInitiatorURI.get(entry.getKey());
if (initiatorURI == null || !initiatorURIs.contains(initiatorURI)) {
// Entry key points to an initiator that was not passed in the remove request
continue;
}
Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
// Get a list of the ExportMasks that were matched to the initiator
// go through the initiators and figure out the proper intiator and volume ramifications
// to the existing masks.
List<URI> exportMaskURIs = new ArrayList<URI>();
exportMaskURIs.addAll(entry.getValue());
List<ExportMask> masks = _dbClient.queryObject(ExportMask.class, exportMaskURIs);
_log.info(String.format("initiator %s masks {%s}", initiator.getInitiatorPort(), Joiner.on(',').join(exportMaskURIs)));
for (ExportMask mask : masks) {
if (mask == null || mask.getInactive() || !mask.getStorageDevice().equals(storageURI)) {
continue;
}
mask = getDevice().refreshExportMask(storage, mask);
_log.info(String.format("mask %s has initiator %s", mask.getMaskName(), initiator.getInitiatorPort()));
// We cannot remove initiator if there are existing volumes in the mask.
if (!isValidationNeeded || !mask.hasAnyExistingVolumes()) {
/**
* If user asked to remove Host from Cluster
* 1. Check if the export mask is shared across other export Groups, if not remove the host.
* 2. If shared, check whether all the initiators of host is being asked to remove
* 3. If yes, check if atleast one of the other shared export Group is EXCLUSIVE
* 4. If yes, then remove the shared volumes
*
* In all other cases, remove the initiators.
*/
List<ExportGroup> otherExportGroups = ExportUtils.getOtherExportGroups(exportGroup, mask, _dbClient);
if (!otherExportGroups.isEmpty() && initiatorIsPartOfFullListFlags.get(initiatorURI) && ExportUtils.exportMaskHasBothExclusiveAndSharedVolumes(exportGroup, otherExportGroups, mask)) {
if (!exportGroup.forInitiator()) {
List<URI> removeVolumesList = existingMasksToRemoveVolumes.get(mask.getId());
if (removeVolumesList == null) {
removeVolumesList = new ArrayList<URI>();
existingMasksToRemoveVolumes.put(mask.getId(), removeVolumesList);
}
for (String volumeIdStr : exportGroup.getVolumes().keySet()) {
URI egVolumeID = URI.create(volumeIdStr);
if (mask.getUserAddedVolumes().containsValue(volumeIdStr) && !removeVolumesList.contains(egVolumeID)) {
removeVolumesList.add(egVolumeID);
}
}
} else {
// Just a reminder to the world in the case where Initiator is used in this odd situation.
_log.info("Removing volumes from an Initiator type export group as part of an initiator removal is not supported.");
}
} else {
_log.info(String.format("We can remove initiator %s from mask %s", initiator.getInitiatorPort(), mask.getMaskName()));
List<URI> initiators = existingMasksToRemoveInitiator.get(mask.getId());
if (initiators == null) {
initiators = new ArrayList<URI>();
existingMasksToRemoveInitiator.put(mask.getId(), initiators);
}
if (!initiators.contains(initiator.getId())) {
initiators.add(initiator.getId());
}
}
} else {
errorMessage.append(String.format("Mask %s has existing volumes %s", mask.forDisplay(), Joiner.on(", ").join(mask.getExistingVolumes().keySet())));
}
}
}
// At this point we have a mapping of masks to objects that we want to remove
Set<URI> masksGettingRemoved = new HashSet<URI>();
// In this loop we are trying to remove those initiators that exist
// on a mask that ViPR created.
Map<URI, String> stepMap = new HashMap<URI, String>();
for (Map.Entry<URI, List<URI>> entry : existingMasksToRemoveInitiator.entrySet()) {
ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
List<URI> initiatorsToRemove = entry.getValue();
Set<String> allInitiators = ExportUtils.getExportMaskAllInitiatorPorts(mask, _dbClient);
List<Initiator> initiatorObjectsToRemove = _dbClient.queryObject(Initiator.class, initiatorsToRemove);
List<String> initiatorPortNamesToRemove = new ArrayList<>(Collections2.transform(initiatorObjectsToRemove, CommonTransformerFunctions.fctnInitiatorToPortName()));
allInitiators.removeAll(initiatorPortNamesToRemove);
if (allInitiators.isEmpty()) {
masksGettingRemoved.add(mask.getId());
// For this case, we are attempting to remove all the
// initiators in the mask. This means that we will have to
// delete the
// exportGroup
_log.info(String.format("mask %s has removed all " + "initiators, we are going to delete the mask from the " + "array", mask.getMaskName()));
List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(mask);
List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, mask, null), CommonTransformerFunctions.fctnDataObjectToID()));
stepMap.put(entry.getKey(), generateDeviceSpecificDeleteWorkflow(workflow, null, exportGroup, mask, maskVolumeURIs, maskInitiatorURIs, storage));
anyOperationsToDo = true;
} else {
_log.info(String.format("mask %s - going to remove the " + "following initiators %s", mask.getMaskName(), Joiner.on(',').join(initiatorsToRemove)));
Map<URI, List<URI>> maskToInitiatorsMap = new HashMap<URI, List<URI>>();
maskToInitiatorsMap.put(mask.getId(), initiatorsToRemove);
List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(mask);
stepMap.put(entry.getKey(), generateDeviceSpecificRemoveInitiatorsWorkflow(workflow, null, exportGroup, mask, storage, maskToInitiatorsMap, maskVolumeURIs, initiatorsToRemove, true));
anyOperationsToDo = true;
}
}
// for the storage array and ExportGroup.
for (Map.Entry<URI, List<URI>> entry : existingMasksToRemoveVolumes.entrySet()) {
if (masksGettingRemoved.contains(entry.getKey())) {
_log.info("Mask {} is getting removed, no need to remove volumes from it", entry.getKey().toString());
continue;
}
ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
List<URI> volumesToRemove = entry.getValue();
List<URI> initiatorsToRemove = existingMasksToRemoveInitiator.get(mask.getId());
if (initiatorsToRemove != null) {
List<URI> initiatorsInExportMask = ExportUtils.getExportMaskAllInitiators(mask, _dbClient);
initiatorsInExportMask.removeAll(initiatorsToRemove);
if (!initiatorsInExportMask.isEmpty()) {
// There are still some initiators in this ExportMask
_log.info(String.format("ExportMask %s would have remaining initiators {%s} that require access to {%s}. " + "Not going to remove any of the volumes", mask.getMaskName(), Joiner.on(',').join(initiatorsInExportMask), Joiner.on(',').join(volumesToRemove)));
continue;
}
}
Collection<String> volumesToRemoveURIStrings = Collections2.transform(volumesToRemove, CommonTransformerFunctions.FCTN_URI_TO_STRING);
List<String> exportMaskVolumeURIStrings = new ArrayList<String>(mask.getVolumes().keySet());
exportMaskVolumeURIStrings.removeAll(volumesToRemoveURIStrings);
if (exportMaskVolumeURIStrings.isEmpty() && !mask.hasAnyExistingVolumes()) {
_log.info(String.format("All the volumes (%s) from mask %s will be removed, so will have to remove the whole mask", Joiner.on(",").join(volumesToRemove), mask.getMaskName()));
errorMessage.append(String.format("Mask %s will be removed from array. ", mask.forDisplay()));
List<URI> maskVolumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(mask);
List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, mask, null), CommonTransformerFunctions.fctnDataObjectToID()));
generateDeviceSpecificDeleteWorkflow(workflow, null, exportGroup, mask, maskVolumeURIs, maskInitiatorURIs, storage);
anyOperationsToDo = true;
} else {
// Null taskID is passed in because the generateExportMaskRemoveVolumesWorkflow will fill it in
ExportTaskCompleter completer = new ExportRemoveVolumesOnAdoptedMaskCompleter(exportGroupURI, mask.getId(), volumesToRemove, null);
_log.info(String.format("A subset of volumes will be removed from mask %s: %s. ", mask.getMaskName(), Joiner.on(",").join(volumesToRemove)));
List<? extends BlockObject> boList = BlockObject.fetchAll(_dbClient, volumesToRemove);
if (mask.hasAnyExistingInitiators()) {
errorMessage.append(String.format("A subset of volumes will be removed from mask %s: %s. This will affect the %s initiators", mask.getMaskName(), Joiner.on(", ").join(Collections2.transform(boList, CommonTransformerFunctions.fctnDataObjectToForDisplay())), mask.getExistingInitiators()));
}
List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, mask, null), CommonTransformerFunctions.fctnDataObjectToID()));
generateDeviceSpecificRemoveVolumesWorkflow(workflow, stepMap.get(entry.getKey()), exportGroup, mask, storage, volumesToRemove, maskInitiatorURIs, completer);
anyOperationsToDo = true;
}
}
}
if (errorMessage != null && !errorMessage.toString().isEmpty()) {
_log.warn("Error Message {}", errorMessage);
}
if (isValidationNeeded && StringUtils.hasText(errorMessage)) {
throw DeviceControllerException.exceptions.removeInitiatorValidationError(Joiner.on(", ").join(initiatorNames), storage.getLabel(), errorMessage.toString());
}
if (anyOperationsToDo) {
String successMessage = String.format("Successfully removed exports for initiators on StorageArray %s", storage.getLabel());
workflow.executePlan(taskCompleter, successMessage);
} else {
taskCompleter.ready(_dbClient);
}
} catch (Exception e) {
_log.error("ExportGroup remove initiator Orchestration failed.", e);
// TODO add service code here
if (taskCompleter != null) {
ServiceError serviceError = DeviceControllerException.errors.jobFailedMsg(e.getMessage(), e);
taskCompleter.error(_dbClient, serviceError);
}
}
}
use of com.emc.storageos.svcs.errorhandling.model.ServiceError in project coprhd-controller by CoprHD.
the class AbstractBasicMaskingOrchestrator method exportGroupDelete.
@Override
public void exportGroupDelete(URI storageURI, URI exportGroupURI, String token) throws Exception {
ExportOrchestrationTask taskCompleter = null;
try {
taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
String previousStep = null;
boolean someOperationDone = false;
logExportGroup(exportGroup, storageURI);
if (!ExportMaskUtils.getExportMasks(_dbClient, exportGroup).isEmpty() && !exportGroup.getInactive()) {
// Set up workflow steps.
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupDelete", true, token);
List<ExportMask> exportMasksToZoneDelete = new ArrayList<ExportMask>();
List<ExportMask> exportMasksToZoneRemoveVolumes = new ArrayList<ExportMask>();
Set<URI> volumesToZoneRemoveVolumes = new HashSet<URI>();
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
for (ExportMask exportMask : exportMasks) {
taskCompleter.setMask(exportMask.getId());
_log.info(String.format("Checking mask %s", exportMask.getMaskName()));
if (!exportMask.getInactive() && exportMask.getStorageDevice().equals(storageURI)) {
exportMask = getDevice().refreshExportMask(storage, exportMask);
Collection<URI> volumeURIs = Collections2.transform(exportGroup.getVolumes().keySet(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
// One way to know if we should delete the mask is if all of the volumes in the mask
// are represented in the export group.
boolean deleteEntireMask = removingLastExportMaskVolumes(exportMask, new ArrayList<>(volumeURIs));
_log.info("deleteEntireMask for {}? {}", exportMask.getId(), deleteEntireMask);
Set<URI> volumesToRemove = new HashSet<>();
if (exportGroup.getInitiators() != null && !exportGroup.getInitiators().isEmpty()) {
Set<String> egInitiators = new HashSet<String>(exportGroup.getInitiators());
for (String initiatorIdStr : egInitiators) {
Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(initiatorIdStr));
if (initiator == null) {
_log.warn("Found that initiator " + initiatorIdStr + " in the export group is no longer in the database, removing from the initiator list.");
exportGroup.removeInitiator(URI.create(initiatorIdStr));
_dbClient.updateObject(exportGroup);
continue;
}
// Search for this initiator in another export group
List<ExportGroup> exportGroupList = ExportUtils.getInitiatorExportGroups(initiator, _dbClient);
// We cannot remove initiator from mask if the mask has existing volumes
if (exportMask.hasUserInitiator(URI.create(initiatorIdStr)) && !exportMask.hasAnyExistingVolumes()) {
// Best to just leave that initiator alone.
if ((exportGroupList != null && exportGroupList.size() > 1) && ExportUtils.isExportMaskShared(_dbClient, exportMask.getId(), null)) {
_log.info(String.format("Found that my initiator is in %s more export groups, so we shouldn't remove it from the mask", exportGroupList.size() - 1));
deleteEntireMask = false;
}
}
}
}
if (deleteEntireMask) {
_log.info(String.format("export_delete: export mask %s was either created by system or last volume is being removed.", exportMask.getMaskName()));
exportMasksToZoneDelete.add(exportMask);
someOperationDone = true;
} else {
// Volume removal -- check to see if that volume is already in another export group with that initiator.
for (String volumeIdStr : exportGroup.getVolumes().keySet()) {
URI egVolumeID = URI.create(volumeIdStr);
BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, egVolumeID);
if (bo != null && exportMask.hasUserCreatedVolume(bo.getId())) {
if (exportGroup.getInitiators() != null) {
for (String initiatorIdStr : exportGroup.getInitiators()) {
if (exportMask.hasInitiator(initiatorIdStr)) {
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()));
} else {
_log.info(String.format("We can remove volume %s from mask %s", volumeIdStr, exportMask.getMaskName()));
volumesToRemove.add(egVolumeID);
}
} else if (exportMask.getCreatedBySystem()) {
_log.info(String.format("Export Mask %s does not contain initiator %s, so we will not modify this export mask", exportMask.getId().toString(), initiatorIdStr));
} else {
// We're in a case where there are no user added initiators for this *existing* mask. So, we
// should be able remove any
// of the volumes that we added to the system.
volumesToRemove.add(egVolumeID);
}
}
}
}
}
// Remove volume steps are generated based on the initiators we collected for removal.
if (!volumesToRemove.isEmpty()) {
_log.info(String.format("Mask %s, Removing volumes %s only", exportMask.getMaskName(), Joiner.on(',').join(volumesToRemove)));
_log.info(String.format("volumes in mask: %s", Joiner.on(',').join(exportMask.getVolumes().entrySet())));
exportMasksToZoneRemoveVolumes.add(exportMask);
volumesToZoneRemoveVolumes.addAll(volumesToRemove);
List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null), CommonTransformerFunctions.fctnDataObjectToID()));
previousStep = generateDeviceSpecificRemoveVolumesWorkflow(workflow, previousStep, exportGroup, exportMask, storage, new ArrayList<URI>(volumesToRemove), maskInitiatorURIs, null);
someOperationDone = true;
}
}
}
}
if (!exportMasksToZoneDelete.isEmpty()) {
for (ExportMask exportMask : exportMasksToZoneDelete) {
List<URI> volumeURIs = ExportMaskUtils.getUserAddedVolumeURIs(exportMask);
List<URI> maskInitiatorURIs = Lists.newArrayList(Collections2.transform(ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null), CommonTransformerFunctions.fctnDataObjectToID()));
previousStep = generateDeviceSpecificExportMaskDeleteWorkflow(workflow, previousStep, exportGroup, exportMask, volumeURIs, maskInitiatorURIs, storage);
}
// CTRL-8506 - VNX StorageGroup cannot be deleted because of a race condition with
// the zoning. This is a live host test case. So, some initiators are still logged
// in by the time ViPR tries to delete the StorageGroup.
// General Solution:
// When we have to delete ExportMask, we'll un-zone first so that any initiators
// that are possibly logged into the array get a chance to log out. That way, there
// should not be any problems with removing the ExportMask off the array.
//
// COP-24183: Reversing the order with serialization to prevent DU if mask validation fails.
previousStep = generateDeviceSpecificZoningDeleteWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneDelete);
}
if (!exportMasksToZoneRemoveVolumes.isEmpty()) {
// Remove all the indicated volumes from the indicated
// export masks.
generateDeviceSpecificZoningRemoveVolumesWorkflow(workflow, previousStep, exportGroup, exportMasksToZoneRemoveVolumes, new ArrayList<URI>(volumesToZoneRemoveVolumes));
}
String successMessage = String.format("Successfully removed export on StorageArray %s", storage.getLabel());
workflow.executePlan(taskCompleter, successMessage);
}
if (!someOperationDone) {
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