use of com.emc.storageos.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexDeviceController method getNativeVolumeInfo.
/**
* Gets the native volume information required by the VPLEX client for
* the passed backend volumes.
*
* @param volumeURIs
* The URIs of the VPLEX backend volumes.
*
* @return A list of the native volume information for the passed backend volumes.
* If any volumes are missing or inactive, they are ignored and not returned.
*/
private List<VolumeInfo> getNativeVolumeInfo(Collection<URI> volumeURIs) {
List<VolumeInfo> nativeVolumeInfoList = new ArrayList<>();
for (URI volumeURI : volumeURIs) {
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
if (volume == null || volume.getInactive()) {
continue;
}
StorageSystem volumeSystem = getDataObject(StorageSystem.class, volume.getStorageController(), _dbClient);
List<String> itls = VPlexControllerUtils.getVolumeITLs(volume);
VolumeInfo vInfo = new VolumeInfo(volumeSystem.getNativeGuid(), volumeSystem.getSystemType(), volume.getWWN().toUpperCase().replaceAll(":", ""), volume.getNativeId(), volume.getThinlyProvisioned().booleanValue(), itls);
nativeVolumeInfoList.add(vInfo);
}
return nativeVolumeInfoList;
}
use of com.emc.storageos.vplex.api.clientdata.VolumeInfo 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.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexApiClient method validateBackendVolumesForVPlexVolume.
/**
* Validates that the backend volumes represented by the passed native volume info
* from the ViPR database are the actual backend volumes used by the passed VPLEX volume.
*
* @param virtualVolumeName The name of the VPLEX volume.
* @param virtualVolumePath The path to the VPLEX volume.
* @param nativeVolumeInfoMap The native volume info for expected backend volumes keyed by cluster name.
*
* @throws VPlexApiException When an exception occurs validating the backend volumes.
*/
public void validateBackendVolumesForVPlexVolume(String virtualVolumeName, String virtualVolumePath, Map<String, List<VolumeInfo>> nativeVolumeInfoMap) throws VPlexApiException {
s_logger.info("Validating backend volumes for VPLEX volume {}", virtualVolumeName);
// Find the VPLEX volume.
VPlexVirtualVolumeInfo vvInfo = findVirtualVolume(virtualVolumeName, virtualVolumePath);
if (vvInfo == null) {
s_logger.error("Could not find VPLEX volume {} to validate its backend volumes", virtualVolumeName);
throw VPlexApiException.exceptions.couldNotFindVolumeForValidation(virtualVolumeName);
}
// Get and validate the name of the supporting device.
String supportingDeviceName = vvInfo.getSupportingDevice();
if ((supportingDeviceName == null) || (supportingDeviceName.isEmpty())) {
s_logger.error("VPLEX volume {} does not specify a supporting device", virtualVolumeName);
throw VPlexApiException.exceptions.noSupportingDeviceForValidation(virtualVolumeName);
}
// Validate the passed storage volume info map.
String locality = vvInfo.getLocality();
Set<String> clusterNames = nativeVolumeInfoMap.keySet();
if (((VPlexVirtualVolumeInfo.Locality.distributed.name().equals(locality)) && (clusterNames.size() != 2)) || ((VPlexVirtualVolumeInfo.Locality.local.name().equals(locality)) && (clusterNames.size() != 1))) {
s_logger.error("Invalid native volume information passed for validation of VPLEX volume {}", virtualVolumeName);
throw VPlexApiException.exceptions.invalidVolumeInfoForValidation(virtualVolumeName, locality);
}
// Get the cluster information, which will get the storage volume
// information on both clusters.
List<VPlexClusterInfo> clusterInfoList = getClusterInfoDetails();
// Validate the expected backend storage volumes on each cluster.
Iterator<String> clusterNameIter = clusterNames.iterator();
while (clusterNameIter.hasNext()) {
String clusterName = clusterNameIter.next();
s_logger.info("Validating backend volumes on cluster {}", clusterName);
// Find the backend storage volumes on the cluster using the passed
// volume info for that cluster. These will be the backend volumes
// that ViPR believes are the backend volumes used by the passed
// virtual volume.
List<VolumeInfo> nativeVolumeInfoList = nativeVolumeInfoMap.get(clusterName);
List<VPlexStorageVolumeInfo> expectedStorageVolumeInfoList = new ArrayList<>();
for (VPlexClusterInfo clusterInfo : clusterInfoList) {
if (clusterInfo.getName().equals(clusterName)) {
for (VolumeInfo nativeVolumeInfo : nativeVolumeInfoList) {
VPlexStorageVolumeInfo expectedStorageVolumeInfo = clusterInfo.getStorageVolume(nativeVolumeInfo);
if (expectedStorageVolumeInfo != null) {
expectedStorageVolumeInfoList.add(expectedStorageVolumeInfo);
}
}
}
}
// Validate we found these volumes.
if (expectedStorageVolumeInfoList.size() != nativeVolumeInfoList.size()) {
s_logger.error("Did not find all expected backend volumes for VPLEX volume {}", virtualVolumeName);
throw VPlexApiException.exceptions.failFindingExpectedBackendVolumesForValidation(virtualVolumeName, nativeVolumeInfoList.size(), expectedStorageVolumeInfoList.size());
}
// Get the actual backend storage volumes used by the supporting device of
// the virtual volume on the cluster. If we are looking for 2 volumes on
// a cluster, the volume has a mirror on that cluster.
boolean hasMirror = (nativeVolumeInfoList.size() == 2);
List<VPlexStorageVolumeInfo> actualStorageVolumeInfoList = _discoveryMgr.getBackendVolumesForDeviceOnCluster(supportingDeviceName, locality, clusterName, hasMirror);
// The actual and expected storage volumes should have the same names.
for (VPlexStorageVolumeInfo expectedStorageVolumeInfo : expectedStorageVolumeInfoList) {
boolean volumeMatch = false;
String expectedStorageVolumeName = expectedStorageVolumeInfo.getName();
for (VPlexStorageVolumeInfo actualStorageVolumeInfo : actualStorageVolumeInfoList) {
String actualStorageVolumeName = actualStorageVolumeInfo.getName();
if (expectedStorageVolumeName.equalsIgnoreCase(actualStorageVolumeName)) {
s_logger.info("Validated backend volume {}", expectedStorageVolumeName);
volumeMatch = true;
break;
}
}
if (!volumeMatch) {
s_logger.error("Failed to validate storage volume {}", expectedStorageVolumeName);
throw VPlexApiException.exceptions.storageVolumeFailedValidation(virtualVolumeName, expectedStorageVolumeName);
}
}
}
}
use of com.emc.storageos.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexApiDiscoveryManager method findStorageVolumes.
/**
* Finds the volumes in the VPlex configuration identified by the passed
* native volume information.
*
* @param volumeInfoList The native volume info for the volumes to find.
* @param clusterInfoList The cluster information.
*
* @return A map of the found VPlex volumes, key'd by the native volume
* information for each volume.
*
* @throws VPlexApiException When an error occurs find the volumes.
*/
Map<VolumeInfo, VPlexStorageVolumeInfo> findStorageVolumes(List<VolumeInfo> volumeInfoList, List<VPlexClusterInfo> clusterInfoList) throws VPlexApiException {
Map<VolumeInfo, VPlexStorageVolumeInfo> storageVolumeInfoMap = new HashMap<VolumeInfo, VPlexStorageVolumeInfo>();
Iterator<VolumeInfo> volumeInfoIter = volumeInfoList.iterator();
while (volumeInfoIter.hasNext()) {
boolean volumeFound = false;
VolumeInfo volumeInfo = volumeInfoIter.next();
String storageSystemNativeGuid = volumeInfo.getStorageSystemNativeGuid();
String volumeWWN = volumeInfo.getVolumeWWN().toLowerCase();
s_logger.info("Volume WWN is {}", volumeWWN);
for (VPlexClusterInfo clusterInfo : clusterInfoList) {
if (clusterInfo.containsStorageSystem(storageSystemNativeGuid)) {
s_logger.info("Found storage system {} in cluster {}", storageSystemNativeGuid, clusterInfo.getName());
VPlexStorageVolumeInfo storageVolumeInfo = clusterInfo.getStorageVolume(volumeInfo);
if (storageVolumeInfo == null) {
s_logger.info("Storage volume with WWN {} was not found in cluster {}", volumeWWN, clusterInfo.getName());
String volumeName = volumeInfo.getVolumeName();
storageVolumeInfo = clusterInfo.getStorageVolume(volumeInfo);
if (storageVolumeInfo != null) {
// The storage volume requested for an operation is
// already claimed. For now, we just log a warning so
// that stale VPLEX artifacts associated with this
// storage volume can be easily identified and purged.
s_logger.warn("The claimed storage volume {} has WWN {}", volumeName, volumeWWN);
}
continue;
}
volumeFound = true;
s_logger.info("Found storage volume {}", storageVolumeInfo.toString());
storageVolumeInfo.setClusterId(clusterInfo.getName());
storageVolumeInfoMap.put(volumeInfo, storageVolumeInfo);
break;
}
}
if (!volumeFound) {
throw VPlexApiException.exceptions.couldNotFindStorageVolumeMatchingWWNOrITL(volumeWWN, storageSystemNativeGuid);
}
}
return storageVolumeInfoMap;
}
use of com.emc.storageos.vplex.api.clientdata.VolumeInfo in project coprhd-controller by CoprHD.
the class VPlexApiDiscoveryManager method forgetVolumes.
/**
* Causes the VPLEX to "forget" about the volumes identified by the
* passed native volume information. Typically called when the calling
* application has deleted backend volumes and wants the VPLEX to disregard
* these volumes.
*
* @param nativeVolumeInfoList The native volume information for the
* storage volumes to be forgotten.
*/
void forgetVolumes(List<VolumeInfo> nativeVolumeInfoList) throws Exception {
// For the volumes to be forgotten, map them by their
// storage system Guids.
Map<String, Set<String>> systemVolumesMap = new HashMap<String, Set<String>>();
for (VolumeInfo volumeInfo : nativeVolumeInfoList) {
String systemGuid = volumeInfo.getStorageSystemNativeGuid();
Set<String> systemVolumes = null;
if (systemVolumesMap.containsKey(systemGuid)) {
systemVolumes = systemVolumesMap.get(systemGuid);
} else {
systemVolumes = new HashSet<String>();
systemVolumesMap.put(systemGuid, systemVolumes);
}
systemVolumes.add(volumeInfo.getVolumeWWN());
}
// Rediscover the storage systems with volumes to be forgotten.
// When forgetting volumes, they have typically just been
// removed from the export group that exposes the volumes to
// the VPLEX. We need to rediscover the storage systems so the
// VPLEX sees that the storage volumes went away.
rediscoverStorageSystems(new ArrayList<String>(systemVolumesMap.keySet()));
// Sleep for a bit to be sure the VPlex completes the
// discovery prior to calling expand. Gets around
// an issue with the VPlex software not returning an
// Async code.
VPlexApiUtils.pauseThread(60000);
// Now find the context paths for the logical units that
// correspond to the volumes to be forgotten.
Map<String, Set<String>> notFoundSystemVolumesMap = new HashMap<String, Set<String>>();
Set<String> logUnitsPaths = findLogicalUnits(systemVolumesMap, notFoundSystemVolumesMap);
// an exception.
if (logUnitsPaths.isEmpty()) {
throw VPlexApiException.exceptions.logicalUnitsNotFoundForVolumes(systemVolumesMap.toString());
}
// Now tell the VPLEX to forget these logical units that were found.
try {
URI requestURI = _vplexApiClient.getBaseURI().resolve(VPlexApiConstants.URI_FORGET_LOG_UNIT);
s_logger.info("Forget logical units URI is {}", requestURI.toString());
StringBuilder argBuilder = new StringBuilder();
for (String logUnitPath : logUnitsPaths) {
if (argBuilder.length() != 0) {
argBuilder.append(",");
}
argBuilder.append(logUnitPath);
}
Map<String, String> argsMap = new HashMap<String, String>();
argsMap.put(VPlexApiConstants.ARG_DASH_U, argBuilder.toString());
JSONObject postDataObject = VPlexApiUtils.createPostData(argsMap, false);
s_logger.info("Forget logical units POST data is {}", postDataObject.toString());
ClientResponse response = _vplexApiClient.post(requestURI, postDataObject.toString());
String responseStr = response.getEntity(String.class);
s_logger.info("Forget logical units response is {}", responseStr);
int status = response.getStatus();
response.close();
if (status != VPlexApiConstants.SUCCESS_STATUS) {
if (response.getStatus() == VPlexApiConstants.ASYNC_STATUS) {
s_logger.info("Forget volumes is completing asynchronously");
_vplexApiClient.waitForCompletion(response);
} else {
String cause = VPlexApiUtils.getCauseOfFailureFromResponse(responseStr);
String errorMsg = String.format("Forget logical units failed with Status %s: %s", response.getStatus(), cause);
throw new Exception(errorMsg);
}
}
// throw an exception identifying those that were not found.
if (!notFoundSystemVolumesMap.isEmpty()) {
throw VPlexApiException.exceptions.logicalUnitsNotFoundForVolumes(notFoundSystemVolumesMap.toString());
}
s_logger.info("Successfully forgot logical units");
} catch (Exception e) {
s_logger.error("Exception forgetting logical units: %s", e.getMessage(), e);
throw e;
}
}
Aggregations