/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.monitoring.cim.event;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.volumecontroller.impl.ControllerUtils;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
import com.emc.storageos.volumecontroller.impl.monitoring.cim.utility.CIMConstants;
@Component("CIMStoragePoolUpdatableDeviceEvent")
@Scope("prototype")
public class CIMStoragePoolUpdatableDeviceEvent extends
CIMInstanceRecordableDeviceEvent implements ApplicationContextAware {
/**
* Logger to log the debug statements
*/
private static final Logger _logger = LoggerFactory
.getLogger(CIMStoragePoolUpdatableDeviceEvent.class);
/**
* Overloaded constructor
*
* @param dbClient
*/
@Autowired
public CIMStoragePoolUpdatableDeviceEvent(DbClient dbClient) {
super(dbClient);
}
/**
* {@inheritDoc}
*/
@Override
protected Class<? extends DataObject> getResourceClass() {
return StoragePool.class;
}
/**
* {@inheritDoc}
*/
@Override
public String getNativeGuid() {
_logger.debug("Computing NativeGuid for VolumeView Event assoicaued with StoragePool");
if (_nativeGuid != null) {
_logger.debug("Using already computed NativeGuid : {}", _nativeGuid);
return _nativeGuid;
}
try {
_nativeGuid = NativeGUIDGenerator
.generateSPNativeGuidFromSPIndication(_indication);
logMessage("NativeGuid for StoragePool Computed as : [{}]",
new Object[] { _nativeGuid });
} catch (Exception e) {
_logger.error("Unable to compute NativeGuid :", e);
}
return _nativeGuid;
}
/**
* {@inheritDoc}
*/
@Override
public String getType() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
_applicationContext = applicationContext;
}
/**
* Log the messages. This method eliminates the logging condition check
* every time when we need to log a message.
*
* @param msg
* @param obj
*/
private void logMessage(String msg, Object[] obj) {
if (_monitoringPropertiesLoader.isToLogIndications()) {
_logger.debug("-> " + msg, obj);
}
}
/**
* {@inheritDoc}
*/
@Override
public String getRecordType() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public String getExtensions() {
return null;
}
/**
* A Utility method to get the value out of a map.
*
* @param key
* @return
*/
private String getValueFromIndication(String key) {
return _indication.get(key);
}
/**
* As part of indication we receive the capacity size in bytes and since
* Bourne platform maintains volume size in KB, capacity will be calculated
* by diving with 1024.
*
* @param freeCapacityAttributeName
* @param poolName
* @param totalCapacityAttributeName
* @param subscribedCapacityAttributeName
* @return
*/
protected boolean retriveAndProcessIndicationAttributeValues(
String freeCapacityAttribute, String poolNameAttribute,
String totalCapacityAttribute, String subscribedCapacityAttribute) {
UpdtableStoragePoolModel spModel = new UpdtableStoragePoolModel();
if (freeCapacityAttribute != null) {
spModel.setFreeCapacity(getValueFromIndication(freeCapacityAttribute));
}
if (poolNameAttribute != null) {
spModel.setPoolName(getValueFromIndication(poolNameAttribute));
}
if (subscribedCapacityAttribute != null) {
spModel.setSubscribedCapacity(getValueFromIndication(subscribedCapacityAttribute));
}
if (totalCapacityAttribute != null) {
spModel.setTotalCapacity(getValueFromIndication(totalCapacityAttribute));
}
return updateStoragePoolObject(spModel);
}
/**
* update the Storage Pool object with the available data came as part of
* indication.
*
* @return
*/
private boolean updateStoragePoolObject(UpdtableStoragePoolModel spModel) {
Long freeCapacity = spModel.getFreeCapacityInKB();
String poolName = spModel.getPoolName();
Long totalCapacity = spModel.getTotalCapacityInKB();
Long subscribedCapacity = spModel.getSubscribedCapacityInKB();
try {
StoragePool pool = retriveStoragePoolFromDatabase();
if (pool != null) {
boolean isUpdateRequired = Boolean.FALSE;
logMessage(
"==> Comparing Existing StoregPool Object with Recieved Information :\n freeCapacity: Existing Value [{}] - Recieved Value [{}], \n PoolName: Existing Value [{}] - Recieved Value [{}], \n TotalCapacity: Existing Value [{}] - Recieved Value [{}], \n SubscribedCapacity: Existing Value [{}] - Recieved Value [{}] \n",
new Object[] { pool.calculateFreeCapacityWithoutReservations(), freeCapacity,
pool.getPoolName(), poolName,
pool.getTotalCapacity(), totalCapacity,
pool.getSubscribedCapacity(),
subscribedCapacity });
if (freeCapacity != null
&& freeCapacity.longValue() != pool.calculateFreeCapacityWithoutReservations().longValue()) {
logMessage(
"Updating Free Capacity : from {} to {}",
new Object[] { pool.calculateFreeCapacityWithoutReservations(), freeCapacity });
pool.setFreeCapacity(freeCapacity);
isUpdateRequired = true;
}
if (poolName != null && !poolName.equals(pool.getPoolName())) {
logMessage("Updating Pool Name : from {} to {}",
new Object[] { pool.getPoolName(), poolName });
pool.setPoolName(poolName);
isUpdateRequired = true;
}
if (totalCapacity != null
&& totalCapacity.longValue() != pool.getTotalCapacity().longValue()) {
logMessage("Updating Total Capacity : from {} to {}",
new Object[] { pool.getTotalCapacity(),
totalCapacity });
pool.setTotalCapacity(totalCapacity);
isUpdateRequired = true;
}
if (subscribedCapacity != null
&& subscribedCapacity.longValue() != pool.getSubscribedCapacity().longValue()) {
logMessage("Updating Subscribed Capacity : from {} to {}",
new Object[] { pool.getSubscribedCapacity(),
subscribedCapacity });
pool.setSubscribedCapacity(subscribedCapacity);
isUpdateRequired = true;
}
if (isUpdateRequired) {
_dbClient.persistObject(pool);
logMessage("Storage Pool Object Updated", new Object[] {});
}
return isUpdateRequired;
} else {
_logger.debug("Indication not processed as no assosiated Storage Pool Object found");
}
} catch (IOException e) {
_logger.error(
"Error occured while retriving StoragePool Object for Corresponding Indication {}",
e.getMessage());
} catch (NumberFormatException e) {
_logger.error(
"Error occured while reading capacity data from Corresponding Indication {}",
e.getMessage());
}
return Boolean.FALSE;
}
/**
* Identifies and use VNX specific attributes to read the corresponding
* values from VNX Storage Pool indication
*
* @return
*/
public boolean updateStoragePoolObjectFromVNXStoragePoolIndication() {
return retriveAndProcessIndicationAttributeValues(
CIMConstants.STORAGE_POOL_INDICATION_FREE_CAPACITY,
CIMConstants.STORAGE_POOL_INDICATION_POOL_NAME,
CIMConstants.STORAGE_POOL_INDICATION_TOTAL_CAPACITY,
CIMConstants.STORAGE_POOL_INDICATION_SUBSCRIBED_CAPACITY);
}
/**
* Identifies and use VMAX specific attributes to read the corresponding
* values from VMAX Storage Pool indication
*
* @return
*/
public boolean updateStoragePoolObjectFromVMAXStoragePoolIndication() {
return retriveAndProcessIndicationAttributeValues(
CIMConstants.STORAGE_POOL_INDICATION_FREE_CAPACITY,
CIMConstants.STORAGE_POOL_INDICATION_POOL_NAME,
CIMConstants.STORAGE_POOL_INDICATION_TOTAL_CAPACITY,
CIMConstants.STORAGE_POOL_INDICATION_SUBSCRIBED_CAPACITY);
}
/**
* Queries the database for the existing Storage Pool Object
*
* @return an instance of StoragePool
* @throws IOException
*/
private StoragePool retriveStoragePoolFromDatabase() throws IOException {
_logger.debug("looking for Storage pool Object");
List<URI> resourceURIs = new ArrayList<URI>();
String nativeGuid = getNativeGuid();
if (nativeGuid == null) {
return null;
}
resourceURIs = _dbClient
.queryByConstraint(AlternateIdConstraint.Factory
.getStoragePoolByNativeGuidConstraint(nativeGuid));
if (resourceURIs.size() > 1) {
_logger.error(
"Multiple StoragePools found with same native guid {}",
nativeGuid);
} else if (resourceURIs.isEmpty()) {
_logger.debug("No StoragePools found with native guid {}",
nativeGuid);
} else if (resourceURIs.size() == 1) {
StoragePool pool = (StoragePool) _dbClient.queryObject(
getResourceClass(), resourceURIs.get(0));
return pool;
}
return null;
}
}
class UpdtableStoragePoolModel {
private static final Logger _logger = LoggerFactory
.getLogger(UpdtableStoragePoolModel.class);
String _freeCapacity = null;
String _totalCapacity = null;
String _poolName = null;
String _subscribedCapacity = null;
public Long getFreeCapacityInKB() {
if (_freeCapacity != null) {
try {
return ControllerUtils.convertBytesToKBytes(_freeCapacity);
} catch (NumberFormatException e) {
_logger.debug("Invalid Free Capacity value", e.getMessage());
} catch (Exception e) {
_logger.debug("Error evaluating Free Capacity", e.getMessage());
}
}
return null;
}
public Long getSubscribedCapacityInKB() {
if (_subscribedCapacity != null) {
try {
return ControllerUtils
.convertBytesToKBytes(_subscribedCapacity);
} catch (NumberFormatException e) {
_logger.debug("Invalid Subscribed Capacity value",
e.getMessage());
} catch (Exception e) {
_logger.debug("Error evaluating Subscribed Capacity",
e.getMessage());
}
}
return null;
}
public Long getTotalCapacityInKB() {
if (_totalCapacity != null) {
try {
return ControllerUtils.convertBytesToKBytes(_totalCapacity);
} catch (NumberFormatException e) {
_logger.debug("Invalid Total Capacity value", e.getMessage());
} catch (Exception e) {
_logger.debug("Error evaluating Total Capacity", e.getMessage());
}
}
return null;
}
public String getFreeCapacity() {
return _freeCapacity;
}
public void setFreeCapacity(String freeCapacity) {
_freeCapacity = freeCapacity;
}
public String getTotalCapacity() {
return _totalCapacity;
}
public void setTotalCapacity(String totalCapacity) {
_totalCapacity = totalCapacity;
}
public String getPoolName() {
return _poolName;
}
public void setPoolName(String poolName) {
_poolName = poolName;
}
public String _subscribedCapacity() {
return _subscribedCapacity;
}
public void setSubscribedCapacity(String subscribedCapacity) {
_subscribedCapacity = subscribedCapacity;
}
}