use of com.emc.storageos.db.client.model.VplexMirror in project coprhd-controller by CoprHD.
the class VPlexDeviceController method promoteMirror.
/**
* This method creates the virtual volume from the detached mirror device.
*
* @param vplexURI
* The vplex storage system URI
* @param vplexMirrorURI
* The URI of the vplex mirror that needs to be promoted to the virtual volume
* @param promoteVolumeURI
* The URI of the volume will be used as a promoted vplex volume
* @param stepId
* The worflow stepId
*
* @throws WorkflowException
* When an error occurs updating the workflow step
* state.
*/
public void promoteMirror(URI vplexURI, URI vplexMirrorURI, URI promoteVolumeURI, 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);
Volume promoteVolume = _dbClient.queryObject(Volume.class, promoteVolumeURI);
// Find virtual volume that should have been created when we did detach mirror.
// Virtual volume is created with the same name as the device name.
VPlexVirtualVolumeInfo vvInfo = client.findVirtualVolume(vplexMirror.getDeviceLabel(), null);
// Get the backend volume for this promoted VPLEX volume.
StringSet assocVolumes = vplexMirror.getAssociatedVolumes();
// Get the ViPR label for the promoted VPLEX volume.
String promotedLabel = String.format("%s-%s", sourceVplexVolume.getLabel(), vplexMirror.getLabel());
// Rename the vplex volume created using device detach mirror. If custom naming is enabled
// generate the custom name, else the name follows the default naming convention and must
// be renamed to append the "_vol" suffix.
String newVolumeName = null;
try {
if (CustomVolumeNamingUtils.isCustomVolumeNamingEnabled(customConfigHandler, DiscoveredDataObject.Type.vplex.name())) {
String customConfigName = CustomConfigConstants.CUSTOM_VOLUME_NAME;
Project project = _dbClient.queryObject(Project.class, promoteVolume.getProject().getURI());
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, promoteVolume.getTenant().getURI());
DataSource customNameDataSource = CustomVolumeNamingUtils.getCustomConfigDataSource(project, tenant, promotedLabel, vvInfo.getWwn(), null, dataSourceFactory, customConfigName, _dbClient);
if (customNameDataSource != null) {
newVolumeName = CustomVolumeNamingUtils.getCustomName(customConfigHandler, customConfigName, customNameDataSource, DiscoveredDataObject.Type.vplex.name());
}
// Rename the vplex volume created using device detach mirror,
vvInfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(vvInfo, newVolumeName, client);
promotedLabel = newVolumeName;
} else {
// Build the name for volume so as to rename the vplex volume that is created
// with the same name as the device name to follow the name pattern _vol
// as the suffix for the vplex volumes
StringBuilder volumeNameBuilder = new StringBuilder();
volumeNameBuilder.append(vplexMirror.getDeviceLabel());
volumeNameBuilder.append(VPlexApiConstants.VIRTUAL_VOLUME_SUFFIX);
newVolumeName = volumeNameBuilder.toString();
// Rename the vplex volume created using device detach mirror,
vvInfo = CustomVolumeNamingUtils.renameVolumeOnVPlex(vvInfo, newVolumeName, client);
}
} catch (Exception e) {
_log.warn(String.format("Error renaming promoted VPLEX volume %s", promoteVolumeURI), e);
}
_log.info(String.format("Renamed promoted virtual volume: %s path: %s", vvInfo.getName(), vvInfo.getPath()));
// Fill in the details for the promoted vplex volume
promoteVolume.setLabel(promotedLabel);
promoteVolume.setNativeId(vvInfo.getPath());
promoteVolume.setNativeGuid(vvInfo.getPath());
promoteVolume.setDeviceLabel(vvInfo.getName());
promoteVolume.setThinlyProvisioned(vvInfo.isThinEnabled());
promoteVolume.setWWN(vvInfo.getWwn());
// For Vplex virtual volumes set allocated capacity to 0 (cop-18608)
promoteVolume.setAllocatedCapacity(0L);
promoteVolume.setCapacity(vplexMirror.getCapacity());
promoteVolume.setProvisionedCapacity(vplexMirror.getProvisionedCapacity());
promoteVolume.setVirtualPool(vplexMirror.getVirtualPool());
promoteVolume.setVirtualArray(vplexMirror.getVirtualArray());
promoteVolume.setStorageController(vplexMirror.getStorageController());
promoteVolume.setSystemType(DiscoveredDataObject.Type.vplex.name());
promoteVolume.setPool(NullColumnValueGetter.getNullURI());
promoteVolume.setAssociatedVolumes(new StringSet(assocVolumes));
promoteVolume.setThinlyProvisioned(vplexMirror.getThinlyProvisioned());
promoteVolume.setThinVolumePreAllocationSize(vplexMirror.getThinPreAllocationSize());
// VPLEX volumes created by VIPR have syncActive set to true hence setting same value for promoted vplex
// volumes
promoteVolume.setSyncActive(true);
// Also, we update the name portion of the project and tenant URIs
// to reflect the new name. This is necessary because the API
// to search for volumes by project, extracts the name portion of the
// project URI to get the volume name.
NamedURI namedURI = promoteVolume.getProject();
namedURI.setName(promotedLabel);
promoteVolume.setProject(namedURI);
namedURI = promoteVolume.getTenant();
namedURI.setName(promotedLabel);
promoteVolume.setTenant(namedURI);
// Remove mirror from the source VPLEX volume
sourceVplexVolume.getMirrors().remove(vplexMirror.getId().toString());
_dbClient.updateObject(sourceVplexVolume);
// Delete the mirror object
_dbClient.removeObject(vplexMirror);
// Persist changes for the newly promoted volume
_dbClient.updateObject(promoteVolume);
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception promoting mirror volume: " + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception promoting mirror volume: " + ex.getMessage(), ex);
ServiceError serviceError = VPlexApiException.errors.promoteMirrorFailed(ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.db.client.model.VplexMirror in project coprhd-controller by CoprHD.
the class VPlexDeviceController method deleteMirrorDevice.
/**
* Do the delete of a VPlex mirror device .
* This is called as a Workflow Step.
* NOTE: The parameters here must match deleteMirrorDeviceMethod above (except stepId).
*
* @param vplexURI
* URI of the VPlex StorageSystem
* @param vplexMirrorURI
* 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 deleteMirrorDevice(URI vplexURI, URI vplexMirrorURI, String stepId) throws WorkflowException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexURI, _dbClient);
VplexMirror vplexMirror = getDataObject(VplexMirror.class, vplexMirrorURI, _dbClient);
if (vplexMirror.getDeviceLabel() != null) {
// Call to delete mirror device
client.deleteLocalDevice(vplexMirror.getDeviceLabel());
if (vplexMirror.getSource() != null && vplexMirror.getSource().getURI() != null) {
Volume vplexVolume = getDataObject(Volume.class, vplexMirror.getSource().getURI(), _dbClient);
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
updateThinProperty(client, vplexSystem, vplexVolume);
}
// Record VPLEX mirror delete event.
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DELETE_VOLUME_MIRROR.getEvType(true), Operation.Status.ready, OperationTypeEnum.DELETE_VOLUME_MIRROR.getDescription());
} else {
_log.info("It seems vplex mirror {} was never created, so just move to the next step.", vplexMirror.getLabel());
}
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception deleting VPlex Virtual Volume: " + vae.getMessage(), vae);
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DELETE_VOLUME_MIRROR.getEvType(true), Operation.Status.error, OperationTypeEnum.DELETE_VOLUME_MIRROR.getDescription());
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception deleting VPlex Virtual Volume: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.DELETE_VPLEX_LOCAL_MIRROR.getName();
ServiceError serviceError = VPlexApiException.errors.deleteMirrorFailed(opName, ex);
recordBourneVplexMirrorEvent(vplexMirrorURI, OperationTypeEnum.DELETE_VOLUME_MIRROR.getEvType(true), Operation.Status.error, OperationTypeEnum.DELETE_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 addStepsForDeleteVolumes.
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#deleteVolumes(java.net.URI, java.util.List,
* java.lang.String)
* <p>
* NOTE: The VolumeDescriptor list will not include the underlying Volumes. These have to be
* added to the VolumeDescriptor list before returning.
*/
@Override
public String addStepsForDeleteVolumes(Workflow workflow, String waitFor, List<VolumeDescriptor> volumes, String taskId) throws ControllerException {
try {
// Filter to get only the VPlex volumes.
List<VolumeDescriptor> vplexVolumes = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.VPLEX_VIRT_VOLUME }, new VolumeDescriptor.Type[] {});
// If there are no VPlex volumes, just return
if (vplexVolumes.isEmpty()) {
return waitFor;
}
// Check to see if there are any volumes flagged to not be fully deleted.
// This will still remove the volume from its VPLEX CG and also clean up
// any Mirrors but will leave the Virtual Volume intact on the VPLEX.
List<VolumeDescriptor> doNotDeleteDescriptors = VolumeDescriptor.getDoNotDeleteDescriptors(vplexVolumes);
List<URI> doNotFullyDeleteVolumeList = VolumeDescriptor.getVolumeURIs(doNotDeleteDescriptors);
List<URI> allVplexVolumeURIs = VolumeDescriptor.getVolumeURIs(vplexVolumes);
// Segregate by device.
Map<URI, List<VolumeDescriptor>> vplexMap = VolumeDescriptor.getDeviceMap(vplexVolumes);
// but subsequent steps will wait on all the delete virtual volumes operations to complete.
for (URI vplexURI : vplexMap.keySet()) {
String nextStepWaitFor = waitFor;
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
// First validate that the backend volumes for these VPLEX volumes are
// the actual volumes used by the VPLEX volume on the VPLEX system. We
// add this verification in case changes were made outside ViPR, such
// as a migration, that caused the backend volumes to change. We don't
// want to delete a backend volume that may in fact be used some other
// VPLEX volume.
List<URI> vplexVolumeURIs = VolumeDescriptor.getVolumeURIs(vplexMap.get(vplexURI));
for (URI vplexVolumeURI : vplexVolumeURIs) {
Volume vplexVolume = _dbClient.queryObject(Volume.class, vplexVolumeURI);
if (vplexVolume == null || vplexVolume.getInactive() == true) {
continue;
}
// Skip validation if the volume was never successfully created.
if (vplexVolume.getDeviceLabel() == null) {
_log.info("Volume {} with Id {} was never created on the VPLEX as device label is null " + "hence skip validation on delete", vplexVolume.getLabel(), vplexVolume.getId());
continue;
}
// backend volume deletion failed.
try {
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
client.findVirtualVolume(vplexVolume.getDeviceLabel(), vplexVolume.getNativeId());
} catch (VPlexApiException ex) {
if (ex.getServiceCode() == ServiceCode.VPLEX_CANT_FIND_REQUESTED_VOLUME) {
_log.info("VPlex virtual volume: " + vplexVolume.getNativeId() + " has already been deleted; will skip validation");
continue;
} else {
_log.error("Exception finding Virtual Volume", ex);
throw ex;
}
}
createWorkflowStepToValidateVPlexVolume(workflow, vplexSystem, vplexVolumeURI, waitFor);
nextStepWaitFor = VALIDATE_VPLEX_VOLUME_STEP;
}
// If there are VPlex Volumes fronting SRDF targets, handle them.
// They will need to be removed from the CG that represents the SRDF targets.
List<URI> volsForTargetCG = VPlexSrdfUtil.returnVplexSrdfTargets(_dbClient, vplexVolumeURIs);
if (!volsForTargetCG.isEmpty()) {
URI volURI = volsForTargetCG.get(0);
Volume vol = VPlexControllerUtils.getDataObject(Volume.class, volURI, _dbClient);
ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(vol);
nextStepWaitFor = consistencyGroupManager.addStepsForRemovingVolumesFromSRDFTargetCG(workflow, vplexSystem, volsForTargetCG, nextStepWaitFor);
}
workflow.createStep(VPLEX_STEP, String.format("Delete VPlex Virtual Volumes:%n%s", BlockDeviceController.getVolumesMsg(_dbClient, vplexVolumeURIs)), nextStepWaitFor, vplexURI, DiscoveredDataObject.Type.vplex.name(), this.getClass(), deleteVirtualVolumesMethod(vplexURI, vplexVolumeURIs, doNotFullyDeleteVolumeList), rollbackMethodNullMethod(), null);
}
// Make a Map of array URI to StorageSystem
Map<URI, StorageSystem> arrayMap = new HashMap<URI, StorageSystem>();
// Make a Map of StorageSystem to a list of Volume URIs to be deleted for the next Step.
Map<URI, List<URI>> arrayVolumesMap = new HashMap<URI, List<URI>>();
// 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.
// We leave the Export Groups, anticipating they will be used for other
// volumes or used later.
List<URI> backendVolURIs = new ArrayList<URI>();
for (URI vplexVolumeURI : allVplexVolumeURIs) {
Volume vplexVolume = _dbClient.queryObject(Volume.class, vplexVolumeURI);
if ((vplexVolume == null) || (vplexVolume.getInactive()) || (vplexVolume.isIngestedVolumeWithoutBackend(_dbClient)) || doNotFullyDeleteVolumeList.contains(vplexVolumeURI)) {
continue;
}
if (null == vplexVolume.getAssociatedVolumes()) {
_log.warn("VPLEX volume {} has no backend volumes. It was possibly ingested 'Virtual Volume Only'.", vplexVolume.forDisplay());
} else {
for (String assocVolumeId : vplexVolume.getAssociatedVolumes()) {
URI assocVolumeURI = new URI(assocVolumeId);
Volume volume = _dbClient.queryObject(Volume.class, assocVolumeURI);
if (volume == null || volume.getInactive() == true) {
continue;
}
StorageSystem array = arrayMap.get(volume.getStorageController());
if (array == null) {
array = _dbClient.queryObject(StorageSystem.class, volume.getStorageController());
arrayMap.put(array.getId(), array);
}
if (arrayVolumesMap.get(array.getId()) == null) {
arrayVolumesMap.put(array.getId(), new ArrayList<URI>());
}
arrayVolumesMap.get(array.getId()).add(volume.getId());
backendVolURIs.add(volume.getId());
}
}
// hence the backend volume for that mirror needs to be deleted as well.
if (vplexVolume.getMirrors() != null && !(vplexVolume.getMirrors().isEmpty())) {
for (String mirrorId : vplexVolume.getMirrors()) {
VplexMirror vplexMirror = _dbClient.queryObject(VplexMirror.class, URI.create(mirrorId));
if (vplexMirror == null || vplexMirror.getInactive() == true || vplexMirror.getAssociatedVolumes() == null) {
continue;
}
for (String assocVolumeId : vplexMirror.getAssociatedVolumes()) {
URI assocVolumeURI = new URI(assocVolumeId);
Volume volume = _dbClient.queryObject(Volume.class, assocVolumeURI);
if (volume == null || volume.getInactive() == true) {
continue;
}
StorageSystem array = arrayMap.get(volume.getStorageController());
if (array == null) {
array = _dbClient.queryObject(StorageSystem.class, volume.getStorageController());
arrayMap.put(array.getId(), array);
}
if (arrayVolumesMap.get(array.getId()) == null) {
arrayVolumesMap.put(array.getId(), new ArrayList<URI>());
}
arrayVolumesMap.get(array.getId()).add(volume.getId());
backendVolURIs.add(volume.getId());
}
}
}
}
waitFor = VPLEX_STEP;
if (vplexAddUnexportVolumeWfSteps(workflow, VPLEX_STEP, backendVolURIs, exportGroupList)) {
waitFor = UNEXPORT_STEP;
}
return waitFor;
} catch (Exception ex) {
throw VPlexApiException.exceptions.addStepsForDeleteVolumesFailed(ex);
}
}
use of com.emc.storageos.db.client.model.VplexMirror in project coprhd-controller by CoprHD.
the class VplexMirrorTaskCompleter method recordVplexMirrorOperation.
/**
* Record vplex mirror related event and audit
*
* @param dbClient db client
* @param opType operation type
* @param status operation status
* @param evDesc event description
* @param extParam parameters array from which we could generate detail
* audit message
*/
public void recordVplexMirrorOperation(DbClient dbClient, OperationTypeEnum opType, Operation.Status status, String evDesc, Object... extParam) {
try {
boolean opStatus = (Operation.Status.ready == status) ? true : false;
String evType = opType.getEvType(opStatus);
String opStage = AuditLogManager.AUDITOP_END;
_log.info("opType: {} detail: {}", opType.toString(), evType.toString() + ':' + evDesc);
VplexMirror mirror = (VplexMirror) extParam[0];
recordBourneVplexMirrorEvent(dbClient, mirror.getId(), evType, status, evDesc);
Volume volume = (Volume) extParam[1];
switch(opType) {
case CREATE_VOLUME_MIRROR:
if (opStatus) {
AuditBlockUtil.auditBlock(dbClient, opType, opStatus, opStage, mirror.getId().toString(), mirror.getLabel(), volume.getId().toString());
} else {
AuditBlockUtil.auditBlock(dbClient, opType, opStatus, opStage, mirror.getLabel(), volume.getId().toString());
}
break;
case DEACTIVATE_VOLUME_MIRROR:
case DELETE_VOLUME_MIRROR:
case DETACH_VOLUME_MIRROR:
AuditBlockUtil.auditBlock(dbClient, opType, opStatus, opStage, mirror.getId().toString(), mirror.getLabel(), volume.getId().toString());
break;
default:
_log.error("unrecognized volume mirror operation type");
}
} catch (Exception e) {
_log.error("Failed to record volume mirror operation {}, err: ", opType.toString(), e);
}
}
use of com.emc.storageos.db.client.model.VplexMirror in project coprhd-controller by CoprHD.
the class VplexMirrorTaskCompleter method recordBourneVplexMirrorEvent.
public static void recordBourneVplexMirrorEvent(DbClient dbClient, URI mirrorUri, String evtType, Operation.Status status, String desc) throws Exception {
RecordableEventManager eventManager = new RecordableEventManager();
eventManager.setDbClient(dbClient);
VplexMirror mirror = dbClient.queryObject(VplexMirror.class, mirrorUri);
RecordableBourneEvent event = ControllerUtils.convertToRecordableBourneEvent(mirror, evtType, desc, "", dbClient, ControllerUtils.BLOCK_EVENT_SERVICE, RecordType.Event.name(), ControllerUtils.BLOCK_EVENT_SOURCE);
try {
eventManager.recordEvents(event);
_log.info("Bourne {} event recorded", evtType);
} catch (Exception ex) {
_log.error("Failed to record event. Event description: {}. Error: ", evtType, ex);
}
}
Aggregations