use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackMigrateVirtualVolume.
/**
* Called when a migration cannot be created and started or the data
* migration is terminated prior to completing successfully. The function
* tries to cancel the migration and cleanup the remnants of the migration
* on the VPLEX.
*
* @param vplexURI
* The URI of the VPLex storage system.
* @param migrationURI
* The URI of the migration.
* @param migrateStepId
* The migration step id.
* @param stepId
* The rollback step id.
* @throws WorkflowException
*/
public void rollbackMigrateVirtualVolume(URI vplexURI, URI migrationURI, String migrateStepId, String stepId) throws WorkflowException {
Migration migration = null;
String migrationVolumeLabel = null;
try {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Was the migration created and started? If so, then
// we'll try and cancel the migration and clean up.
// Otherwise, there is nothing to do.
Boolean migrationStarted = (Boolean) _workflowService.loadStepData(migrateStepId);
if (!migrationStarted.booleanValue()) {
// The migration was not successfully started.
WorkflowStepCompleter.stepSucceded(stepId);
return;
}
// Get the migration.
migration = _dbClient.queryObject(Migration.class, migrationURI);
// Get the VPLEX volume for the migration.
Volume migrationVolume = _dbClient.queryObject(Volume.class, migration.getVolume());
if (migrationVolume != null) {
migrationVolumeLabel = migrationVolume.getLabel();
}
// cancel it now.
if (!VPlexMigrationInfo.MigrationStatus.CANCELLED.getStatusValue().equals(migration.getMigrationStatus())) {
_log.info("Cancel migration {}", migrationURI);
// Get the VPlex API client.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
_log.info("Got VPlex API client for VPlex {}", vplexURI);
// Try to cancel the migration and cleanup and remove any
// remnants of the migration.
client.cancelMigrations(Arrays.asList(migration.getLabel()), true, true);
_log.info("Migration cancelled");
}
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
// Do not allow rollback to go any further COP-21257
_workflowService.setWorkflowRollbackContOnError(stepId, false);
_log.error("Error during rollback of start migration: {}", vae.getMessage(), vae);
if (migration != null) {
setOrClearVolumeInternalFlag(migration.getVolume(), true);
vae = VPlexApiException.exceptions.migrationRollbackFailureContactEMC(migration.getVolume().toString(), migrationVolumeLabel, migration.getLabel());
}
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception e) {
_log.error("Error during rollback of start migration: {}", e.getMessage());
// Do not allow rollback to go any further COP-21257
_workflowService.setWorkflowRollbackContOnError(stepId, false);
if (migration != null) {
setOrClearVolumeInternalFlag(migration.getVolume(), true);
e = VPlexApiException.exceptions.migrationRollbackFailureContactEMC(migration.getVolume().toString(), migrationVolumeLabel, migration.getLabel());
}
WorkflowStepCompleter.stepFailed(stepId, VPlexApiException.exceptions.rollbackMigrateVolume(migrationURI.toString(), e));
}
}
use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method exportGroupAddVolumes.
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportAddVolume(java.net.URI, java.net.URI,
* java.net.URI,
* java.lang.Integer, java.lang.String)
*/
@Override
public void exportGroupAddVolumes(URI vplexURI, URI exportURI, Map<URI, Integer> volumeMap, String opId) throws ControllerException {
String volListStr = "";
ExportAddVolumeCompleter completer = null;
try {
WorkflowStepCompleter.stepExecuting(opId);
completer = new ExportAddVolumeCompleter(exportURI, volumeMap, opId);
volListStr = Joiner.on(',').join(volumeMap.keySet());
Workflow workflow = _workflowService.getNewWorkflow(this, "exportGroupAddVolumes", true, opId);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportURI);
StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, vplexURI);
URI srcVarray = exportGroup.getVirtualArray();
boolean isRecoverPointExport = ExportUtils.checkIfInitiatorsForRP(_dbClient, exportGroup.getInitiators());
if (!exportGroup.hasInitiators()) {
// VPLEX API restricts adding volumes before initiators
VPlexApiException.exceptions.cannotAddVolumesToExportGroupWithoutInitiators(exportGroup.forDisplay());
}
// Determine whether this export will be done across both VPLEX clusters,
// or just the src or ha varray.
// We get a map of varray to the volumes that can be exported in each varray.
Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplexURI, exportGroup);
// Put the srcVolumes in their own set, and remove the src varray from the varrayToVolumes map.
Set<URI> srcVolumes = varrayToVolumes.get(srcVarray);
varrayToVolumes.remove(srcVarray);
URI haVarray = null;
// and we're not exporting to recover point initiators
if (!varrayToVolumes.isEmpty() && !isRecoverPointExport) {
if (exportGroup.hasAltVirtualArray(vplexURI.toString())) {
// If we've already chosen an haVarray, go with with the choice
haVarray = URI.create(exportGroup.getAltVirtualArrays().get(vplexURI.toString()));
} else {
// Otherwise we will make sure there is only one HA varray and persist it.
haVarray = VPlexUtil.pickHAVarray(varrayToVolumes);
}
}
// Partition the initiators by varray into varrayToInitiators map.
List<URI> varrayURIs = new ArrayList<URI>();
varrayURIs.add(exportGroup.getVirtualArray());
if (haVarray != null) {
varrayURIs.add(haVarray);
}
List<URI> exportGroupInitiatorList = StringSetUtil.stringSetToUriList(exportGroup.getInitiators());
Map<URI, List<URI>> varrayToInitiators = VPlexUtil.partitionInitiatorsByVarray(_dbClient, exportGroupInitiatorList, varrayURIs, vplexSystem);
if (varrayToInitiators.isEmpty()) {
throw VPlexApiException.exceptions.exportCreateNoinitiatorsHaveCorrectConnectivity(exportGroup.getInitiators().toString(), varrayURIs.toString());
}
findAndUpdateFreeHLUsForClusterExport(vplexSystem, exportGroup, exportGroupInitiatorList, volumeMap);
// Check if Zoning needs to be checked from system config
// call the doZoneExportMasksCreate to check/create/remove zones with the flag
String addZoneWhileAddingVolume = customConfigHandler.getComputedCustomConfigValue(CustomConfigConstants.ZONE_ADD_VOLUME, CustomConfigConstants.GLOBAL_KEY, null);
// Default behavior is we allow zoning checks against the Network System
Boolean addZoneOnDeviceOperation = true;
_log.info("zoneExportAddVolumes checking for custom config value {} to skip zoning checks : (Default) : {}", addZoneWhileAddingVolume, addZoneOnDeviceOperation);
if (addZoneWhileAddingVolume != null) {
addZoneOnDeviceOperation = Boolean.valueOf(addZoneWhileAddingVolume);
_log.info("Boolean convereted of : {} : returned by Config handler as : {} ", addZoneWhileAddingVolume, addZoneOnDeviceOperation);
} else {
_log.info("Config handler returned null for value so going by default value {}", addZoneOnDeviceOperation);
}
_log.info("zoneExportAddVolumes checking for custom config value {} to skip zoning checks : (Custom Config) : {}", addZoneWhileAddingVolume, addZoneOnDeviceOperation);
// Add all the volumes to the SRC varray if there are src side volumes and
// initiators that have connectivity to the source side.
String srcExportStepId = null;
if (varrayToInitiators.get(srcVarray) != null && srcVolumes != null) {
srcExportStepId = assembleExportMasksWorkflow(vplexURI, exportURI, srcVarray, varrayToInitiators.get(srcVarray), ExportMaskUtils.filterVolumeMap(volumeMap, srcVolumes), addZoneOnDeviceOperation, workflow, null, opId);
}
// and there are volumes to be added to the ha varray, do so.
if (haVarray != null && varrayToInitiators.get(haVarray) != null && varrayToVolumes.get(haVarray) != null) {
exportGroup.putAltVirtualArray(vplexURI.toString(), haVarray.toString());
_dbClient.updateObject(exportGroup);
assembleExportMasksWorkflow(vplexURI, exportURI, haVarray, varrayToInitiators.get(haVarray), ExportMaskUtils.filterVolumeMap(volumeMap, varrayToVolumes.get(haVarray)), addZoneOnDeviceOperation, workflow, srcExportStepId, opId);
}
// Initiate the workflow.
String message = String.format("VPLEX ExportGroup Add Volumes (%s) for export %s completed successfully", volListStr, exportURI);
workflow.executePlan(completer, message);
} catch (VPlexApiException vae) {
String message = String.format("Failed to add Volumes %s to ExportGroup %s", volListStr, exportURI);
_log.error(message, vae);
failStep(completer, opId, vae);
} catch (Exception ex) {
String message = String.format("Failed to add Volumes %s to ExportGroup %s", volListStr, exportURI);
_log.error(message, ex);
String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.exportGroupAddVolumesFailed(volListStr, exportURI.toString(), opName, ex);
failStep(completer, opId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method createMirrors.
/**
* Do the creation of a VPlex Mirror device and attach it as a mirror to the Virtual Volume.
* This is called as a Workflow Step.
* NOTE: The parameters here must match createMirrorsMethod above (except stepId).
*
* @param vplexURI
* URI of the VPlex StorageSystem
* @param vplexMirrorURIs
* URI of the mirrors to be created.
* @param workflowTaskId
* The workflow taskId.
* @param stepId
* The stepId used for completion.
*
* @throws WorkflowException
* When an error occurs updating the workflow step
* state.
*/
public void createMirrors(URI vplexURI, List<URI> vplexMirrorURIs, String workflowTaskId, String stepId) throws WorkflowException {
List<VolumeInfo> rollbackData = new ArrayList<VolumeInfo>();
List<URI> createdVplexMirrorURIs = new ArrayList<URI>();
VplexMirrorTaskCompleter completer = new VplexMirrorTaskCompleter(VplexMirror.class, vplexMirrorURIs, workflowTaskId);
try {
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Make a map of StorageSystem ids to Storage System
Map<URI, StorageSystem> storageMap = new HashMap<URI, StorageSystem>();
// Make a map of Mirrors to Storage Volumes.
Map<VplexMirror, Volume> mirrorMap = new HashMap<VplexMirror, Volume>();
for (URI vplexMirrorURI : vplexMirrorURIs) {
VplexMirror vplexMirror = getDataObject(VplexMirror.class, vplexMirrorURI, _dbClient);
// Find the underlying Storage Volume, there will be only one associated storage volume
for (String associatedVolume : vplexMirror.getAssociatedVolumes()) {
Volume storageVolume = getDataObject(Volume.class, new URI(associatedVolume), _dbClient);
URI storageSystemId = storageVolume.getStorageController();
if (storageMap.containsKey(storageSystemId) == false) {
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageSystemId);
storageMap.put(storageSystemId, storage);
}
mirrorMap.put(vplexMirror, storageVolume);
}
}
// Now make a call to the VPlexAPIClient.createDeviceAndAttachAsMirror for each vplex mirror.
StringBuilder buf = new StringBuilder();
buf.append("Vplex: " + vplexURI + " created mirror(s): ");
for (VplexMirror vplexMirror : mirrorMap.keySet()) {
URI vplexMirrorId = vplexMirror.getId();
Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
VPlexVirtualVolumeInfo vplexVolumeInfo = new VPlexVirtualVolumeInfo();
vplexVolumeInfo.setName(sourceVplexVolume.getDeviceLabel());
vplexVolumeInfo.setPath(sourceVplexVolume.getNativeId());
if (null == sourceVplexVolume.getAssociatedVolumes() || sourceVplexVolume.getAssociatedVolumes().isEmpty()) {
_log.error("VPLEX volume {} has no backend volumes.", sourceVplexVolume.forDisplay());
throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(sourceVplexVolume.forDisplay());
}
if (sourceVplexVolume.getAssociatedVolumes().size() > 1) {
vplexVolumeInfo.setLocality(VPlexApiConstants.DISTRIBUTED_VIRTUAL_VOLUME);
} else {
vplexVolumeInfo.setLocality(VPlexApiConstants.LOCAL_VIRTUAL_VOLUME);
}
_log.info(String.format("Creating mirror: %s (%s)", vplexMirror.getLabel(), vplexMirrorId));
Volume storageVolume = mirrorMap.get(vplexMirror);
long totalProvisioned = storageVolume.getProvisionedCapacity();
StorageSystem storage = storageMap.get(storageVolume.getStorageController());
List<String> itls = VPlexControllerUtils.getVolumeITLs(storageVolume);
VolumeInfo vinfo = new VolumeInfo(storage.getNativeGuid(), storage.getSystemType(), storageVolume.getWWN().toUpperCase().replaceAll(":", ""), storageVolume.getNativeId(), storageVolume.getThinlyProvisioned().booleanValue(), itls);
// Update rollback information.
rollbackData.add(vinfo);
List<VolumeInfo> vinfos = new ArrayList<VolumeInfo>();
vinfos.add(vinfo);
_workflowService.storeStepData(stepId, rollbackData);
// Make the call to create device and attach it as mirror to the source virtual volume device.
VPlexDeviceInfo vInfo = client.createDeviceAndAttachAsMirror(vplexVolumeInfo, vinfos, true, false);
buf.append(vInfo.getName() + " ");
_log.info(String.format("Created mirror : %s path: %s : for virtual volume %s device label %s", vInfo.getName(), vInfo.getPath(), sourceVplexVolume.getLabel(), sourceVplexVolume.getDeviceLabel()));
vplexMirror.setNativeId(vInfo.getPath());
vplexMirror.setDeviceLabel(vInfo.getName());
// For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
vplexMirror.setAllocatedCapacity(0L);
vplexMirror.setProvisionedCapacity(totalProvisioned);
if (vplexVolumeInfo.isThinEnabled() != sourceVplexVolume.getThinlyProvisioned()) {
_log.info("Thin provisioned setting changed after mirror operation to " + vplexVolumeInfo.isThinEnabled());
sourceVplexVolume.setThinlyProvisioned(vplexVolumeInfo.isThinEnabled());
_dbClient.updateObject(sourceVplexVolume);
}
vplexMirror.setThinlyProvisioned(vplexVolumeInfo.isThinEnabled());
_dbClient.updateObject(vplexMirror);
// Record VPLEX volume created event.
createdVplexMirrorURIs.add(vplexMirrorId);
recordBourneVplexMirrorEvent(vplexMirrorId, OperationTypeEnum.CREATE_VOLUME_MIRROR.getEvType(true), Operation.Status.ready, OperationTypeEnum.CREATE_VOLUME_MIRROR.getDescription());
}
completer.ready(_dbClient);
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception creating Mirror for the Virtual Volume: " + vae.getMessage(), vae);
// not created.
for (URI vplexMirrorURI : vplexMirrorURIs) {
if (!createdVplexMirrorURIs.contains(vplexMirrorURI)) {
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.CREATE_VOLUME_MIRROR.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_VOLUME_MIRROR.getDescription());
}
}
failStep(completer, stepId, vae);
} catch (Exception ex) {
_log.error("Exception creating Mirror for the Virtual Volume: " + ex.getMessage(), ex);
// not created.
for (URI vplexMirrorURI : vplexMirrorURIs) {
if (!createdVplexMirrorURIs.contains(vplexMirrorURI)) {
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.CREATE_VOLUME_MIRROR.getEvType(false), Operation.Status.error, OperationTypeEnum.CREATE_VOLUME_MIRROR.getDescription());
}
}
ServiceError serviceError = VPlexApiException.errors.createMirrorsFailed(ex);
failStep(completer, stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method attachMirror.
/**
* Called to reattach the remote mirror for a distributed VPLEX volume upon
* successfully restoring a native snapshot of the backend source volume.
*
* @param vplexURI
* The URI of the VPLEX system.
* @param vplexVolumeURI
* The URI of the distributed VPLEX volume.
* @param cgURI
* The URI of the volume's CG or null.
* @param detachStepId
* The Id of the detach mirror step.
* @param stepId
* The workflow step identifier.
*/
public void attachMirror(URI vplexURI, URI vplexVolumeURI, URI cgURI, String detachStepId, String stepId) {
_log.info("Executing attach mirror to VPLEX volume {} on VPLEX {}", new Object[] { vplexVolumeURI, vplexURI });
String mirrorDeviceName = "";
try {
// Update workflow step.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
_log.info("Got VPLEX API client");
// Get the VPLEX volume.
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
String vplexVolumeName = vplexVolume.getDeviceLabel();
_log.info("Got VPLEX volume");
// Attach the mirror.
@SuppressWarnings("unchecked") Map<String, String> detachStepData = (Map<String, String>) _workflowService.loadStepData(detachStepId);
mirrorDeviceName = detachStepData.get(DETACHED_DEVICE);
client.reattachMirrorToDistributedVolume(vplexVolumeName, mirrorDeviceName);
_log.info("Attached the mirror");
// On a subsequent failure, we don't want rollback to try to
// reattach the mirror as it must have been successful here.
// If the reattach fails, rollback will just end up trying again.
detachStepData.put(REATTACH_MIRROR, Boolean.FALSE.toString());
_workflowService.storeStepData(detachStepId, detachStepData);
// If on detach it was required to temporarily modify the distributed device name
// then we restore the correct name now after the volume is back together.
String modifiedName = null;
String successWarningMessage = null;
String restoreDeviceName = detachStepData.get(RESTORE_DEVICE_NAME);
if (restoreDeviceName != null) {
try {
modifiedName = restoreDeviceName.substring(0, VPlexApiConstants.MAX_DEVICE_NAME_LENGTH_FOR_ATTACH_MIRROR);
client.renameDistributedDevice(modifiedName, restoreDeviceName);
_log.info("Restored name of distributed device from {} to {}", modifiedName, restoreDeviceName);
} catch (Exception e) {
// We don't fail the workflow step in this case, but instead just log a message
// indicating this error. The distributed device for the volume will just have
// the modified name.
successWarningMessage = String.format("Failed renaming the distributed device %s back " + " to its orginal name %s after reattaching remote mirror", modifiedName, restoreDeviceName);
_log.warn(successWarningMessage);
}
// Remove the entry in the step data. We do this regardless of success
// or failure so that we don't try and rename again in a rollback
// scenario.
detachStepData.remove(RESTORE_DEVICE_NAME);
}
// If the volume is in a CG, we can now add it back.
if (cgURI != null) {
ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(vplexVolume);
consistencyGroupManager.addVolumeToCg(cgURI, vplexVolume, client, false);
// No need to try and add it back in rollback if something
// fails in the step after this point. If the add fails
// here, rollback will just try again.
detachStepData.put(ADD_BACK_TO_CG, Boolean.FALSE.toString());
_workflowService.storeStepData(detachStepId, detachStepData);
_log.info("Added volume back to consistency group.");
}
// Update workflow step state to success.
if (successWarningMessage != null) {
WorkflowStepCompleter.stepSucceeded(stepId, successWarningMessage);
} else {
WorkflowStepCompleter.stepSucceded(stepId);
}
_log.info("Updated workflow step state to success");
} catch (VPlexApiException vae) {
_log.error("Exception attaching mirror for VPLEX distributed volume" + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception e) {
_log.error("Exception attaching mirror for VPLEX distributed volume " + e.getMessage(), e);
WorkflowStepCompleter.stepFailed(stepId, VPlexApiException.exceptions.failedAttachingVPlexVolumeMirror(mirrorDeviceName, vplexVolumeURI.toString(), e));
}
}
use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method exportGroupRemoveInitiators.
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportRemoveInitiator(java.net.URI,
* java.net.URI, java.net.URI,
* java.lang.String)
*/
@Override
public void exportGroupRemoveInitiators(URI vplexURI, URI exportURI, List<URI> initiatorURIs, String opId) throws ControllerException {
try {
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
ExportRemoveInitiatorCompleter completer = new ExportRemoveInitiatorCompleter(exportURI, initiatorURIs, opId);
Workflow workflow = _workflowService.getNewWorkflow(this, "exportRemoveInitiator", true, opId);
// true if Workflow has a Step
boolean hasStep = false;
Initiator firstInitiator = _dbClient.queryObject(Initiator.class, initiatorURIs.get(0));
StringBuffer errorMessages = new StringBuffer();
boolean isValidationNeeded = validatorConfig.isValidationEnabled() && !ExportUtils.checkIfInitiatorsForRP(Arrays.asList(firstInitiator));
_log.info("Orchestration level validation needed : {}", isValidationNeeded);
_log.info("starting remove initiators for export group: " + exportGroup.toString());
_log.info("request is to remove these initiators: " + initiatorURIs);
initiatorURIs = VPlexUtil.filterInitiatorsForVplex(_dbClient, initiatorURIs);
// get a map of host URI to a list of Initiators in that Host
Map<URI, List<Initiator>> hostInitiatorsMap = VPlexUtil.makeHostInitiatorsMap(initiatorURIs, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Loop, processing each host separately.
for (URI hostURI : hostInitiatorsMap.keySet()) {
_log.info("setting up initiator removal for host " + hostURI);
// Get the initiators (and initiator URIs) for this host
List<Initiator> initiators = hostInitiatorsMap.get(hostURI);
// Find the ExportMask for my host.
List<ExportMask> exportMasks = getExportMaskForHost(exportGroup, hostURI, vplexURI);
if (exportMasks == null || exportMasks.isEmpty()) {
// If there is no ExportMask for this host, there is nothing to do.
_log.info("No export mask found for hostURI: " + hostURI);
continue;
}
String lastStep = null;
List<URI> initiatorsAlreadyRemovedFromExportGroup = new ArrayList<URI>();
for (ExportMask exportMask : exportMasks) {
_log.info("adding remove initiators steps for " + "export mask / storage view: " + exportMask.getMaskName());
String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
_log.info("Refreshing ExportMask {}", exportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortToPwwnMap, _networkDeviceController);
// initiator filter logic is move inside addStepsForRemoveInitiators and addStepsForInitiatorRemoval as
// it is not required for zone related operation.
// validate the remove initiator operation against the export mask volumes
List<URI> volumeURIList = (exportMask.getUserAddedVolumes() != null) ? URIUtil.toURIList(exportMask.getUserAddedVolumes().values()) : new ArrayList<URI>();
if (volumeURIList.isEmpty()) {
_log.warn("volume URI list for validating remove initiators is empty...");
}
ExportMaskValidationContext ctx = new ExportMaskValidationContext();
ctx.setStorage(vplex);
ctx.setExportMask(exportMask);
ctx.setBlockObjects(volumeURIList, _dbClient);
ctx.setAllowExceptions(!WorkflowService.getInstance().isStepInRollbackState(opId));
validator.removeInitiators(ctx).validate();
lastStep = addStepsForRemoveInitiators(vplex, workflow, completer, exportGroup, exportMask, initiators, hostURI, initiatorsAlreadyRemovedFromExportGroup, errorMessages, lastStep);
if (lastStep != null) {
hasStep = true;
}
}
}
String message = errorMessages.toString();
if (isValidationNeeded && !message.isEmpty()) {
_log.error("Error Message {}", errorMessages);
List<String> initiatorNames = new ArrayList<String>();
for (URI initiatorURI : initiatorURIs) {
Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
if (initiator != null) {
String normalizedName = Initiator.normalizePort(initiator.getInitiatorPort());
initiatorNames.add(normalizedName);
} else {
_log.warn("no initiator found for URI {}", initiatorURI);
}
}
throw DeviceControllerException.exceptions.removeInitiatorValidationError(Joiner.on(", ").join(initiatorNames), vplex.getLabel(), message);
}
// Fire off the workflow if there were initiators to delete. Otherwise just fire completer.
if (hasStep) {
workflow.executePlan(completer, "Successfully removed initiators: " + initiatorURIs.toString());
} else {
_log.info(String.format("No updates to ExportMasks needed... complete"));
completer.ready(_dbClient);
}
} catch (VPlexApiException vae) {
_log.error("Exception in exportRemoveInitiators: " + initiatorURIs.toString(), vae);
WorkflowStepCompleter.stepFailed(opId, vae);
} catch (Exception ex) {
_log.error("Exception in exportRemoveInitiators: " + initiatorURIs.toString(), ex);
String opName = ResourceOperationTypeEnum.DELETE_EXPORT_INITIATOR.getName();
ServiceError serviceError = VPlexApiException.errors.exportGroupRemoveInitiatorsFailed(opName, ex);
WorkflowStepCompleter.stepFailed(opId, serviceError);
}
}
Aggregations