/*
* Copyright (c) 2008-2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.AutoTieringPolicy;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StoragePoolSetting;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.plugins.AccessProfile;
import com.emc.storageos.plugins.BaseCollectionException;
import com.emc.storageos.plugins.common.Constants;
import com.emc.storageos.plugins.common.domainmodel.Operation;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
import com.emc.storageos.volumecontroller.impl.utils.ImplicitPoolMatcher;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.AutoTieringPolicyProcessorHelper.getAutoTieringPolicyByNameFromDB;
/**
* Each StoragePool will be associated with multiple StoragePoolSettings.
* 1. potted settings and user Settings.
* Both these settings would get discovered for a StoragePool.
*
* StoragePool Setting refers to physicalSetting. With use of physical,we determine the RAID
* level and use it to update the RAID and parity details on the corresponding StoragePools.
*/
public class StoragePoolSettingProcessor extends PoolProcessor {
private static final String INSTANCEID = "InstanceID";
private static final String DATAREDUNDANCYGOAL = "DataRedundancyGoal";
private static final String DATAREDUNDANCYMAX = "DataRedundancyMax";
private static final String DATAREDUNDANCYMIN = "DataRedundancyMin";
private static final String EMCRAIDLEVEL = "EMCRaidLevel";
private static final String EXTENTSTRIPELENGTH = "ExtentStripeLength";
private static final String EXTENTSTRIPELENGTHMAX = "ExtentStripeLengthMax";
private static final String EXTENTSTRIPELENGTHMIN = "ExtentStripeLengthMin";
private static final String PACKAGEREDUNDANCYGOAL = "PackageRedundancyGoal";
private static final String PACKAGEREDUNDANCYMAX = "PackageRedundancyMax";
private static final String PACKAGEREDUNDANCYMIN = "PackageRedundancyMin";
private static final String EMC_POTTED_SETTING = "EMCPottedSetting";
private Logger _logger = LoggerFactory.getLogger(StoragePoolSettingProcessor.class);
private DbClient _dbClient;
private AccessProfile profile = null;
private List<StoragePoolSetting> _poolsettingList = null;
private List<Object> _args;
private List<AutoTieringPolicy> newSLOList = null;
private List<AutoTieringPolicy> updateSLOList = null;
private Set<String> sloNames = null;
/**
* {@inheritDoc}
*/
@Override
public void processResult(
Operation operation, Object resultObj, Map<String, Object> keyMap)
throws BaseCollectionException {
try {
@SuppressWarnings("unchecked")
final Iterator<CIMInstance> it = (Iterator<CIMInstance>) resultObj;
profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE);
_dbClient = (DbClient) keyMap.get(Constants.dbClient);
Map<URI, StoragePool> poolsToMatchWithVpool = (Map<URI, StoragePool>) keyMap
.get(Constants.MODIFIED_STORAGEPOOLS);
_poolsettingList = new ArrayList<StoragePoolSetting>();
StorageSystem device = _dbClient.queryObject(StorageSystem.class,
profile.getSystemId());
boolean isVmax3 = device.checkIfVmax3();
if (isVmax3) {
sloNames = (Set<String>) keyMap.get(Constants.SLO_NAMES);
newSLOList = new ArrayList<>();
updateSLOList = new ArrayList<>();
}
Set<String> raidLevels = new HashSet<String>();
CIMObjectPath poolCapabilitiesPath = getObjectPathfromCIMArgument();
while (it.hasNext()) {
CIMInstance settingInstance = null;
try {
settingInstance = it.next();
String emcRaidLevel = (String) settingInstance
.getPropertyValue(EMCRAIDLEVEL);
if (!Strings.isNullOrEmpty(emcRaidLevel) && isPottedSetting(settingInstance)) {
raidLevels
.addAll(extractRaidLevelsFromSettingInstance(settingInstance));
}
if (isVmax3) {
processVMAX3SLO(device, settingInstance);
}
addPath(keyMap, operation.getResult(),
settingInstance.getObjectPath());
} catch (Exception e) {
_logger.warn("Pool Setting Discovery failed for {}-->{}",
settingInstance.getObjectPath(), getMessage(e));
}
}
String poolId = getPoolIdFromCapabilities(poolCapabilitiesPath);
StoragePool pool = checkStoragePoolExistsInDB(poolId, _dbClient, device);
if (null != pool) {
// add to modified pool list if pool's property which is required for vPool matcher, has changed.
// If the modified list already has this pool, skip the check.
if (!poolsToMatchWithVpool.containsKey(pool.getId()) &&
ImplicitPoolMatcher.checkPoolPropertiesChanged(pool.getSupportedRaidLevels(), raidLevels)) {
poolsToMatchWithVpool.put(pool.getId(), pool);
}
pool.addSupportedRaidLevels(raidLevels);
_dbClient.persistObject(pool);
attachPoolsToSLOBasedAutoTierPolicies(pool, newSLOList, updateSLOList);
}
processSLOBasedAutoTierPolicies(device, sloNames, newSLOList, updateSLOList);
} catch (Exception e) {
_logger.error("Pool Setting Discovery failed -->{}", getMessage(e));
} finally {
_poolsettingList = null;
}
}
private Set<String> extractRaidLevelsFromSettingInstance(CIMInstance settingInstance) {
// format : RAID1;RADI0;RAID2
String emcRaidLevels = (String) settingInstance.getPropertyValue(EMCRAIDLEVEL);
List<String> emcRaidLevelList = new ArrayList<String>(Arrays.asList(emcRaidLevels
.split(";")));
return new HashSet<String>(emcRaidLevelList);
}
private boolean isPottedSetting(CIMInstance settingInstance) {
return (Boolean) settingInstance.getPropertyValue(EMC_POTTED_SETTING);
}
/**
* createStoragePoolSetting
*
* @param setting
* @param settingInstance
*/
private void createStoragePoolSetting(
StoragePoolSetting setting, CIMInstance settingInstance, StorageSystem device) {
if (setting == null) {
setting = new StoragePoolSetting();
setting.setId(URIUtil.createId(StoragePoolSetting.class));
setting.setStorageSystem(profile.getSystemId());
}
setting.setPoolsettingID(getCIMPropertyValue(settingInstance, INSTANCEID));
setting.setDataRedundancyGoal(getCIMPropertyValue(settingInstance,
DATAREDUNDANCYGOAL));
setting.setDataRedundancyMax(getCIMPropertyValue(settingInstance,
DATAREDUNDANCYMAX));
setting.setDataRedundancyMin(getCIMPropertyValue(settingInstance,
DATAREDUNDANCYMIN));
setting.setExtentStripeLength(getCIMPropertyValue(settingInstance,
EXTENTSTRIPELENGTH));
setting.setExtentStripeLengthMax(getCIMPropertyValue(settingInstance,
EXTENTSTRIPELENGTHMAX));
setting.setExtentStripeLengthMin(getCIMPropertyValue(settingInstance,
EXTENTSTRIPELENGTHMIN));
setting.setRaidLevel(getCIMPropertyValue(settingInstance, EMCRAIDLEVEL));
setting.setPackageRedundancyGoal(getCIMPropertyValue(settingInstance,
PACKAGEREDUNDANCYGOAL));
setting.setPackageRedundancyMax(getCIMPropertyValue(settingInstance,
PACKAGEREDUNDANCYMAX));
setting.setPackageRedundancyMin(getCIMPropertyValue(settingInstance,
PACKAGEREDUNDANCYMIN));
setStoragePoolReference(settingInstance, setting, device);
_poolsettingList.add(setting);
}
/**
* set PoolSetting's corresponding StoragePool.
*
* @param settingInstance
* @param setting
*
*/
private void setStoragePoolReference(
CIMInstance settingInstance, StoragePoolSetting setting, StorageSystem device) {
// CLARiiON+APM00062103520+P+F+0+C+0001
String[] idformat = null;
try {
idformat = getCIMPropertyValue(settingInstance, INSTANCEID).toString().split(
"\\+");
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getStoragePoolByNativeGuidConstraint(NativeGUIDGenerator
.generateNativeGuid(device, idformat[6],
NativeGUIDGenerator.POOL)), result);
if (result.iterator().hasNext()) {
URI poolID = result.iterator().next();
setting.setStoragePool(poolID);
}
} catch (Exception e) {
_logger.warn("Storage Pool not Found :{}", idformat[6].toString());
}
}
/**
* return 1st Argument in inputArguments used to
* call this SMI-S call.
*
* @return
*/
private CIMObjectPath getObjectPathfromCIMArgument() {
Object[] arguments = (Object[]) _args.get(0);
return (CIMObjectPath) arguments[0];
}
/**
* isStoragePoolSetting present in DB.
*
* @param settingInstance
* @return
* @throws IOException
*/
private StoragePoolSetting checkStoragePoolSettingExistsInDB(
CIMInstance settingInstance) throws IOException {
StoragePoolSetting setting = null;
@SuppressWarnings("deprecation")
List<URI> settingURIs = _dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getStoragePoolSettingByIDConstraint(settingInstance.getPropertyValue(
INSTANCEID).toString()));
if (!settingURIs.isEmpty()) {
setting = _dbClient.queryObject(StoragePoolSetting.class, settingURIs.get(0));
}
return setting;
}
@Override
protected void setPrerequisiteObjects(List<Object> args)
throws BaseCollectionException {
_args = args;
}
/**
* For each AutoTierPolicy in the the given lists, asociated them to the pool
*
* @param pool [in] - StoragePool object
* @param newList [in] - List of AutoTierPolicies that were not found in the database
* @param updateList [in] - List of AutoTierPolicies that were already in the database
*/
private void attachPoolsToSLOBasedAutoTierPolicies(StoragePool pool, List<AutoTieringPolicy> newList,
List<AutoTieringPolicy> updateList) {
if (newList != null) {
for (AutoTieringPolicy newPolicy : newList) {
newPolicy.addPool(pool.getId().toString());
}
}
if (updateList != null) {
for (AutoTieringPolicy updatePolicy : updateList) {
updatePolicy.addPool(pool.getId().toString());
}
}
}
/**
* Persist the AutoTieringPolicies found in the passed in lists. Perform some checks
* and update policies that may have been removed.
*
* @param storageSystem [in] - StorageSystem that the AutoTierPolicies will belong to
* @param sloNames [in] - SLO policy native GUID names found
* @param newList [in] - List of AutoTierPolicies that were not found in the database
* @param updateList [in] - List of AutoTierPolicies that were already in the database
* @throws IOException
*/
private void processSLOBasedAutoTierPolicies(StorageSystem storageSystem, Set<String> sloNames,
List<AutoTieringPolicy> newList, List<AutoTieringPolicy> updateList)
throws IOException {
if (newList != null) {
_dbClient.createObject(newList);
}
if (updateList != null) {
_dbClient.updateAndReindexObject(updateList);
}
}
/**
* Validate that this represents a SLO setting. If it does, then process it as an AutoTierPolicy
*
* If the CIMInstance has a its EMCFastSetting populated, then this is a SLO policy
* based StoragePoolSetting. We will extract the SLOName, Workload, and Average response time.
* These will be populated in the AutoTieringPolicy object (if one needs to be created).
*
* Updates 'sloNames' list
*
* @param storageSystem [in] - StorageSystem that the setting belongs to
* @param settingInstance [in] - Should be an instance of Symm_StoragePoolSetting.
*/
private void processVMAX3SLO(StorageSystem storageSystem, CIMInstance settingInstance) {
String emcFastSetting = (String) settingInstance.getPropertyValue(Constants.EMC_FAST_SETTING);
if (!Strings.isNullOrEmpty(emcFastSetting)) {
String slo = (String) settingInstance.getPropertyValue(Constants.EMC_SLO);
Float avgResponseTimeValue = (Float) settingInstance.getPropertyValue(Constants.EMC_AVG_RESPONSE_TIME);
if (!Strings.isNullOrEmpty(slo) && !checkForNull(avgResponseTimeValue)) {
String avgResponseTime = avgResponseTimeValue.toString();
String workload = (String) settingInstance.getPropertyValue(Constants.EMC_WORKLOAD);
workload = Strings.isNullOrEmpty(workload) ? Constants.NONE : workload;
String sloName = generateSLOPolicyName(slo, workload, avgResponseTime);
sloNames.add(sloName);
// This is a SLO policy setting. We can use this to create/update an AutoTieringPolicy
String sloID = NativeGUIDGenerator.generateAutoTierPolicyNativeGuid(storageSystem.getNativeGuid(),
sloName, NativeGUIDGenerator.SLO_POLICY);
AutoTieringPolicy autoTieringPolicy = getAutoTieringPolicyByNameFromDB(sloID, _dbClient);
createOrUpdateSLOBasedAutoTierPolicy(storageSystem, autoTieringPolicy, sloID, sloName, slo,
workload, avgResponseTime);
} else {
_logger.warn(String.format("Setting %s had non-null EMCFastSetting property = '%s', " +
"but its EMCSLO and/or EMCApproxAverageResponseTime property is null/empty.",
settingInstance.getObjectPath().toString(), emcFastSetting));
}
}
}
/**
* Create or update an AutoTieringPolicy object with the passed parameters.
*
* Updates 'newSLOList' and 'updateSLOList'
*
* @param storageSystem [in] - StorageSystem that the AutoTierPolicy will belong to
* @param policy [in] - If null, implies we have to create a new one, otherwise it's an update
* @param sloID [in] - Native ID constructed based on the slo and workload
* @param sloName [in] - SLO + Workload
* @param avgResponseTime [in] - Average Expected Response time for the SLO + Workload @throws IOException
*/
private void createOrUpdateSLOBasedAutoTierPolicy(StorageSystem storageSystem, AutoTieringPolicy policy,
String sloID, String sloName, String slo, String workload,
String avgResponseTime) {
boolean newPolicy = false;
if (null == policy) {
newPolicy = true;
policy = new AutoTieringPolicy();
policy.setId(URIUtil.createId(AutoTieringPolicy.class));
policy.setStorageSystem(storageSystem.getId());
policy.setNativeGuid(sloID);
policy.setSystemType(storageSystem.getSystemType());
policy.setVmaxSLO(slo);
policy.setVmaxWorkload(workload);
}
policy.setLabel(sloName);
policy.setPolicyName(sloName);
policy.setPolicyEnabled(true);
policy.setAvgExpectedResponseTime(Double.parseDouble(avgResponseTime));
// SLO is on V3 VMAX, which only supports Thin
policy.setProvisioningType(AutoTieringPolicy.ProvisioningType.ThinlyProvisioned.name());
if (newPolicy) {
newSLOList.add(policy);
} else {
updateSLOList.add(policy);
}
}
}