use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method portRebalance.
@Override
public void portRebalance(URI vplex, URI exportGroupURI, URI varray, URI exportMaskURI, Map<URI, List<URI>> adjustedPaths, Map<URI, List<URI>> removedPaths, boolean isAdd, String stepId) throws Exception {
// Retrieve the ExportGroup and ExportMask and validate
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
if (exportGroup == null || exportMask == null || exportGroup.getInactive() || exportMask.getInactive() || !exportGroup.hasMask(exportMaskURI)) {
String reason = String.format("Bad exportGroup %s or exportMask %s", exportGroupURI, exportMaskURI);
_log.error(reason);
ServiceCoded coded = WorkflowException.exceptions.workflowConstructionError(reason);
WorkflowStepCompleter.stepFailed(stepId, coded);
return;
}
// Check if the ExportMask is in the desired varray (in cross-coupled ExportGroups)
if (!ExportMaskUtils.exportMaskInVarray(_dbClient, exportMask, varray)) {
_log.info(String.format("ExportMask %s (%s) not in specified varray %s", exportMask.getMaskName(), exportMask.getId(), varray));
WorkflowStepCompleter.stepSucceeded(stepId, String.format("No operation done: Mask not in specified varray %s", varray));
return;
}
// Refresh the ExportMask so we have the latest data.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplex, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplex, client, _dbClient);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
_log.info("Processing and Refreshing ExportMask {}", exportMask.getMaskName());
Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortToPwwnMap, _networkDeviceController);
// Determine hosts in ExportMask
Set<URI> hostsInExportMask = new HashSet<URI>();
Set<String> hostNames = ExportMaskUtils.getHostNamesInMask(exportMask, _dbClient);
Set<Initiator> initiatorsInMask = ExportMaskUtils.getInitiatorsForExportMask(_dbClient, exportMask, null);
for (Initiator initiator : initiatorsInMask) {
if (initiator.getHost() != null) {
hostsInExportMask.add(initiator.getHost());
}
}
boolean sharedMask = (hostsInExportMask.size() > 1);
if (isAdd) {
// Processing added paths only
Workflow workflow = _workflowService.getNewWorkflow(this, "portRebalance", false, stepId);
// Determine initiators and targets to be added.
// These are initiators not in mask that are in a host in the mask.
// Earlier versions of the Vplex code may not have had all the initiators in the mask, as
// earlier code only put initiators in the Storage View for which ports were added.
// Targets to be added may be on existing initiators or newly added initiators.
List<URI> initiatorsToAdd = new ArrayList<URI>();
List<URI> targetsToAdd = new ArrayList<URI>();
for (URI initiatorURI : adjustedPaths.keySet()) {
if (!exportMask.hasInitiator(initiatorURI.toString())) {
// Initiator not in ExportMask
Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
if (initiator != null && !initiator.getInactive()) {
if (hostsInExportMask.contains(initiator.getHost())) {
initiatorsToAdd.add(initiatorURI);
for (URI targetURI : adjustedPaths.get(initiatorURI)) {
if (!exportMask.hasTargets(Arrays.asList(targetURI)) && !targetsToAdd.contains(targetURI)) {
targetsToAdd.add(targetURI);
}
}
}
}
} else {
// Initiator already in ExportMask, look for additional targets
for (URI targetURI : adjustedPaths.get(initiatorURI)) {
if (!exportMask.hasTargets(Arrays.asList(targetURI)) && !targetsToAdd.contains(targetURI)) {
targetsToAdd.add(targetURI);
}
}
}
}
_log.info("Targets to add: " + targetsToAdd.toString());
_log.info("Initiators to add: " + initiatorsToAdd.toString());
// Invoke either storageViewAddInitiators if there are initiators to be added (it will add targets also),
// or storageViewAddStoragePorts if no initiators to be added (which adds only targets).
Workflow.Method addPathsMethod = null;
if (!initiatorsToAdd.isEmpty() || !targetsToAdd.isEmpty()) {
String addInitiatorStepId = workflow.createStepId();
ExportMaskAddInitiatorCompleter completer = new ExportMaskAddInitiatorCompleter(exportGroupURI, exportMaskURI, initiatorsToAdd, targetsToAdd, addInitiatorStepId);
;
if (!initiatorsToAdd.isEmpty()) {
addPathsMethod = storageViewAddInitiatorsMethod(vplex, exportGroupURI, exportMaskURI, initiatorsToAdd, targetsToAdd, sharedMask, completer);
} else if (!targetsToAdd.isEmpty()) {
addPathsMethod = storageViewAddStoragePortsMethod(vplex, exportGroupURI, exportMaskURI, targetsToAdd, completer);
}
String description = String.format("Adding paths to ExportMask %s Hosts %s", exportMask.getMaskName(), hostNames.toString());
workflow.createStep("addPaths", description, null, vplex, vplexSystem.getSystemType(), this.getClass(), addPathsMethod, null, false, addInitiatorStepId);
ExportMaskAddPathsCompleter workflowCompleter = new ExportMaskAddPathsCompleter(exportGroupURI, exportMaskURI, stepId);
workflow.executePlan(workflowCompleter, description + " completed successfully");
return;
}
} else {
// Processing the paths to be removed only, Paths not in the removedPaths map will be retained.
// Note that we only remove ports (targets), never initiators.
Workflow workflow = _workflowService.getNewWorkflow(this, "portRebalance", false, stepId);
// Compute the targets to be removed.
Set<URI> targetsToBeRemoved = ExportMaskUtils.getAllPortsInZoneMap(removedPaths);
Collection<URI> targetsInMask = Collections2.transform(exportMask.getStoragePorts(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
targetsToBeRemoved.retainAll(targetsInMask);
Set<URI> targetsToBeRetained = ExportMaskUtils.getAllPortsInZoneMap(adjustedPaths);
targetsToBeRemoved.removeAll(targetsToBeRetained);
List<URI> portsToBeRemoved = new ArrayList<URI>(targetsToBeRemoved);
_log.info("Targets to be removed: " + portsToBeRemoved.toString());
// Call storageViewRemoveStoragePorts to remove any necessary targets.
Workflow.Method removePathsMethod = null;
if (!portsToBeRemoved.isEmpty()) {
String removeInitiatorStepId = workflow.createStepId();
removePathsMethod = storageViewRemoveStoragePortsMethod(vplex, exportGroupURI, exportMaskURI, portsToBeRemoved, null);
String description = String.format("Removing paths to ExportMask %s Hosts %s", exportMask.getMaskName(), hostNames.toString());
workflow.createStep("removePaths", description, null, vplex, vplexSystem.getSystemType(), this.getClass(), removePathsMethod, null, false, removeInitiatorStepId);
ExportMaskRemovePathsCompleter workflowCompleter = new ExportMaskRemovePathsCompleter(exportGroupURI, exportMaskURI, stepId);
workflowCompleter.setRemovedStoragePorts(portsToBeRemoved);
workflow.executePlan(workflowCompleter, description + " completed successfully");
return;
}
}
// Apparently nothing to do, return success
WorkflowStepCompleter.stepSucceeded(stepId, "No operation performed on VPLEX mask");
}
use of com.emc.storageos.vplex.api.VPlexApiClient 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.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackCommitMigration.
/**
* Rollback when a migration commit fails.
*
* @param migrationURIs
* The URIs for all migrations.
* @param newVpoolURI
* The URI of the new Vpool after migration commit
* @param newVarrayURI
* The URI of the new Varray after migration commit
* @param commitStepId
* The commit step id.
* @param stepId
* The rollback step id.
*
* @throws WorkflowException
*/
public void rollbackCommitMigration(List<URI> migrationURIs, URI newVpoolURI, URI newVarrayURI, String commitStepId, String stepId) throws WorkflowException {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
try {
// Determine if any migration was successfully committed.
boolean migrationCommitted = false;
Iterator<URI> migrationIter = migrationURIs.iterator();
while (migrationIter.hasNext()) {
URI migrationURI = migrationIter.next();
Migration migration = _dbClient.queryObject(Migration.class, migrationURI);
Volume volume = _dbClient.queryObject(Volume.class, migration.getVolume());
// Check migration database record for committed state
if (VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue().equals(migration.getMigrationStatus())) {
migrationCommitted = true;
updateMigratedVirtualVolumeVpoolAndVarray(volume, newVpoolURI, newVarrayURI);
_dbClient.updateObject(volume);
inventoryDeleteMigrationSource(migration.getSource(), volume);
continue;
}
// Check vplex hardware migration records for committed state
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, volume.getStorageController(), _dbClient);
VPlexMigrationInfo migrationInfo = client.getMigrationInfo(migration.getLabel());
if (migrationInfo.getStatus().equalsIgnoreCase(VPlexMigrationInfo.MigrationStatus.COMMITTED.name())) {
migrationCommitted = true;
migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.COMMITTED.name());
_dbClient.updateObject(migration);
associateVplexVolumeWithMigratedTarget(migration, migration.getVolume());
updateMigratedVirtualVolumeVpoolAndVarray(volume, newVpoolURI, newVarrayURI);
_dbClient.updateObject(volume);
inventoryDeleteMigrationSource(migration.getSource(), volume);
continue;
}
}
// creation step will cancel the migration.
if (migrationCommitted) {
_log.info("The migration has already been committed or the migration state can not be determined, failing rollback");
// Don't allow rollback to go further than the first error.
_workflowService.setWorkflowRollbackContOnError(stepId, false);
ServiceError serviceError = VPlexApiException.errors.cantRollbackCommittedMigration();
WorkflowStepCompleter.stepFailed(stepId, serviceError);
} else {
_log.info("No Migrations are not committed");
WorkflowStepCompleter.stepSucceded(stepId);
}
} catch (Exception e) {
_log.info("Exception determining commit rollback state", e);
// Don't allow rollback to go further than the first error.
_workflowService.setWorkflowRollbackContOnError(stepId, false);
ServiceError serviceError = VPlexApiException.errors.cantRollbackExceptionDeterminingCommitState(e);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient 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.VPlexApiClient 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