/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.utils.attrmatchers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import com.emc.storageos.db.client.model.AutoTieringPolicy;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageTier;
import com.emc.storageos.db.client.model.StorageTier.SupportedTiers;
import com.emc.storageos.db.client.model.StringMap;
import com.emc.storageos.volumecontroller.AttributeMatcher;
import com.google.common.base.Joiner;
/**
* VNXBlockAutoTieringPolicyMatcher is responsible to match all the pools matching FAST policy name
* given CoS. This is applicable only to VNX.
* During provisioning, we should pick the right pool based on the ranking algorithm.
*
*/
public class VNXBlockAutoTieringPolicyMatcher extends AttributeMatcher {
private static final Logger _logger = LoggerFactory
.getLogger(VNXBlockAutoTieringPolicyMatcher.class);
@Override
protected boolean isAttributeOn(Map<String, Object> attributeMap) {
if (null != attributeMap
&& attributeMap.containsKey(Attributes.auto_tiering_policy_name.toString())
&& checkVNXBlockPolicyNames(attributeMap)) {
return true;
}
return false;
}
/**
* Return true if the policy is matching with the default VNX policy names.
*
* @return
*/
private boolean checkVNXBlockPolicyNames(Map<String, Object> attributeMap) {
String autoTierPolicyName = attributeMap.get(Attributes.auto_tiering_policy_name.toString()).toString();
_logger.info("Policy Name : {}", autoTierPolicyName);
// Unique Policy names field in vPool will not be set for VNX. (CTRL-8911)
// vPool will have policy name, not the policy's nativeGuid
if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_NO_MOVEMENT.toString().equalsIgnoreCase(autoTierPolicyName)
|| AutoTieringPolicy.VnxFastPolicy.DEFAULT_AUTOTIER.toString().equalsIgnoreCase(autoTierPolicyName)
|| AutoTieringPolicy.VnxFastPolicy.DEFAULT_HIGHEST_AVAILABLE.toString().equalsIgnoreCase(autoTierPolicyName)
|| AutoTieringPolicy.VnxFastPolicy.DEFAULT_LOWEST_AVAILABLE.toString().equalsIgnoreCase(autoTierPolicyName)
|| AutoTieringPolicy.VnxFastPolicy.DEFAULT_START_HIGH_THEN_AUTOTIER.toString().equalsIgnoreCase(autoTierPolicyName)) {
return true;
}
return false;
}
@Override
protected List<StoragePool> matchStoragePoolsWithAttributeOn(List<StoragePool> pools, Map<String, Object> attributeMap,
StringBuffer errorMessage) {
_logger.info("Auto Tiering Policy Matcher Started :" + Joiner.on("\t").join(getNativeGuidFromPools(pools)));
String autoTieringPolicyName = attributeMap.get(Attributes.auto_tiering_policy_name.toString()).toString();
_logger.info("Policy Name : {}", autoTieringPolicyName);
/*
* If matcher is called during provisioning, then run ranking Algorithm
* to get vnx matched pool. The reason for moving ranking algorithm to
* provisioning is, ranking algorithm was basically designed to get a
* single best matching Pool, which can be used in provisioning.Hence,
* during vpool creation, if we run ranking algorithm, we may end up in a
* single Pool in matched Pools List, which is not desired.
*/
/** Run Ranking Algorithm to get matched Pools on VNX */
List<StoragePool> filteredPoolList = returnMatchedVNXPoolsForGivenAutoTieringPolicy(pools, autoTieringPolicyName);
if (CollectionUtils.isEmpty(filteredPoolList)) {
errorMessage
.append(String.format("No matching storage pools found for the VNX Auto-tiering policy %s. ", autoTieringPolicyName));
_logger.info(errorMessage.toString());
}
return filteredPoolList;
}
/**
* Ranking Algorithm to find matched Pools
*
* NO_DATA_MOVEMENT : return all the Pools
* AUTO_TIER :
* Find Pools which contains more than one tier, if not found return all the Pools
* HIGHEST_TIER:
* Find Pools which contains max tierPercentage looping through each Derive Type starting from
* SSD,FC,SAS,NL_SAS,SATA. If a pool is being found with max tier Percentage for a given drive type,
* return the matched Pool back.If more than one pool is having the same max tier percentage, then pass
* matching pools to find max tier Percentage for the next Drive Type, and continues till we get a single
* matched Pool or the processing of all drive Types is done.
* LOWEST_TIER:
* The same logic works , by passing drive Types in reverse order.
*
* @param pools
* @param auto_tier_policy_name
* @return
*/
private List<StoragePool> returnMatchedVNXPoolsForGivenAutoTieringPolicy(
List<StoragePool> pools, String auto_tier_policy_name) {
if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_NO_MOVEMENT.toString()
.equalsIgnoreCase(auto_tier_policy_name)) {
_logger.info("Auto Tiering {} Matcher Ended {} :",
auto_tier_policy_name,
Joiner.on("\t").join(getNativeGuidFromPools(pools)));
return pools;
}
if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_AUTOTIER.toString().equalsIgnoreCase(auto_tier_policy_name) ||
AutoTieringPolicy.VnxFastPolicy.DEFAULT_START_HIGH_THEN_AUTOTIER.toString().equalsIgnoreCase(auto_tier_policy_name)) {
return getMatchingPoolsForVNXAutoTier(pools, auto_tier_policy_name);
}
return runRankingAlgorithmToGetMatchedPoolsForHighAndLowTiers(
auto_tier_policy_name, pools);
}
private List<StoragePool> runRankingAlgorithmToGetMatchedPoolsForHighAndLowTiers(
String fastPolicyName, List<StoragePool> initialPools) {
List<StoragePool> percentageFilteredPool = new ArrayList<StoragePool>(
initialPools);
List<SupportedTiers> tierTypes = getTierTypeOrderBasedOnPolicy(fastPolicyName);
// Pools got based on ordered drive Type
for (SupportedTiers tierType : tierTypes) {
// max percentage logic
percentageFilteredPool = getAvailablePoolWithMaxUtilizationPercentage(
percentageFilteredPool, tierType.toString());
if (percentageFilteredPool.size() == 1) {
break;
}
}
_logger.info("Auto Tiering {} Matcher Ended {} :", fastPolicyName,
Joiner.on("\t").join(getNativeGuidFromPools(percentageFilteredPool)));
return percentageFilteredPool;
}
private List<SupportedTiers> getTierTypeOrderBasedOnPolicy(
String autoTierPolicy) {
if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_HIGHEST_AVAILABLE.toString()
.equalsIgnoreCase(autoTierPolicy)) {
return Arrays.asList(StorageTier.SupportedTiers.SSD,
StorageTier.SupportedTiers.FC,
StorageTier.SupportedTiers.SAS,
StorageTier.SupportedTiers.SATA);
} else if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_LOWEST_AVAILABLE.toString()
.equalsIgnoreCase(autoTierPolicy)) {
return Arrays.asList(StorageTier.SupportedTiers.SATA,
StorageTier.SupportedTiers.SAS,
StorageTier.SupportedTiers.FC,
StorageTier.SupportedTiers.SSD);
}
return Collections.EMPTY_LIST;
}
private List<StoragePool> getAvailablePoolWithMaxUtilizationPercentage(
List<StoragePool> initialPools, String driveType) {
_logger.info(
"Pools Sent for finding Max Utilization Percentage for Drive Type: {} --> {}",
driveType, Joiner.on("\t").join(getNativeGuidFromPools(initialPools)));
int maxPercentage = 0;
List<StoragePool> filteredPoolList = new ArrayList<StoragePool>();
for (StoragePool pool : initialPools) {
StringMap tierUtilizationPercentage = pool.getTierUtilizationPercentage();
if (null == tierUtilizationPercentage.get(driveType)) {
continue;
}
if (Integer.parseInt(tierUtilizationPercentage.get(driveType)) > maxPercentage) {
maxPercentage = Integer
.parseInt(tierUtilizationPercentage.get(driveType));
filteredPoolList.clear();
}
if (Integer.parseInt(tierUtilizationPercentage.get(driveType)) == maxPercentage) {
filteredPoolList.add(pool);
}
}
if (filteredPoolList.isEmpty()) {
_logger.info(
" None of the Pools matching the Drive Type {}-->returning all Pools{}:",
driveType, Joiner.on("\t").join(getNativeGuidFromPools(initialPools)));
return initialPools;
}
_logger.info(" Pools matching the Drive Type {}-->returning MatchedPools{}:",
driveType, Joiner.on("\t").join(getNativeGuidFromPools(filteredPoolList)));
return filteredPoolList;
}
private List<StoragePool> getMatchingPoolsForVNXAutoTier(
List<StoragePool> initialPools, String autoTierPolicyName) {
List<StoragePool> filteredPoolList = new ArrayList<StoragePool>();
for (StoragePool pool : initialPools) {
if (null != pool.getSupportedDriveTypes()
&& !pool.getSupportedDriveTypes().isEmpty()) {
filteredPoolList.add(pool);
}
}
if (filteredPoolList.isEmpty()) {
_logger.info(
"Auto Tiering Policy Matcher Ended : None of the Pools have more than 1 Tier, returning all Pools: {}-->{}",
autoTierPolicyName, Joiner.on("\t").join(getNativeGuidFromPools(initialPools)));
return initialPools;
}
_logger.info(
"Auto Tiering Policy Matcher Ended , and returned pools having more than 1 Tier : {}-->{}",
autoTierPolicyName, Joiner.on("\t").join(getNativeGuidFromPools(filteredPoolList)));
return filteredPoolList;
}
}