use of com.emc.storageos.workflow.WorkflowException 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.workflow.WorkflowException 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.workflow.WorkflowException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method storageViewAddStoragePorts.
/**
* Workflow Step to add storage port(s) to Storage View.
* Note arguments (except stepId) must match storageViewAddStoragePortsMethod above.
*
* @param vplexURI
* -- URI of VPlex StorageSystem
* @param exportURI
* -- ExportGroup URI
* @param maskURI
* -- ExportMask URI.
* @param targetURIs
* -- list of targets URIs (VPLEX FE ports) to be added.
* If not null, the targets (VPlex front end ports) indicated by the targetURIs will be added
* to the Storage View making sure they do belong to zoningMap storagePorts.
* If null, then ports are calculated from the zoningMap.
* @param completer the ExportMaskAddInitiatorCompleter
* @param stepId
* -- Workflow step id.
* @throws WorkflowException
*/
public void storageViewAddStoragePorts(URI vplexURI, URI exportURI, URI maskURI, List<URI> targetURIs, ExportMaskAddInitiatorCompleter completer, String stepId) throws DeviceControllerException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
ExportOperationContext context = new VplexExportOperationContext();
// Prime the context object
completer.updateWorkflowStepContext(context);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplexURI);
for (ExportMask exportMask : exportMasks) {
// If a specific ExportMask is to be processed, ignore any others.
if (maskURI != null && !exportMask.getId().equals(maskURI)) {
continue;
}
ArrayList<URI> filteredTargetURIs = new ArrayList<URI>();
// Filter or get targets from the zoning map
if (exportMask.getZoningMap() != null) {
Set<String> zoningMapTargets = BlockStorageScheduler.getTargetIdsFromAssignments(exportMask.getZoningMap());
List<URI> zoningMapTargetURIs = StringSetUtil.stringSetToUriList(zoningMapTargets);
if (targetURIs == null || targetURIs.isEmpty()) {
// Add all storage ports from the zoning map
if (zoningMapTargetURIs != null && !zoningMapTargetURIs.isEmpty()) {
filteredTargetURIs.addAll(zoningMapTargetURIs);
}
} else {
// Log any ports not in the zoning map.
for (URI targetURI : targetURIs) {
filteredTargetURIs.add(targetURI);
if (zoningMapTargetURIs.contains(targetURI)) {
_log.info(String.format("Target %s not in zoning map", targetURI));
}
}
}
}
// Add new targets if specified
if (filteredTargetURIs != null && filteredTargetURIs.isEmpty() == false) {
List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
List<URI> targetsAddedToStorageView = new ArrayList<URI>();
for (URI target : filteredTargetURIs) {
// Do not try to add a port twice.
if (exportMask.getStoragePorts().contains(target.toString())) {
continue;
}
// Build the PortInfo structure for the port to be added
StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
targetPortInfos.add(pi);
targetsAddedToStorageView.add(target);
}
if (!targetPortInfos.isEmpty()) {
// Add the targets on the VPLEX
client.addTargetsToStorageView(exportMask.getMaskName(), targetPortInfos);
ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_TARGETS_TO_STORAGE_VIEW, targetsAddedToStorageView);
// Add the targets to the database.
for (URI target : targetsAddedToStorageView) {
exportMask.addTarget(target);
}
_dbClient.updateObject(exportMask);
}
}
}
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_083);
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
_log.error("VPlexApiException adding storagePorts to Storage View: " + vae.getMessage(), vae);
failStep(completer, stepId, vae);
} catch (Exception ex) {
_log.error("Exception adding storagePorts to Storage View: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.ADD_STORAGE_VIEW_STORAGEPORTS.getName();
ServiceError serviceError = VPlexApiException.errors.storageViewAddStoragePortFailed(opName, ex);
failStep(completer, stepId, serviceError);
}
}
use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackCreateMirrors.
/**
* Rollback any mirror device previously created.
*
* @param vplexURI
* URI of the VPlex StorageSystem
* @param vplexMirrorURIs
* URI of the mirrors
* @param executeStepId
* step Id of the execute step; used to retrieve rollback data.
* @param stepId
* The stepId used for completion.
*
* @throws WorkflowException
* When an error occurs updating the workflow step
* state.
*/
public void rollbackCreateMirrors(URI vplexURI, List<URI> vplexMirrorURIs, String executeStepId, String stepId) throws WorkflowException {
try {
List<VolumeInfo> rollbackData = (List<VolumeInfo>) _workflowService.loadStepData(executeStepId);
if (rollbackData != null) {
WorkflowStepCompleter.stepExecuting(stepId);
// Get the API client.
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// For each mirror device attempted, try and rollback.
for (VolumeInfo rollbackInfo : rollbackData) {
client.deleteLocalDevice(rollbackInfo);
}
}
} catch (Exception ex) {
_log.error("Exception rolling back: " + ex.getLocalizedMessage());
} finally {
// cleanup vplex mirror object in Database
for (URI uri : vplexMirrorURIs) {
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, uri);
if (vplexMirror != null) {
Volume sourceVplexVolume = _dbClient.queryObject(Volume.class, vplexMirror.getSource());
sourceVplexVolume.getMirrors().remove(vplexMirror.getId().toString());
_dbClient.updateObject(sourceVplexVolume);
_dbClient.removeObject(vplexMirror);
}
}
WorkflowStepCompleter.stepSucceded(stepId);
}
}
use of com.emc.storageos.workflow.WorkflowException in project coprhd-controller by CoprHD.
the class VnxSnapshotOperations method deleteConsistencyGroupSnapshot.
/**
* This method will delete a snapshot that was created as part of volume consistency
* group 'snap-set'.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshot [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
* @return true - All the snaps in the 'snap-set' where deleted successfully.
* @throws WorkflowException
*/
private boolean deleteConsistencyGroupSnapshot(StorageSystem storage, BlockSnapshot snap, TaskCompleter taskCompleter) throws DeviceControllerException {
boolean wasSuccess = false;
try {
callEMCRefreshIfRequired(_dbClient, _helper, storage, Arrays.asList(snap.getId()));
CIMObjectPath syncObjectPath = _cimPath.getSyncObject(storage, snap);
if (_helper.checkExists(storage, syncObjectPath, false, false) != null) {
deactivateSnapshot(storage, snap, syncObjectPath);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.callModifyReplica(storage, _helper.getDeleteSnapshotSynchronousInputArguments(syncObjectPath), outArgs);
if (snap.getSettingsInstance() != null) {
Volume volume = _dbClient.queryObject(Volume.class, snap.getParent());
outArgs = new CIMArgument[5];
_helper.callModifySettingsDefineState(storage, _helper.getDeleteSettingsForSnapshotInputArguments(storage, volume, snap), outArgs);
}
}
wasSuccess = true;
} catch (WBEMException e) {
String message = String.format("Error encountered during delete snapshot %s on array %s", snap.getId().toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} catch (Exception e) {
String message = String.format("Generic exception when trying to delete snapshot %s on array %s", snap.getId().toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("deleteConsistencyGroupSnapshot", e.getMessage());
taskCompleter.error(_dbClient, error);
}
return wasSuccess;
}
Aggregations