use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackDeleteMirrorDevice.
/**
* Here we will try to reattach mirror device. If we cannot reattach then the mirror
* is already detached and mirror related objects will be removed from the database.
*
* @param vplexURI
* URI of the VPlex StorageSystem
* @param mirrorURI
* URI of the mirror to be deleted
* @param stepId
* The stepId used for completion.
*
* @throws WorkflowException
* When an error occurs updating the workflow step
* state.
*/
public void rollbackDeleteMirrorDevice(URI vplexURI, URI mirrorURI, String stepId) throws WorkflowException {
try {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
// Get source volume for the mirror
Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
String locality = null;
if (sourceVplexVolume.getAssociatedVolumes() != null && sourceVplexVolume.getAssociatedVolumes().size() > 1) {
locality = VPlexApiConstants.DISTRIBUTED_VIRTUAL_VOLUME;
} else {
locality = VPlexApiConstants.LOCAL_VIRTUAL_VOLUME;
}
// Try to re-attach the mirror device back to the source device
client.attachMirror(locality, sourceVplexVolume.getDeviceLabel(), vplexMirror.getDeviceLabel());
_log.info("Successfully re-attached mirror %s to the source volume %s during delete mirror rollback. ", vplexMirror.getDeviceLabel(), sourceVplexVolume.getDeviceLabel());
} catch (Exception e) {
// If exception occurs that means mirror is already detached and we couldn't reattach
// So cleanup database objects related to a mirror.
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
// Remove mirror from the source VPLEX volume
sourceVplexVolume.getMirrors().remove(vplexMirror.getId().toString());
_dbClient.updateObject(sourceVplexVolume);
_log.info("Removed mirror %s from source volume %s", mirrorURI, sourceVplexVolume.getId());
// Delete mirror and associated volume from database
if (null != vplexMirror.getAssociatedVolumes()) {
for (String assocVolumeId : vplexMirror.getAssociatedVolumes()) {
Volume volume = _dbClient.queryObject(Volume.class, URI.create(assocVolumeId));
if (null != volume) {
_dbClient.removeObject(volume);
}
}
}
// Delete the mirror object
_dbClient.removeObject(vplexMirror);
_log.error("Error during rollback of promote mirror: {}", e.getMessage(), e);
} finally {
// Return success so rollback continues
WorkflowStepCompleter.stepSucceded(stepId);
}
}
use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method waitOnRebuild.
/**
* Waits for the rebuild to complete when a non-VPLEX volume is imported to a VPLEX
* distribute volume or a local VPLEX volume is upgraded to distributed.
*
* @param vplexURI
* The URI of the VPLEX system.
* @param vplexVolumeURI
* The URI of the VPLEX volume.
* @param stepId
* The workflow step identifier.
*
* @throws WorkflowException
*/
public void waitOnRebuild(URI vplexURI, URI vplexVolumeURI, String stepId) throws WorkflowException {
String volumeName = null;
try {
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Get the VPLEX volume that is rebuilding.
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
volumeName = vplexVolume.getLabel();
// Check the rebuild status until it completes, fails, or we timeout waiting.
WaitOnRebuildResult rebuildResult = client.waitOnRebuildCompletion(vplexVolume.getDeviceLabel());
_log.info(String.format("Finished waiting on rebuild for virtual volume: %s path: %s rebuild-status: %s", vplexVolume.getDeviceLabel(), vplexVolume.getNativeId(), rebuildResult.name()));
if (WaitOnRebuildResult.SUCCESS == rebuildResult) {
WorkflowStepCompleter.stepSucceded(stepId);
} else {
ServiceError serviceError;
if (WaitOnRebuildResult.FAILED == rebuildResult) {
serviceError = VPlexApiException.errors.waitOnRebuildFailed(volumeName);
} else if (WaitOnRebuildResult.TIMED_OUT == rebuildResult) {
serviceError = VPlexApiException.errors.waitOnRebuildTimedOut(volumeName);
} else {
serviceError = VPlexApiException.errors.waitOnRebuildInvalid(volumeName);
}
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
} catch (VPlexApiException vae) {
_log.error("Exception checking the rebuild status: " + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception checking the rebuild status: " + ex.getMessage(), ex);
ServiceError serviceError = VPlexApiException.errors.waitOnRebuildException(volumeName, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackUpgradeVirtualVolumeLocalToDistributed.
/**
* Rollback upgrade of VPLEX local to VPLEX distributed volume.
*
* @param vplexURI
* Reference to VPLEX system
* @param virtualVolumeName
* Virtual volume name which was supposed to be upgraded
* @param virtualVolumePath
* Virtual volume path which was supposed to be upgraded
* @param executeStepId
* step Id of the execute step; used to retrieve rollback data
* @param stepId
* The rollback step id
* @throws WorkflowException
* When an error occurs updating the workflow step state
*/
public void rollbackUpgradeVirtualVolumeLocalToDistributed(URI vplexURI, String virtualVolumeName, String virtualVolumePath, String executeStepId, String stepId) throws WorkflowException {
try {
VolumeInfo mirrorInfo = (VolumeInfo) _workflowService.loadStepData(executeStepId);
if (mirrorInfo != null) {
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// Get the cluster id for this storage volume.
String clusterId = client.getClaimedStorageVolumeClusterName(mirrorInfo);
try {
// Try to detach mirror that might have been added.
client.detachMirrorFromDistributedVolume(virtualVolumeName, clusterId);
// Find virtual volume and its supporting device
VPlexVirtualVolumeInfo virtualVolumeInfo = client.findVirtualVolume(virtualVolumeName, virtualVolumePath);
String sourceDeviceName = virtualVolumeInfo.getSupportingDevice();
// Once mirror is detached we need to do device collapse so that its not seen as distributed device.
client.deviceCollapse(sourceDeviceName, VPlexApiConstants.DISTRIBUTED_DEVICE);
// Once device collapse is successful we need to set visibility of device to local because volume will be seen from
// other cluster still as visibility of device changes to global once mirror is attached.
client.setDeviceVisibility(sourceDeviceName);
} catch (Exception e) {
_log.error("Exception restoring virtual volume " + virtualVolumeName + " to its original state." + e);
_log.info(String.format("Couldn't detach mirror corresponding to the backend volume %s from the VPLEX volume %s on VPLEX cluster %s during rollback. " + "Its possible mirror was never attached, so just move on to delete backend volume artifacts from the VPLEX", mirrorInfo.getVolumeName(), virtualVolumeName, clusterId));
}
// Its possible that mirror was never attached so we will try to delete the device even if we fail to
// detach a mirror.
// If mirror device is still attached this will anyway fail, so its safe to make this call.
client.deleteLocalDevice(mirrorInfo);
}
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception rollback VPlex Virtual Volume upgrade from local to distributed : " + vae.getLocalizedMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception rollback VPlex Virtual Volume upgrade from local to distributed : " + ex.getLocalizedMessage(), ex);
ServiceError serviceError = VPlexApiException.errors.createVirtualVolumesRollbackFailed(stepId, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method deleteVirtualVolumes.
/**
* A workflow Step to delete VPLex Virtual volumes.
* This Step is also used to rollback create virtual volumes.
* NOTE NOTE: The parameters here must match deleteVirtualVolumesMethod above (except stepId).
*
* @param vplexURI
* @param volumeURIs
* @param doNotFullyDeleteVolumeList
* @param stepId
* @throws WorkflowException
*/
public void deleteVirtualVolumes(URI vplexURI, List<URI> volumeURIs, List<URI> doNotFullyDeleteVolumeList, String stepId) throws WorkflowException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
StringBuilder errMsgBuilder = new StringBuilder();
boolean failed = false;
// Loop deleting each volume by name (the deviceLabel in the Volume).
for (URI volumeURI : volumeURIs) {
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
if (volume == null || volume.getInactive() == true) {
continue;
}
// Skip this operation if the volume has already been deleted
if (volume.getDeviceLabel() == null) {
_log.info("Volume {} with Id {} was never created on the Vplex as device label is null " + "hence skip volume delete on VPLEX", volume.getLabel(), volume.getId());
continue;
}
try {
client.findVirtualVolume(volume.getDeviceLabel(), volume.getNativeId());
} catch (VPlexApiException ex) {
if (ex.getServiceCode() == ServiceCode.VPLEX_CANT_FIND_REQUESTED_VOLUME) {
_log.info("VPlex virtual volume: " + volume.getNativeId() + " has already been deleted; will skip deletion of virtual volume");
continue;
} else {
_log.error("Exception finding Virtual Volume", ex);
throw ex;
}
}
try {
if (volume.getNativeId() != null) {
// Volumes in consistency groups must be removed.
BlockConsistencyGroup cg = null;
if (!NullColumnValueGetter.isNullURI(volume.getConsistencyGroup())) {
cg = getDataObject(BlockConsistencyGroup.class, volume.getConsistencyGroup(), _dbClient);
}
if (cg != null) {
// Call the appropriate ConsistencyGroupManager to delete the CG volume
ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(volume);
consistencyGroupManager.deleteConsistencyGroupVolume(vplexURI, volume, cg);
}
// to delete volume.
if (doNotFullyDeleteVolumeList == null || doNotFullyDeleteVolumeList.isEmpty() || !doNotFullyDeleteVolumeList.contains(volume.getId())) {
// We only retry a dismantle failure on volumes created
// in ViPR as the retry code relies on the well-known ViPR
// naming conventions and virtual volume structure to find
// VPLEX artifacts related to the volume being deleted.
_log.info(String.format("Deleting VPlex virtual volume %s (%s)", volume.getDeviceLabel(), volume.getNativeId()));
boolean isIngestedWithoutBackend = volume.isIngestedVolumeWithoutBackend(_dbClient);
client.deleteVirtualVolume(volume.getDeviceLabel(), !isIngestedWithoutBackend, !isIngestedWithoutBackend);
}
// Record VPLEX volume deleted event.
recordBourneVolumeEvent(volume.getId(), OperationTypeEnum.DELETE_BLOCK_VOLUME.getEvType(true), Operation.Status.ready, OperationTypeEnum.DELETE_BLOCK_VOLUME.getDescription());
if (volume.getMirrors() != null && !(volume.getMirrors().isEmpty())) {
for (String mirrorId : volume.getMirrors()) {
VplexMirror mirror = _dbClient.queryObject(VplexMirror.class, URI.create(mirrorId));
if (null != mirror) {
_log.info("Marking mirror {} {} for deletion.", mirror.getId(), mirror.getDeviceLabel());
_dbClient.removeObject(mirror);
}
}
}
}
} catch (Exception ex) {
_log.error("Exception deleting Virtual Volume: " + volumeURI, ex);
// Record VPLEX volume deletion failed event.
recordBourneVolumeEvent(volume.getId(), OperationTypeEnum.DELETE_BLOCK_VOLUME.getEvType(false), Operation.Status.error, OperationTypeEnum.DELETE_BLOCK_VOLUME.getDescription());
// Update error message
if (errMsgBuilder.length() != 0) {
errMsgBuilder.append("\n");
} else {
errMsgBuilder.append("Exception deleting vplex virtual volume(s):\n");
}
errMsgBuilder.append(volume.getLabel());
errMsgBuilder.append(":");
errMsgBuilder.append(ex.getMessage());
failed = true;
}
}
if (failed) {
String opName = ResourceOperationTypeEnum.DELETE_VIRTUAL_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.jobFailedOp(opName);
serviceError.setMessage(errMsgBuilder.toString());
WorkflowStepCompleter.stepFailed(stepId, serviceError);
} else {
WorkflowStepCompleter.stepSucceded(stepId);
}
} catch (VPlexApiException vae) {
_log.error("Exception deleting VPlex Virtual Volume: " + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception deleting VPlex Virtual Volume: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.DELETE_VIRTUAL_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.deleteVirtualVolumesFailed(opName, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.workflow.WorkflowException 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));
}
}
Aggregations