use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexControllerUtils method getDistributedDevicePathToClusterMap.
/**
* Returns a Map of distributed device component context
* paths from the VPLEX API to VPLEX cluster names.
*
* @param vplexUri the VPLEX to query
* @param dbClient a reference to the database client
* @return a Map of distributed device component context
* paths from the VPLEX API to VPLEX cluster names
*
* @throws VPlexApiException
*/
public static Map<String, String> getDistributedDevicePathToClusterMap(URI vplexUri, DbClient dbClient) throws VPlexApiException {
VPlexApiClient client = null;
try {
VPlexApiFactory vplexApiFactory = VPlexApiFactory.getInstance();
client = VPlexControllerUtils.getVPlexAPIClient(vplexApiFactory, vplexUri, dbClient);
} catch (URISyntaxException e) {
log.error("cannot load vplex api client", e);
}
Map<String, String> distributedDevicePathToClusterMap = Collections.emptyMap();
if (null != client) {
distributedDevicePathToClusterMap = client.getDistributedDevicePathToClusterMap();
}
return distributedDevicePathToClusterMap;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexControllerUtils method getVPlexClusterName.
/**
* Determines the cluster name based on the volume's virtual array.
*
* @param dbClient db client
* @param vplexURI The vplex system URI
* @param vaURI The virtual array URI
* @return The VPlex cluster name
* @throws Exception
* @throws URISyntaxException
*/
public static String getVPlexClusterName(DbClient dbClient, URI vaURI, URI vplexURI) {
String clusterName = null;
// Get the vplex storage system so we can a handle on the vplex client
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, dbClient);
VPlexApiClient client = null;
try {
client = VPlexControllerUtils.getVPlexAPIClient(VPlexApiFactory.getInstance(), vplexSystem, dbClient);
} catch (URISyntaxException e) {
throw VPlexApiException.exceptions.connectionFailure(vplexURI.toString());
}
String vplexCluster = ConnectivityUtil.getVplexClusterForVarray(vaURI, vplexSystem.getId(), dbClient);
if (vplexCluster.equals(ConnectivityUtil.CLUSTER_UNKNOWN)) {
throw VPlexApiException.exceptions.couldNotFindCluster(vplexCluster);
}
clusterName = client.getClusterNameForId(vplexCluster);
return clusterName;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexControllerUtils method validateSupportingDeviceStructure.
/**
* Validates that the underlying structure of the given device name
* satisfies the constraints for compatibility with ViPR. Used for
* validating unmanaged VPLEX volumes before ingestion.
*
* @param deviceName the device to validate
* @param vplexUri the VPLEX to query
* @param dbClient a reference to the database client
* @throws VPlexApiException if the device structure is incompatible with ViPR
*/
public static void validateSupportingDeviceStructure(String deviceName, URI vplexUri, DbClient dbClient) throws VPlexApiException {
VPlexApiClient client = null;
try {
VPlexApiFactory vplexApiFactory = VPlexApiFactory.getInstance();
client = VPlexControllerUtils.getVPlexAPIClient(vplexApiFactory, vplexUri, dbClient);
} catch (URISyntaxException e) {
log.error("cannot load vplex api client", e);
}
if (null != client) {
String drillDownResponse = client.getDrillDownInfoForDevice(deviceName);
if (!VPlexUtil.isDeviceStructureValid(deviceName, drillDownResponse)) {
throw VPlexApiException.exceptions.deviceStructureIsIncompatibleForIngestion(drillDownResponse);
}
} else {
throw VPlexApiException.exceptions.failedToExecuteDrillDownCommand(deviceName, "cannot load vplex api client");
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexControllerUtils method getStorageVolumeInfoForDevice.
/**
* Returns a Map of lowest-level storage-volume resource's WWN to its VPlexStorageVolumeInfo
* object for a given device name, virtual volume type, and cluster name. If
* hasMirror is true, this indicates the top-level device is composed of a
* RAID-1 mirror, so there's an extra layers of components to traverse in finding
* the lowest-level storage-volume resources.
*
* @param deviceName the name of the top-level device to look at
* @param virtualVolumeType the type of virtual volume (local or distributed)
* @param clusterName the cluster name
* @param hasMirror indicates if the top-level device is a RAID-1 mirror
* @param vplexUri the URI of the VPLEX system
* @param dbClient a reference to the database client
*
* @return a map of WWNs to VPlexStorageVolumeInfo objects
* @throws VPlexApiException
*/
public static Map<String, VPlexStorageVolumeInfo> getStorageVolumeInfoForDevice(String deviceName, String virtualVolumeType, String clusterName, boolean hasMirror, URI vplexUri, DbClient dbClient) throws VPlexApiException {
Map<String, VPlexStorageVolumeInfo> storageVolumeInfo = null;
VPlexApiClient client = null;
try {
VPlexApiFactory vplexApiFactory = VPlexApiFactory.getInstance();
client = VPlexControllerUtils.getVPlexAPIClient(vplexApiFactory, vplexUri, dbClient);
} catch (URISyntaxException e) {
log.error("cannot load vplex api client", e);
}
if (null != client) {
storageVolumeInfo = client.getStorageVolumeInfoForDevice(deviceName, virtualVolumeType, clusterName, hasMirror);
}
log.info("Backend storage volume wwns for {} are {}", deviceName, storageVolumeInfo);
return storageVolumeInfo;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexControllerUtils method cleanStaleExportMasks.
/**
* Cleans stale instances of ExportMasks from the database. A stale instance is
* one which no longer exists as a storage view on the VPLEX and also contains
* no more user added volumes.
*
* @param dbClient a reference to the database client
* @param vplexUri the VPLEX system URI
*/
public static void cleanStaleExportMasks(DbClient dbClient, URI vplexUri) {
log.info("starting clean up of stale export masks for vplex {}", vplexUri);
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasksForStorageSystem(dbClient, vplexUri);
// get a VPLEX API client for this VPLEX URI
VPlexApiClient client = null;
try {
client = VPlexControllerUtils.getVPlexAPIClient(VPlexApiFactory.getInstance(), vplexUri, dbClient);
} catch (URISyntaxException ex) {
log.error("URISyntaxException encountered: ", ex);
}
if (null == client) {
log.error("Couldn't load vplex api client, skipping stale export mask cleanup.");
return;
}
// assemble collections of storage view native ids (VPLEX API context paths)
// and export mask names (VPLEX API storage view names) for comparison with ViPR
List<VPlexStorageViewInfo> storageViewsOnDevice = client.getStorageViewsLite();
Set<String> svNativeIds = new HashSet<String>();
Set<String> svNames = new HashSet<String>();
for (VPlexStorageViewInfo sv : storageViewsOnDevice) {
svNativeIds.add(sv.getPath());
svNames.add(sv.getName());
}
// create collections to hold any stale data we find, for clean up all at once at the very end
Set<ExportMask> staleExportMasks = new HashSet<ExportMask>();
Map<ExportGroup, Set<ExportMask>> exportGroupToStaleMaskMap = new HashMap<ExportGroup, Set<ExportMask>>();
Map<URI, ExportGroup> exportGroupUriMap = new HashMap<URI, ExportGroup>();
// by ViPR in the database, but not yet created on the VPLEX device itself. skip those of course.
for (ExportMask exportMask : exportMasks) {
if (null != exportMask && !exportMask.getInactive() && (exportMask.getNativeId() != null && !exportMask.getNativeId().isEmpty())) {
// we need to check both native id and export mask name to make sure we are NOT finding the storage view.
// native id is most accurate, but greenfield ExportMasks for VPLEX don't have this property set.
// native id will be set on ingested export masks, however, and we should check it, in case the same
// storage view name is used on both vplex clusters.
// greenfield VPLEX ExportMasks will always have unique mask names on both clusters (prefixed by V1_ or V2_),
// so for greenfield export masks, we can check mask names if the native id property is not set.
boolean noNativeIdMatch = (null != exportMask.getNativeId()) && !svNativeIds.contains(exportMask.getNativeId());
boolean noMaskNameMatch = (null != exportMask.getMaskName()) && !svNames.contains(exportMask.getMaskName());
if (noNativeIdMatch || noMaskNameMatch) {
log.info("ExportMask {} is not found on VPLEX", exportMask.getMaskName());
// if any user added volumes are still present, we will not do anything with this export mask
boolean hasActiveVolumes = false;
if (exportMask.hasAnyUserAddedVolumes()) {
List<URI> userAddedVolUris = URIUtil.toURIList(exportMask.getUserAddedVolumes().values());
List<Volume> userAddedVols = dbClient.queryObject(Volume.class, userAddedVolUris);
for (Volume vol : userAddedVols) {
if (null != vol && !vol.getInactive()) {
hasActiveVolumes = true;
break;
}
}
}
if (hasActiveVolumes) {
log.warn("ExportMask {} has active user added volumes, so will not remove from database.", exportMask.forDisplay());
continue;
}
// this is a stale export mask because it doesn't exist on the VPLEX and doesn't have user-added volumes
staleExportMasks.add(exportMask);
// we need to remove this stale ExportMask from any ExportGroups that contain it.
// we use the exportGroupUriMap so that at the end of this process we will only
// be updating a single ExportGroup instance from the database in case
// multiple ExportMasks from the same ExportGroup need to be removed.
List<ExportGroup> egList = ExportUtils.getExportGroupsForMask(exportMask.getId(), dbClient);
if (!CollectionUtils.isEmpty(egList)) {
for (ExportGroup exportGroup : egList) {
// skip this one if the export group is no longer existent or active
if (null == exportGroup || exportGroup.getInactive()) {
continue;
}
// update or reuse from the cache of already-loaded ExportGroups
if (!exportGroupUriMap.containsKey(exportGroup.getId())) {
// add this one to the cache
exportGroupUriMap.put(exportGroup.getId(), exportGroup);
} else {
// just reuse the one already loaded from the database
exportGroup = exportGroupUriMap.get(exportGroup.getId());
}
// of associations at the end of this whole process
if (!exportGroupToStaleMaskMap.containsKey(exportGroup)) {
exportGroupToStaleMaskMap.put(exportGroup, new HashSet<ExportMask>());
}
exportGroupToStaleMaskMap.get(exportGroup).add(exportMask);
log.info("Stale ExportMask {} will be removed from ExportGroup {}", exportMask.getMaskName(), exportGroup.getLabel());
}
}
}
}
}
if (!CollectionUtils.isEmpty(staleExportMasks)) {
dbClient.markForDeletion(staleExportMasks);
log.info("Deleted {} stale ExportMasks from database.", staleExportMasks.size());
if (!CollectionUtils.isEmpty(exportGroupToStaleMaskMap.keySet())) {
for (Entry<ExportGroup, Set<ExportMask>> entry : exportGroupToStaleMaskMap.entrySet()) {
ExportGroup exportGroup = entry.getKey();
for (ExportMask exportMask : entry.getValue()) {
log.info("Removing ExportMask {} from ExportGroup {}", exportMask.getMaskName(), exportGroup.getLabel());
exportGroup.removeExportMask(exportMask.getId());
}
}
dbClient.updateObject(exportGroupToStaleMaskMap.keySet());
}
}
log.info("Stale Export Mask cleanup complete.");
}
Aggregations