Search in sources :

Example 6 with VolumeInfo

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;
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) ArrayList(java.util.ArrayList) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 7 with VolumeInfo

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);
    }
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) ApplicationAddVolumeList(com.emc.storageos.volumecontroller.ApplicationAddVolumeList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) VplexMirror(com.emc.storageos.db.client.model.VplexMirror) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 8 with VolumeInfo

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);
            }
        }
    }
}
Also used : ArrayList(java.util.ArrayList) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo)

Example 9 with VolumeInfo

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;
}
Also used : HashMap(java.util.HashMap) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo)

Example 10 with VolumeInfo

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;
    }
}
Also used : ClientResponse(com.sun.jersey.api.client.ClientResponse) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) URI(java.net.URI) JSONObject(org.codehaus.jettison.json.JSONObject)

Aggregations

VolumeInfo (com.emc.storageos.vplex.api.clientdata.VolumeInfo)25 ArrayList (java.util.ArrayList)18 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)11 VPlexVirtualVolumeInfo (com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo)11 VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)10 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)9 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)9 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)9 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)9 ControllerException (com.emc.storageos.volumecontroller.ControllerException)9 VPlexApiClient (com.emc.storageos.vplex.api.VPlexApiClient)9 WorkflowException (com.emc.storageos.workflow.WorkflowException)9 IOException (java.io.IOException)9 URISyntaxException (java.net.URISyntaxException)9 Volume (com.emc.storageos.db.client.model.Volume)8 URI (java.net.URI)8 NamedURI (com.emc.storageos.db.client.model.NamedURI)6 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)6 HashMap (java.util.HashMap)6 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)4