/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.smis;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import javax.wbem.client.WBEMClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl;
import com.emc.storageos.volumecontroller.impl.ControllerUtils;
public class SmisUtils {
private static final Logger _log = LoggerFactory.getLogger(SmisUtils.class);
public static final String SPACE_STR = " ";
public static final String SLO = "SLO";
public static final String WORKLOAD = "Workload";
/**
* Return RemainingManagedSpace of the pool.
* RemainingManagedSpace always matches with Element Managers in most of the cases.
* Capacity will not match with Element Managers, when a VNX Pool is created with UnBound raid level
* as user doesn't know the RAID to choose. FreeCapacity will match once it becomes bound.
*
* @param poolInstance
* @return
*/
public static Long getFreeCapacity(CIMInstance poolInstance) {
String freeCapacityStr = getCIMPropertyValue(poolInstance, SmisConstants.CP_REMAININGMANAGEDSPACE);
return ControllerUtils.convertBytesToKBytes(freeCapacityStr);
}
/**
* Return TotalManagedSpace of the pool.
* TotalManagedSpace always matches with Element Managers in most of the cases.
* Capacity will not match with Element Managers, when a VNX Pool is created with UnBound raid level
* as user doesn't know the RAID to choose. TotalCapacity will match once it becomes bound.
*
* @param poolInstance
* @return
*/
public static Long getTotalCapacity(CIMInstance poolInstance) {
String totalCapacityStr = getCIMPropertyValue(poolInstance, SmisConstants.CP_TOTALMANAGEDSPACE);
return ControllerUtils.convertBytesToKBytes(totalCapacityStr);
}
/**
* get Property Value;
*
* @param instance cim instance
* @param propName name of property
* @return
*/
public static String getCIMPropertyValue(CIMInstance instance, String propName) {
String value = null;
try {
value = instance.getPropertyValue(propName).toString();
} catch (Exception e) {
_log.debug("Property {} Not found in returned Instance {}", propName, instance.getObjectPath());
}
return value;
}
public static Volume checkStorageVolumeExistsInDB(String nativeGuid, DbClient dbClient)
throws IOException {
@SuppressWarnings("deprecation")
List<URI> volumeUris = dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getVolumeNativeGuidConstraint(nativeGuid));
if (!volumeUris.isEmpty()) {
Volume volume = dbClient.queryObject(Volume.class, volumeUris.get(0));
if (!volume.getInactive()) {
return volume;
}
}
return null;
}
public static void updateStoragePoolCapacity(DbClient dbClient, WBEMClient client, URI storagePoolURI) {
StorageSystem storageSystem = null;
try {
StoragePool storagePool = dbClient.queryObject(StoragePool.class, storagePoolURI);
storageSystem = dbClient.queryObject(StorageSystem.class, storagePool.getStorageDevice());
_log.info(String.format("Old storage pool capacity data for %n pool %s/%s --- %n free capacity: %s; subscribed capacity: %s",
storageSystem.getId(), storagePoolURI,
storagePool.calculateFreeCapacityWithoutReservations(),
storagePool.getSubscribedCapacity()));
// Get cim object path factory from context
CIMObjectPathFactory objectPathFactory = null;
// FIXME Shouldn't have hardcoded bean references here
if (storageSystem.getSystemType().equals(StorageSystem.Type.vmax.toString())) {
objectPathFactory = (CIMObjectPathFactory) ControllerServiceImpl.getBean("vmaxCIMObjectPathFactoryAdapter");
} else if (storageSystem.getSystemType().equals(StorageSystem.Type.vnxblock.toString())) {
objectPathFactory = (CIMObjectPathFactory) ControllerServiceImpl.getBean("vnxCIMObjectPathFactory");
} else {
String msg = String.format("Unexpected storage system type: %s for storage system %s ",
storageSystem.getSystemType(), storageSystem.getId());
_log.error(msg);
throw new RuntimeException(msg);
}
CIMObjectPath poolPath = objectPathFactory.getStoragePoolPath(storageSystem, storagePool);
CIMInstance poolInstance = client.getInstance(poolPath, true, false, null);
// Get capacity properties.
Long freePoolCapacity = getFreeCapacity(poolInstance);
String subscribedCapacity = getCIMPropertyValue(poolInstance, SmisConstants.CP_SUBSCRIBEDCAPACITY);
// Update storage pool and save to data base
storagePool.setFreeCapacity(freePoolCapacity);
if (null != subscribedCapacity) {
storagePool.setSubscribedCapacity(ControllerUtils.convertBytesToKBytes(subscribedCapacity));
}
_log.info(String.format("New storage pool capacity data for pool %n %s/%s --- %n free capacity: %s; subscribed capacity: %s",
storageSystem.getId(), storagePoolURI,
storagePool.getFreeCapacity(),
storagePool.getSubscribedCapacity()));
dbClient.persistObject(storagePool);
} catch (Exception e) {
_log.error(
String.format(
"Failed to update capacity of storage pool after volume provisioning operation. %n Storage system: %s, storage pool %s .",
storageSystem.getId(), storagePoolURI), e);
}
}
/**
* Access state of a volume is derived from the "Access" field, with an exception from the contents of the "StatusDescription" field.
*
* @param accessState simple access state, see Volume VolumeAccessState enum.
* @param statusDescriptions a string of fields that may contain "NOT_READY", and if it does, we want to mark the volume as such.
* @return the access state. Defaults to read/write
*/
public static String generateAccessState(String accessState, Collection<String> statusDescriptions) {
if ((accessState != null) && (statusDescriptions != null) && (statusDescriptions.contains(SmisConstants.NOT_READY))) {
return Volume.VolumeAccessState.NOT_READY.name();
} else if (accessState != null) {
String displayName = Volume.VolumeAccessState.getVolumeAccessStateDisplayName(accessState);
if (displayName.equals(Volume.VolumeAccessState.UNKNOWN.name())) {
return accessState;
} else {
return displayName;
}
}
return Volume.VolumeAccessState.READWRITE.name();
}
/**
* This method checks if the storage sytem is using SMIS 8.0 then translates
* the delimiter from "+" to "-+-".
*
* @param storageDevice The reference to storage system
* @param translateString The string to be translated
* @return returns translatedString if V3 provider or same string.
*/
public static String translate(StorageSystem storageDevice, String translateString) {
if (storageDevice.getUsingSmis80()) {
translateString = translateString.replaceAll(Constants.SMIS_PLUS_REGEX, Constants.SMIS80_DELIMITER_REGEX);
}
return translateString;
}
/*
* Parse target group name
*/
public static String getTargetGroupName(String instanceId, Boolean isUsingSMIS80) {
if (isUsingSMIS80) {
// for VMAX V3 instanceId, e.g., 000196700567+EMC_SMI_RG1415737386866
return instanceId.split(Constants.SMIS_PLUS_REGEX)[1];
} else {
// for VMAX V2 using 4.6.2, instanceId, e.g., 557B5BBA+1+SYMMETRIX+000195701573
return instanceId.split(Constants.SMIS_PLUS_REGEX)[0];
}
}
public static String getSLOPolicyName(CIMInstance instance) {
Object sloNameObj = instance.getPropertyValue(SmisConstants.CP_EMC_SLO);
String sloName = null, emcWorkload = null;
if (null != sloNameObj) {
sloName = String.valueOf(sloNameObj);
}
Object emcWorkloadObj = instance.getPropertyValue(SmisConstants.CP_EMC_WORKLOAD);
if (null != emcWorkloadObj) {
emcWorkload = String.valueOf(emcWorkloadObj);
}
_log.info("sloName {} emcWorkload {}", sloName, emcWorkload);
String emcFastSetting = String.valueOf(instance.getPropertyValue(SmisConstants.CP_FAST_SETTING));
_log.debug("EMCFastSetting: {}", emcFastSetting);
return formatSGSLOName(sloName, emcWorkload);
}
public static boolean checkPolicyMatchForVMAX3(String storageGroupPolicyName, String autoTierPolicyName) {
if (autoTierPolicyName.contains(storageGroupPolicyName) &&
!(autoTierPolicyName.contains(Constants.WORKLOAD) && !storageGroupPolicyName.contains(Constants.WORKLOAD))) {
return true;
} else {
return false;
}
}
/**
* Format the given EMCSLOName & EMCWorkload to understand the
* AutoTieringPolicy persisted in DB.
*
* Ex. Bronze, OLTP => Bronze SLO OLTP Workload
*
* @param sloName - SLO Name
* @param emcWorkload - Workload
* @return - formatted SLO Name.
*/
public static String formatSGSLOName(String sloName, String emcWorkload) {
if (null != sloName && sloName.length() > 0) {
StringBuffer fastSetting = new StringBuffer(sloName).append(SPACE_STR).append(SLO);
if (null != emcWorkload && emcWorkload.length() > 0) {
fastSetting.append(SPACE_STR).append(emcWorkload).append(SPACE_STR).append(WORKLOAD);
}
return fastSetting.toString();
}
return null;
}
/*
* Set settings instance for VMAX V3 only.
*
* @param StorageSytem storage
* @param sourceElementId String of source volume (or source group) ID
* @param elementName String used as ElementName when creating ReplicationSettingData during single snapshot
* creation, or RelationshipName used in CreateGroupReplica for group snapshot.
*
* @see com.emc.storageos.volumecontroller.impl.smis.vmax.VmaxSnapshotOperations#getReplicationSettingData
*
* Note elementName should be target device's DeviceID or target group ID.
*/
public static String generateVmax3SettingsInstance(StorageSystem storage, String sourceElementId, String elementName) {
// SYMMETRIX-+-000196700567-+-<sourceElementId>-+-<elementName>-+-0
StringBuilder sb = new StringBuilder("SYMMETRIX");
sb.append(Constants.SMIS80_DELIMITER)
.append(storage.getSerialNumber())
.append(Constants.SMIS80_DELIMITER).append(sourceElementId)
.append(Constants.SMIS80_DELIMITER).append(elementName)
.append(Constants.SMIS80_DELIMITER).append("0");
return sb.toString();
}
/**
* Gets the session label from settings instance.
*
* @param snapshot the snapshot
* @return the session label from settings instance
*/
public static String getSessionLabelFromSettingsInstance(BlockSnapshot snapshot) {
String sessionLabel = null;
String settingsInstance = snapshot.getSettingsInstance();
if (settingsInstance != null && !settingsInstance.isEmpty()) {
String[] instanceArray = settingsInstance.split(Constants.SMIS80_DELIMITER_REGEX);
sessionLabel = instanceArray[3];
}
return sessionLabel;
}
public static String getCompressionRatioForVolume(CIMInstance volumeInstance) {
String compressionRatio = CIMPropertyFactory.getPropertyValue(volumeInstance, SmisConstants.CP_EMC_COMPRESSION_RATIO);
if (compressionRatio != null && !compressionRatio.isEmpty() && !compressionRatio.equals("0")) {
compressionRatio = (Double.valueOf(compressionRatio) / 10) + ":1";
} else {
compressionRatio = Constants.DEFAULT_COMPRESSION_RATIO;
}
return compressionRatio;
}
public static boolean getEMCCompressionForStorageGroup(CIMInstance storageGroup) {
String emcCompression = CIMPropertyFactory.getPropertyValue(storageGroup, SmisConstants.CP_EMC_COMPRESSION);
return (emcCompression != null) ? emcCompression.equalsIgnoreCase(Boolean.TRUE.toString()) : false;
}
}