/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.externaldevice;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageProvider;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.services.util.StorageDriverManager;
import com.emc.storageos.storagedriver.model.StorageVolume;
import com.emc.storageos.storagedriver.model.VolumeClone;
import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
/**
* Utility class to capture common code and functionality
*/
public class ExternalDeviceUtils {
private static final Logger _log = LoggerFactory.getLogger(ExternalDeviceUtils.class);
private static final String EXTERNAL_DEVICE = "externalBlockStorageDevice";
private static StorageDriverManager driverManager;
private static ExternalBlockStorageDevice externalDevice;
private static synchronized StorageDriverManager getDriverManager() {
if (driverManager == null) {
driverManager = (StorageDriverManager) ControllerServiceImpl.getBean(StorageDriverManager.STORAGE_DRIVER_MANAGER);
}
return driverManager;
}
private static synchronized ExternalBlockStorageDevice getExternalDevice() {
if (externalDevice == null) {
externalDevice = (ExternalBlockStorageDevice) ControllerServiceImpl.getBean(EXTERNAL_DEVICE);
}
return externalDevice;
}
/**
* Updates the ViPR volume from the passed, newly created external device clone.
*
* @param volume A reference to the volume representing the controller clone.
* @param deviceClone A reference to the external device clone.
* @param dbClient A reference to a database client.
*
* @throws IOException When there is an issue generating the native GUID for the volume.
*/
public static void updateNewlyCreatedClone(Volume volume, VolumeClone deviceClone, DbClient dbClient) throws IOException {
volume.setNativeId(deviceClone.getNativeId());
volume.setWWN(deviceClone.getWwn());
volume.setDeviceLabel(deviceClone.getDeviceLabel());
volume.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(dbClient, volume));
volume.setReplicaState(deviceClone.getReplicationState().name());
volume.setProvisionedCapacity(deviceClone.getProvisionedCapacity());
volume.setAllocatedCapacity(deviceClone.getAllocatedCapacity());
volume.setInactive(false);
dbClient.updateObject(volume);
}
/**
* Updates the ViPR consistency group volume from the passed, newly created external
* device group clone.
*
* @param volume A reference to the volume representing the controller clone.
* @param deviceClone A reference to the external device clone.
* @param cgURI The URI of the consistency group.
* @param dbClient A reference to a database client.
*
* @throws IOException When there is an issue generating the native GUID for the volume.
*/
public static void updateNewlyCreatedGroupClone(Volume volume, VolumeClone deviceClone, URI cgURI, DbClient dbClient) throws IOException {
volume.setNativeId(deviceClone.getNativeId());
volume.setWWN(deviceClone.getWwn());
volume.setDeviceLabel(deviceClone.getDeviceLabel());
volume.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(dbClient, volume));
volume.setReplicaState(deviceClone.getReplicationState().name());
volume.setReplicationGroupInstance(deviceClone.getConsistencyGroup());
volume.setProvisionedCapacity(deviceClone.getProvisionedCapacity());
volume.setAllocatedCapacity(deviceClone.getAllocatedCapacity());
volume.setInactive(false);
// We do not associate clones with original source cg (see cop-27409)
}
/**
* Updates the ViPR volume from the passed, newly expanded external device volume to reflect
* the expanded capacity.
*
* @param volume A reference to the controller volume.
* @param deviceVolume A reference to the external device volume.
* @param dbClient A reference to a database client.
*/
public static void updateExpandedVolume(Volume volume, StorageVolume deviceVolume, DbClient dbClient) {
volume.setCapacity(deviceVolume.getRequestedCapacity());
volume.setProvisionedCapacity(deviceVolume.getProvisionedCapacity());
volume.setAllocatedCapacity(deviceVolume.getAllocatedCapacity());
dbClient.updateObject(volume);
}
/**
* Updates the ViPR volume from the passed external device clone after the clone is
* successfully restored.
*
* @param volume A reference to the Volume representing the controller clone..
* @param deviceClone A reference to the external device clone.
* @param dbClient A reference to a database client.
* @param updateDb true to update the object in the DB, false otherwise.
*/
public static void updateRestoredClone(Volume volume, VolumeClone deviceClone, DbClient dbClient, boolean updateDb) {
volume.setReplicaState(deviceClone.getReplicationState().name());
if (updateDb) {
dbClient.updateObject(volume);
}
}
/**
* Determines if the passed volume (representing a controller clone) represents the
* passed external device clone.
*
* @param volume A reference o a controller clone.
* @param deviceClone A reference to an external device clone.
* @param dbClient A reference to a database client.
*
* @return true if the controller volume represents the passed external device clone, false otherwise.
*/
public static boolean isVolumeExternalDeviceClone(Volume volume, VolumeClone deviceClone, DbClient dbClient) {
// Get the native id of the associated source volume for the controller clone.
URI assocSourceVolumeURI = volume.getAssociatedSourceVolume();
Volume assocSourceVolume = dbClient.queryObject(Volume.class, assocSourceVolumeURI);
String assocSourceVolumeNativeId = assocSourceVolume.getNativeId();
// The passed controller clone represents the passed external device clone if
// the native id of the associated source volume for the controller clone is
// the parent id of the passed device clone.
return deviceClone.getParentId().equals(assocSourceVolumeNativeId);
}
public static void updateStoragePoolCapacityAfterOperationComplete(URI storagePoolURI, URI storageSystemURI,
List<URI> volumeURIs, DbClient dbClient) {
StoragePool dbPool = dbClient.queryObject(StoragePool.class, storagePoolURI);
StorageSystem dbSystem = dbClient.queryObject(StorageSystem.class, storageSystemURI);
ExternalBlockStorageDevice.updateStoragePoolCapacity(dbPool, dbSystem,
volumeURIs, dbClient);
}
/**
* Refresh connections to driver managed providers.
*
* @param dbClient db client
* @return list of connected providers
*/
public static List<URI> refreshProviderConnections(DbClient dbClient) {
List<StorageProvider> externalProviders = new ArrayList<>();
List<URI> externalProvidersUris = new ArrayList<>();
try {
// get providers managed by drivers
driverManager = getDriverManager();
Collection<String> externalDeviceProviderTypes = driverManager.getStorageProvidersMap().values();
_log.info("Processing external provider types: {}", externalDeviceProviderTypes);
for (String providerType : externalDeviceProviderTypes) {
externalProviders.addAll(CustomQueryUtility.getActiveStorageProvidersByInterfaceType(
dbClient, providerType));
}
} catch (Exception e) {
_log.error("Failed to refresh connections for external providers.", e);
return externalProvidersUris;
}
for (StorageProvider storageProvider : externalProviders) {
try {
// Make sure external provider is connected
String providerIpAddress = storageProvider.getIPAddress();
Integer providerPortNumber = storageProvider.getPortNumber();
if (getExternalDevice().validateStorageProviderConnection(providerIpAddress, providerPortNumber)) {
storageProvider.setConnectionStatus(StorageProvider.ConnectionStatus.CONNECTED.name());
externalProvidersUris.add(storageProvider.getId());
_log.info("Storage Provider {}/{}:{} is reachable", storageProvider.getLabel(), providerIpAddress, providerPortNumber);
} else {
storageProvider.setConnectionStatus(StorageProvider.ConnectionStatus.NOTCONNECTED.name());
_log.error("Storage Provider {}/{}:{} is not reachable", storageProvider.getLabel(), providerIpAddress, providerPortNumber);
}
} catch (Exception e) {
storageProvider.setConnectionStatus(StorageProvider.ConnectionStatus.NOTCONNECTED.name());
_log.error("Storage Provider {}/{}:{} is not reachable", storageProvider.getLabel(), storageProvider.getIPAddress(), storageProvider.getPortNumber(), e);
} finally {
dbClient.updateObject(storageProvider);
}
}
return externalProvidersUris;
}
}