use of com.emc.storageos.db.client.model.VplexMirror 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.db.client.model.VplexMirror in project coprhd-controller by CoprHD.
the class VPlexDeviceController method addStepsForDetachAndDeleteMirror.
/**
* Here we detach the mentioned mirror device from the source device and
* dismantle mirror device.
*
* @param workflow
* The workflow to which the steps are added.
* @param waitFor
* The previous workflow step for which these steps will wait
* @param vplexURI
* The vplex storage system URI
* @param mirrorURI
* The URI of the mirror that needs to be detached
* @param taskId
* The workflow taskId
*/
public String addStepsForDetachAndDeleteMirror(Workflow workflow, String waitFor, URI vplexURI, URI mirrorURI, String taskId) throws ControllerException {
try {
// Add a step to detach mirror device
String detachStep = workflow.createStepId();
waitFor = workflow.createStep(VPLEX_STEP, String.format("VPlex %s detaching mirror:%n%s", vplexURI, mirrorURI), waitFor, vplexURI, DiscoveredDataObject.Type.vplex.name(), this.getClass(), detachMirrorDeviceMethod(vplexURI, mirrorURI, null, true), rollbackMethodNullMethod(), detachStep);
// Add a step to delete mirror device
String deleteMirrorStep = workflow.createStepId();
waitFor = workflow.createStep(VPLEX_STEP, String.format("VPlex %s deleting mirror:%n%s", vplexURI, mirrorURI), waitFor, vplexURI, DiscoveredDataObject.Type.vplex.name(), this.getClass(), deleteMirrorDeviceMethod(vplexURI, mirrorURI), rollbackDeleteMirrorDeviceMethod(vplexURI, mirrorURI), deleteMirrorStep);
// Make a list of ExportGroups that is used.
List<URI> exportGroupList = new ArrayList<URI>();
// Create a series of steps to remove the volume from the Export Groups.
// This list will contain only one backend volume uri for the vplex mirror
List<URI> backendVolURIs = new ArrayList<URI>();
boolean unexportStepsAdded = false;
VplexMirror mirror = _dbClient.queryObject(VplexMirror.class, mirrorURI);
if (mirror.getAssociatedVolumes() != null) {
for (String volumeId : mirror.getAssociatedVolumes()) {
URI volumeURI = new URI(volumeId);
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
// reference when user attempts to cleanup this failed mirror.
if (volume == null || volume.getInactive() == true || volume.getNativeId() == null) {
continue;
}
backendVolURIs.add(volume.getId());
}
if (!backendVolURIs.isEmpty()) {
unexportStepsAdded = vplexAddUnexportVolumeWfSteps(workflow, VPLEX_STEP, backendVolURIs, exportGroupList);
}
}
// If we unexported a backend volume, add a step to forget those volumes.
if (unexportStepsAdded) {
waitFor = UNEXPORT_STEP;
// Add a step to forget the backend volumes for the deleted
// VPLEX volumes on this VPLEX system.
addStepToForgetVolumes(workflow, vplexURI, backendVolURIs, waitFor);
} else {
waitFor = VPLEX_STEP;
}
return waitFor;
} catch (Exception ex) {
throw VPlexApiException.exceptions.addStepsForDetachAndDeleteMirror(ex);
}
}
use of com.emc.storageos.db.client.model.VplexMirror 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.db.client.model.VplexMirror in project coprhd-controller by CoprHD.
the class VPlexDeviceController method detachMirrorDevice.
/**
* This method will detach mirror device from the vplex volume source device.
* If discard is true it will leave the device and the underlying structure on VPlex.
* True is used when this method is used in the context of deleting mirror.
* If discarded is false it will convert the detached mirror into virtual volume with
* the same name as the mirror device. False is used in the context of promoting mirror
* to a vplex volume.
*
* @param vplexURI
* URI of the VPlex StorageSystem
* @param vplexMirrorURI
* URI of the mirror to be detached.
* @param discard
* true or false value, whether to discard device or not.
* @param stepId
* The stepId used for completion.
*
* @throws WorkflowException
* When an error occurs updating the workflow step
* state.
*/
public void detachMirrorDevice(URI vplexURI, URI vplexMirrorURI, URI promotedVolumeURI, boolean discard, String stepId) throws WorkflowException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
VplexMirror vplexMirror = getDataObject(VplexMirror.class, vplexMirrorURI, _dbClient);
Volume sourceVplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
if (vplexMirror.getDeviceLabel() != null) {
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) {
// Call to detach mirror device from Distributed Virtual Volume
client.detachLocalMirrorFromDistributedVirtualVolume(sourceVplexVolume.getDeviceLabel(), vplexMirror.getDeviceLabel(), discard);
} else {
// Call to detach mirror device from Local Virtual Volume
client.detachMirrorFromLocalVirtualVolume(sourceVplexVolume.getDeviceLabel(), vplexMirror.getDeviceLabel(), discard);
}
// Record VPLEX mirror detach event.
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DETACH_VOLUME_MIRROR.getEvType(true), Operation.Status.ready, OperationTypeEnum.DETACH_VOLUME_MIRROR.getDescription());
} else {
_log.info("It seems vplex mirror {} was never created, so move to the next step for cleanup.", vplexMirror.getLabel());
}
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception detaching Vplex Mirror {} ", vplexMirrorURI + vae.getMessage(), vae);
if (promotedVolumeURI != null) {
// If we are here due to promote mirror action then
// delete the volume that was supposed to be promoted volume.
Volume volume = _dbClient.queryObject(Volume.class, promotedVolumeURI);
_dbClient.removeObject(volume);
}
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DETACH_VOLUME_MIRROR.getEvType(true), Operation.Status.error, OperationTypeEnum.DETACH_VOLUME_MIRROR.getDescription());
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception detaching Vplex Mirror {} ", vplexMirrorURI + ex.getMessage(), ex);
if (promotedVolumeURI != null) {
// If we are here due to promote mirror action then
// delete the volume that was supposed to be promoted volume.
Volume volume = _dbClient.queryObject(Volume.class, promotedVolumeURI);
_dbClient.removeObject(volume);
}
String opName = ResourceOperationTypeEnum.DETACH_VPLEX_LOCAL_MIRROR.getName();
ServiceError serviceError = VPlexApiException.errors.detachMirrorFailed(opName, ex);
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DETACH_VOLUME_MIRROR.getEvType(true), Operation.Status.error, OperationTypeEnum.DETACH_VOLUME_MIRROR.getDescription());
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.db.client.model.VplexMirror in project coprhd-controller by CoprHD.
the class VPlexDeviceController method validateVPlexVolume.
/**
* Validates that the backend volumes of the passed VPLEX volumes in the
* ViPR database are the actual backend volumes used by the VPLEX volume
* on the VPLEX system.
*
* @param vplexSystemURI
* The URI of the VPLEX storage system.
* @param vplexVolumeURI
* The URI of the VPLEX volume to validate.
* @param stepId
* The workflow step id.
*/
public void validateVPlexVolume(URI vplexSystemURI, URI vplexVolumeURI, String stepId) {
Volume vplexVolume = null;
try {
// Skip this if validation disabled
ValidatorConfig validatorConfig = new ValidatorConfig();
validatorConfig.setCoordinator(coordinator);
if (!validatorConfig.isValidationEnabled()) {
WorkflowStepCompleter.stepSucceeded(stepId, "Validations not enabled");
return;
}
// Update step state to executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the VPLEX API client for the VPLEX system.
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystemURI, _dbClient);
// Get the VPLEX volume
vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
// Get a VolumeInfo for each backend volume and any mirrors, mapped by VPLEX cluster name.
Set<String> volumeIds = new HashSet<>();
Map<String, List<VolumeInfo>> volumeInfoMap = new HashMap<>();
StringSet associatedVolumeIds = vplexVolume.getAssociatedVolumes();
if ((associatedVolumeIds == null) || (associatedVolumeIds.isEmpty())) {
// Ingested volume w/o backend volume ingestion. We can't verify the backend volumes.
_log.info("VPLEX volume {}:{} has no backend volumes to validate", vplexVolumeURI, vplexVolume.getLabel());
WorkflowStepCompleter.stepSucceded(stepId);
return;
} else {
volumeIds.addAll(associatedVolumeIds);
}
// Now mirrors.
StringSet mirrorIds = vplexVolume.getMirrors();
if ((mirrorIds != null) && (mirrorIds.isEmpty() == false)) {
for (String mirrorId : mirrorIds) {
VplexMirror mirror = getDataObject(VplexMirror.class, URI.create(mirrorId), _dbClient);
StringSet associatedVolumeIdsForMirror = mirror.getAssociatedVolumes();
if ((associatedVolumeIdsForMirror == null) || (associatedVolumeIdsForMirror.isEmpty())) {
_log.info("VPLEX mirror {}:{} has no associated volumes", mirrorId, mirror.getLabel());
throw DeviceControllerExceptions.vplex.vplexMirrorDoesNotHaveAssociatedVolumes(vplexVolume.getLabel(), mirror.getLabel());
} else {
volumeIds.addAll(associatedVolumeIdsForMirror);
}
}
}
// Get the WWNs for these volumes mapped by VPLEX cluster name.
for (String volumesId : volumeIds) {
URI volumeURI = URI.create(volumesId);
Volume volume = getDataObject(Volume.class, volumeURI, _dbClient);
String clusterName = VPlexUtil.getVplexClusterName(volume.getVirtualArray(), vplexSystemURI, client, _dbClient);
StorageSystem storageSystem = getDataObject(StorageSystem.class, volume.getStorageController(), _dbClient);
List<String> itls = VPlexControllerUtils.getVolumeITLs(volume);
VolumeInfo volumeInfo = new VolumeInfo(storageSystem.getNativeGuid(), storageSystem.getSystemType(), volume.getWWN().toUpperCase().replaceAll(":", ""), volume.getNativeId(), volume.getThinlyProvisioned().booleanValue(), itls);
_log.info(String.format("Validating backend volume %s on cluster %s", volumeURI, clusterName));
if (volumeInfoMap.containsKey(clusterName)) {
List<VolumeInfo> clusterVolumeInfos = volumeInfoMap.get(clusterName);
clusterVolumeInfos.add(volumeInfo);
} else {
List<VolumeInfo> clusterVolumeInfos = new ArrayList<>();
clusterVolumeInfos.add(volumeInfo);
volumeInfoMap.put(clusterName, clusterVolumeInfos);
}
}
// Validate the ViPR backend volume WWNs match those on the VPLEX.
client.validateBackendVolumesForVPlexVolume(vplexVolume.getDeviceLabel(), vplexVolume.getNativeId(), volumeInfoMap);
WorkflowStepCompleter.stepSucceded(stepId);
} catch (InternalException ie) {
_log.info("Exception attempting to validate the backend volumes for VPLEX volume {}", vplexVolumeURI);
WorkflowStepCompleter.stepFailed(stepId, ie);
} catch (Exception e) {
_log.info("Exception attempting to validate the backend volumes for VPLEX volume {}", vplexVolumeURI);
ServiceCoded sc = DeviceControllerExceptions.vplex.failureValidatingVplexVolume(vplexVolumeURI.toString(), (vplexVolume != null ? vplexVolume.getLabel() : ""), e.getMessage());
WorkflowStepCompleter.stepFailed(stepId, sc);
}
}
Aggregations