use of com.emc.storageos.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexDeviceController method forgetVolumes.
/**
* Uses the VPLREX client for the VPLEX storage system with the passed URI to
* tell the VPLERX system to forget the volumes with the passed URIs.
*
* @param vplexSystemURI
* The URI of the VPLEX storage system.
* @param volumeInfo
* The native volume information for the volumes to be forgotten.
* @param stepId
* The id of the workflow step that invoked this method.
*/
public void forgetVolumes(URI vplexSystemURI, List<VolumeInfo> volumeInfo, String stepId) {
String warnMsg = null;
String vplexSystemName = null;
try {
// Workflow step is executing.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the VPLEX client for this VPLEX system.
StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, vplexSystemURI);
vplexSystemName = vplexSystem.getLabel();
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
// Tell the VPLEX system to forget about these volumes.
client.forgetVolumes(volumeInfo);
} catch (Exception ex) {
StringBuffer forgottenVolumeInfo = new StringBuffer();
for (VolumeInfo vInfo : volumeInfo) {
if (forgottenVolumeInfo.length() != 0) {
forgottenVolumeInfo.append(", ");
}
forgottenVolumeInfo.append(vInfo.getVolumeWWN());
}
ServiceCoded sc = VPlexApiException.exceptions.forgetVolumesFailed(forgottenVolumeInfo.toString(), vplexSystemName, ex.getMessage(), ex);
warnMsg = sc.getMessage();
_log.warn(warnMsg);
}
// This is a cleanup step that we don't want to impact the
// workflow execution if it fails.
WorkflowStepCompleter.stepSucceeded(stepId, warnMsg);
}
use of com.emc.storageos.vplex.api.clientdata.VolumeInfo 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);
}
}
use of com.emc.storageos.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackCreateVirtualVolumes.
/**
* Rollback any virtual volumes previously created.
*
* @param vplexURI
* @param vplexVolumeURIs
* @param executeStepId
* - step Id of the execute step; used to retrieve rollback data.
* @param stepId
* @throws WorkflowException
*/
public void rollbackCreateVirtualVolumes(URI vplexURI, List<URI> vplexVolumeURIs, String executeStepId, String stepId) throws WorkflowException {
try {
List<List<VolumeInfo>> rollbackData = (List<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 virtual volume attempted, try and rollback.
for (List<VolumeInfo> rollbackList : rollbackData) {
client.deleteVirtualVolume(rollbackList);
}
}
WorkflowStepCompleter.stepSucceded(stepId);
} catch (VPlexApiException vae) {
_log.error("Exception rollback VPlex Virtual Volume create: " + vae.getLocalizedMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception ex) {
_log.error("Exception rollback VPlex Virtual Volume create: " + ex.getLocalizedMessage(), ex);
ServiceError serviceError = VPlexApiException.errors.createVirtualVolumesRollbackFailed(stepId, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
use of com.emc.storageos.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexApiVirtualVolumeManager method claimStorageVolumes.
/**
* Claims the VPlex volumes in the passed map.
*
* @param storageVolumeInfoMap The VPlex volumes to claim.
* @param preserveData true if the native volume data should be preserved
* during virtual volume creation.
*
* @throws VPlexApiException When an error occurs claiming the volumes.
*/
void claimStorageVolumes(Map<VolumeInfo, VPlexStorageVolumeInfo> storageVolumeInfoMap, boolean preserveData) throws VPlexApiException {
URI requestURI = _vplexApiClient.getBaseURI().resolve(VPlexApiConstants.URI_CLAIM_VOLUME);
s_logger.info("Claim storage volumes URI is {}", requestURI.toString());
Iterator<Entry<VolumeInfo, VPlexStorageVolumeInfo>> volumeIter = storageVolumeInfoMap.entrySet().iterator();
List<String> storageVolumeContextPaths = new ArrayList<String>();
while (volumeIter.hasNext()) {
ClientResponse response = null;
Entry<VolumeInfo, VPlexStorageVolumeInfo> entry = volumeIter.next();
VolumeInfo volumeInfo = entry.getKey();
String volumeName = volumeInfo.getVolumeName();
s_logger.info("Claiming volume {}", volumeInfo.getVolumeWWN());
try {
VPlexStorageVolumeInfo storageVolumeInfo = entry.getValue();
Map<String, String> argsMap = new HashMap<String, String>();
argsMap.put(VPlexApiConstants.ARG_DASH_D, storageVolumeInfo.getPath());
argsMap.put(VPlexApiConstants.ARG_DASH_N, volumeName);
if (preserveData) {
argsMap.put(VPlexApiConstants.ARG_APPC, "");
}
if (volumeInfo.getIsThinProvisioned()) {
argsMap.put(VPlexApiConstants.ARG_THIN_REBUILD, "");
}
JSONObject postDataObject = VPlexApiUtils.createPostData(argsMap, true);
s_logger.info("Claim storage volumes POST data is {}", postDataObject.toString());
response = _vplexApiClient.post(requestURI, postDataObject.toString());
String responseStr = response.getEntity(String.class);
s_logger.info("Claim storage volume response is {}", responseStr);
if (response.getStatus() != VPlexApiConstants.SUCCESS_STATUS) {
if (response.getStatus() == VPlexApiConstants.ASYNC_STATUS) {
s_logger.info("Claiming storage volume is completing asynchronously");
_vplexApiClient.waitForCompletion(response);
} else {
String cause = VPlexApiUtils.getCauseOfFailureFromResponse(responseStr);
throw VPlexApiException.exceptions.claimVolumeFailureStatus(volumeInfo.getVolumeWWN(), String.valueOf(response.getStatus()), cause);
}
}
// If successfully claimed, update the VPlex storage volume
// info with the name assigned when the volume was claimed.
storageVolumeInfo.setName(volumeName);
// Also, update the context path.
String currentPath = storageVolumeInfo.getPath();
int endIndex = currentPath.lastIndexOf("/");
String newPath = currentPath.substring(0, endIndex + 1) + volumeName;
storageVolumeInfo.setPath(newPath);
s_logger.info("Successfully claimed storage volume {}", volumeInfo.getVolumeWWN());
// Update storage volumes contexts to be refreshed.
String contextPath = currentPath.substring(0, endIndex);
if (!storageVolumeContextPaths.contains(contextPath)) {
storageVolumeContextPaths.add(contextPath);
}
} catch (VPlexApiException vae) {
throw vae;
} catch (Exception e) {
throw VPlexApiException.exceptions.failedClaimVolume(volumeInfo.getVolumeWWN(), e);
} finally {
if (response != null) {
response.close();
}
}
}
// Workaround for VPLEX issue zeph-q34217 as seen in Jira 9121
_vplexApiClient.getDiscoveryManager().refreshContexts(storageVolumeContextPaths);
}
use of com.emc.storageos.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexApiVirtualVolumeManager method createDeviceAndAttachAsMirror.
/**
* Creates and attaches mirror device to the source device.
*
* @param virtualVolume The virtual volume information to which mirror will be attached
* @param nativeVolumeInfoList The native volume information.
* @param discoveryRequired true if the passed native volumes are newly
* exported and need to be discovered by the VPlex.
* @param preserveData true if the native volume data should be preserved
* during mirror device creation.
*
* @return The VPlex device info that is attached as a mirror.
*
* @throws VPlexApiException When an error occurs creating and attaching device as a mirror
*/
VPlexDeviceInfo createDeviceAndAttachAsMirror(VPlexVirtualVolumeInfo virtualVolume, List<VolumeInfo> nativeVolumeInfoList, boolean discoveryRequired, boolean preserveData) throws VPlexApiException {
if (nativeVolumeInfoList.size() != 1) {
throw VPlexApiException.exceptions.oneDeviceRequiredForMirror();
}
// Find the storage volumes corresponding to the passed native
// volume information, discovery them if required.
List<VPlexClusterInfo> clusterInfoList = new ArrayList<VPlexClusterInfo>();
Map<VolumeInfo, VPlexStorageVolumeInfo> storageVolumeInfoMap = findStorageVolumes(nativeVolumeInfoList, discoveryRequired, clusterInfoList, null);
// Claim the storage volumes
claimStorageVolumes(storageVolumeInfoMap, preserveData);
s_logger.info("Claimed storage volumes");
// clean up the VPLEX artifacts and unclaim the storage volume.
try {
// Create extents
List<VPlexStorageVolumeInfo> storageVolumeInfoList = new ArrayList<VPlexStorageVolumeInfo>();
for (VolumeInfo nativeVolumeInfo : nativeVolumeInfoList) {
storageVolumeInfoList.add(storageVolumeInfoMap.get(nativeVolumeInfo));
}
createExtents(storageVolumeInfoList);
s_logger.info("Created extents on storage volumes");
// Find the extents just created and create local devices on
// those extents.
VPlexApiDiscoveryManager discoveryMgr = _vplexApiClient.getDiscoveryManager();
List<VPlexExtentInfo> extentInfoList = discoveryMgr.findExtents(storageVolumeInfoList);
createLocalDevices(extentInfoList);
s_logger.info("Created local devices on extents");
// Find the local devices just created.There will be only one local device
List<VPlexDeviceInfo> localDevices = discoveryMgr.findLocalDevices(extentInfoList);
VPlexVirtualVolumeInfo vplexVolumeInfo = findVirtualVolumeAndUpdateInfo(virtualVolume.getName(), discoveryMgr);
String sourceDeviceName = vplexVolumeInfo.getSupportingDevice();
if (virtualVolume.getLocality().equals(VPlexApiConstants.LOCAL_VIRTUAL_VOLUME)) {
// Find the source local device.
VPlexDeviceInfo sourceLocalDevice = discoveryMgr.findLocalDevice(sourceDeviceName);
if (sourceLocalDevice == null) {
throw VPlexApiException.exceptions.cantFindLocalDevice(sourceDeviceName);
}
s_logger.info("Found the local device {}", sourceLocalDevice.getPath());
// Attach mirror device to the source volume device
deviceAttachMirror(sourceLocalDevice.getPath(), localDevices.get(0).getPath(), null);
s_logger.info("Added {} as a mirror to the source device {}", localDevices.get(0).getPath(), sourceLocalDevice.getPath());
} else {
// Find the distributed device
VPlexDistributedDeviceInfo distributedDeviceInfo = discoveryMgr.findDistributedDevice(sourceDeviceName);
if (distributedDeviceInfo == null) {
throw VPlexApiException.exceptions.cantFindDistDevice(sourceDeviceName);
}
String sourceDevicePath = null;
List<VPlexDistributedDeviceComponentInfo> ddComponents = discoveryMgr.getDistributedDeviceComponents(distributedDeviceInfo);
for (VPlexDistributedDeviceComponentInfo ddComponent : ddComponents) {
discoveryMgr.updateDistributedDeviceComponent(ddComponent);
if (ddComponent.getCluster().equals(localDevices.get(0).getCluster())) {
sourceDevicePath = ddComponent.getPath();
break;
}
}
if (sourceDevicePath == null) {
throw VPlexApiException.exceptions.couldNotFindComponentForDistDevice(distributedDeviceInfo.getName(), localDevices.get(0).getCluster());
}
// Attach mirror device to one of the device in the distributed device where
// mirror device and the source device are in the same cluster
deviceAttachMirror(sourceDevicePath, localDevices.get(0).getPath(), null);
s_logger.info("Added {} as a mirror to the device {}", localDevices.get(0).getPath(), sourceDevicePath);
}
// update the vplexVolumeInfo object so we can tell if thin-capability changed
vplexVolumeInfo = findVirtualVolumeAndUpdateInfo(virtualVolume.getName(), discoveryMgr);
virtualVolume.setThinCapable(vplexVolumeInfo.getThinCapable());
virtualVolume.setThinEnabled(vplexVolumeInfo.getThinEnabled());
// return mirror device
return localDevices.get(0);
} catch (Exception e) {
s_logger.error("Exception occurred creating mirror device");
throw e;
}
}
Aggregations