/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.utils.attrmatchers; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; 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.DiscoveredDataObject.Type; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.services.util.StorageDriverManager; import com.emc.storageos.vnxe.models.StorageResource; import com.emc.storageos.volumecontroller.AttributeMatcher; import com.google.common.base.Joiner; /** * FastPolicyAttrMatcher is responsible to match all the pools matching FAST policy name * given CoS. * */ public class AutoTieringPolicyMatcher extends AttributeMatcher { private static final Logger _logger = LoggerFactory.getLogger(AutoTieringPolicyMatcher.class); @Override protected List<StoragePool> matchStoragePoolsWithAttributeOn(List<StoragePool> pools, Map<String, Object> attributeMap, StringBuffer errorMessage) { String autoTieringPolicyName = attributeMap.get(Attributes.auto_tiering_policy_name.toString()).toString(); _logger.info("Pools Matching Auto Tiering Policy name attribute {} Started:{}", autoTieringPolicyName, Joiner .on("\t").join(getNativeGuidFromPools(pools))); // defensive copy List<StoragePool> filteredPoolList = new ArrayList<StoragePool>(); Set<String> fastPolicyPools = null; StringSet deviceTypes = (StringSet) attributeMap.get(Attributes.system_type.toString()); /* * 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. */ // called during implicit Pool matching // deviceTypes other than vmax or vnxblock's control will not come to this matcher itself. if (deviceTypes.contains(VirtualPool.SystemType.vnxblock.toString())) { /** return pools whose Storage System is Auto Tiering enabled */ filteredPoolList = getAutoTieringPoolsOnVnx(pools); } else if (deviceTypes.contains(VirtualPool.SystemType.vmax.toString())) { fastPolicyPools = getAutoTieringPoolsOnVMAX(autoTieringPolicyName, attributeMap); Iterator<StoragePool> poolIterator = pools.iterator(); while (poolIterator.hasNext()) { StoragePool pool = poolIterator.next(); // check whether pool matching with vpool or not. // if it doesn't match remove it from all pools. if (fastPolicyPools.contains(pool.getId().toString())) { filteredPoolList.add(pool); } else { _logger.info("Ignoring pool {} as it doesn't belongs to FAST policy.", pool.getNativeGuid()); } } } else if (deviceTypes.contains(VirtualPool.SystemType.hds.name())) { filteredPoolList = getAutoTieringPoolsOnHDS(autoTieringPolicyName, attributeMap, pools); } else if (deviceTypes.contains(VirtualPool.SystemType.vnxe.toString()) || deviceTypes.contains(VirtualPool.SystemType.unity.toString())) { filteredPoolList = getPoolsWithAutoTieringEnabled(pools); } else { Iterator<String> deviceTypesIter = deviceTypes.iterator(); if (deviceTypesIter.hasNext()) { String deviceType = deviceTypes.iterator().next(); StorageDriverManager storageDriverManager = (StorageDriverManager) StorageDriverManager.getApplicationContext().getBean( StorageDriverManager.STORAGE_DRIVER_MANAGER); if (storageDriverManager.isDriverManaged(deviceType)) { filteredPoolList = getAutoTieringPoolsOnExternalSystem(autoTieringPolicyName, attributeMap, pools); } } } _logger.info("Pools Matching Auto Tiering name Ended:{}", Joiner.on("\t").join(getNativeGuidFromPools(filteredPoolList))); if (CollectionUtils.isEmpty(filteredPoolList)) { errorMessage.append(String.format("No matching storage pool found with auto tiering policy %s. ", autoTieringPolicyName)); _logger.error(errorMessage.toString()); } return filteredPoolList; } @Override public Map<String, Set<String>> getAvailableAttribute(List<StoragePool> neighborhoodPools, URI vArrayId) { try { Set<String> policyNameSet = new HashSet<String>(); Map<String, Set<String>> availableAttrMap = new HashMap<String, Set<String>>(1); for (StoragePool pool : neighborhoodPools) { // First verify whether system has autoTieringEnabled. // If FAST is enabled on System then check Whether pool has // policies with FAST enabled. StorageSystem system = _objectCache.queryObject(StorageSystem.class, pool.getStorageDevice()); if (null != system && system.getAutoTieringEnabled()) { if (Type.vmax.toString().equalsIgnoreCase(system.getSystemType())) { policyNameSet.addAll(fetchFastPoliciesForVMAX(pool.getId())); } else if (Type.vnxblock.toString().equalsIgnoreCase(system.getSystemType())) { policyNameSet.add(AutoTieringPolicy.VnxFastPolicy.DEFAULT_START_HIGH_THEN_AUTOTIER.toString()); policyNameSet.add(AutoTieringPolicy.VnxFastPolicy.DEFAULT_AUTOTIER.toString()); policyNameSet.add(AutoTieringPolicy.VnxFastPolicy.DEFAULT_HIGHEST_AVAILABLE.toString()); policyNameSet.add(AutoTieringPolicy.VnxFastPolicy.DEFAULT_LOWEST_AVAILABLE.toString()); policyNameSet.add(AutoTieringPolicy.VnxFastPolicy.DEFAULT_NO_MOVEMENT.toString()); } else if (Type.vnxe.toString().equalsIgnoreCase(system.getSystemType()) || Type.unity.toString().equalsIgnoreCase(system.getSystemType())) { policyNameSet.add(StorageResource.TieringPolicyEnum.AUTOTIER_HIGH.name()); policyNameSet.add(StorageResource.TieringPolicyEnum.AUTOTIER.name()); policyNameSet.add(StorageResource.TieringPolicyEnum.HIGHEST.name()); policyNameSet.add(StorageResource.TieringPolicyEnum.LOWEST.name()); policyNameSet.add(StorageResource.TieringPolicyEnum.MIXED.name()); policyNameSet.add(StorageResource.TieringPolicyEnum.NO_DATA_MOVEMENT.name()); } else if (Type.hds.name().equalsIgnoreCase(system.getSystemType())) { policyNameSet.addAll(fetchTieringPoliciesForHDS(system)); } } } if (!policyNameSet.isEmpty()) { availableAttrMap.put(Attributes.fast.toString(), policyNameSet); return availableAttrMap; } } catch (Exception e) { _logger.error("Exception occurred while getting available attributes using AutoTieringPolicy Matcher.", e); } return Collections.emptyMap(); } @Override protected boolean isAttributeOn(Map<String, Object> attributeMap) { boolean status = false; if (null != attributeMap && attributeMap.containsKey(Attributes.auto_tiering_policy_name.toString()) && !((String) attributeMap.get(Attributes.auto_tiering_policy_name.toString())).equalsIgnoreCase("NONE")) { StringSet deviceTypes = (StringSet) attributeMap.get(Attributes.system_type.toString()); if (deviceTypes.contains(VirtualPool.SystemType.vmax.toString()) || deviceTypes.contains(VirtualPool.SystemType.vnxblock.toString()) || deviceTypes.contains(VirtualPool.SystemType.vnxe.toString()) || deviceTypes.contains(VirtualPool.SystemType.unity.toString()) || deviceTypes.contains(VirtualPool.SystemType.hds.name())) { status = true; } } return status; } /** * Get all storagepools associated with all the policies based on the policy name passed. * * @param policyName * @return */ private Set<String> getAutoTieringPoolsOnVMAX(String policyName, Map<String, Object> attributeMap) { Set<String> fastPolicyPools = new HashSet<String>(); URIQueryResultList result = getAutoTierPolicies(attributeMap, policyName); Iterator<URI> iterator = result.iterator(); while (iterator.hasNext()) { AutoTieringPolicy policy = _objectCache.queryObject(AutoTieringPolicy.class, iterator.next()); if (isValidAutoTieringPolicy(policy) && isAutoTieringEnabledOnStorageSystem(policy.getStorageSystem()) && doesGivenProvisionTypeMatchFastPolicy( attributeMap.get(Attributes.provisioning_type.toString()).toString(), policy)) { if (null != policy.getPools()) { fastPolicyPools.addAll(policy.getPools()); } } } return fastPolicyPools; } /** * return Pools, whose associated StorageSystem is Fast Enabled. * * @param pools * @return */ private List<StoragePool> getAutoTieringPoolsOnVnx(List<StoragePool> pools) { List<StoragePool> filteredPools = new ArrayList<StoragePool>(); // Unique Policy names field in vPool will not be set for VNX. (CTRL-8911) // vPool will have policy name, not the policy's nativeGuid for (StoragePool pool : pools) { if (isAutoTieringEnabledOnStorageSystem(pool.getStorageDevice())) { filteredPools.add(pool); } } return filteredPools; } /** * return Pools, whose storagepool is tiering capable or not. * * @param pools * @return */ private List<StoragePool> getPoolsWithAutoTieringEnabled(List<StoragePool> pools) { List<StoragePool> filteredPools = new ArrayList<StoragePool>(); for (StoragePool pool : pools) { if (pool.getAutoTieringEnabled()) { filteredPools.add(pool); } } return filteredPools; } /** * Match the pools based on the policyName selected during vpool create/update. * * @param policyName - Vpool PolicyName to match. * @param attributeMap - AttributeMap. * @param pools - Pools to match. * @return - list of matched pools. */ private List<StoragePool> getAutoTieringPoolsOnHDS(String policyName, Map<String, Object> attributeMap, List<StoragePool> pools) { boolean uniquePolicyNames = (boolean) attributeMap.get(Attributes.unique_policy_names.toString()); List<StoragePool> filteredPools = new ArrayList<StoragePool>(); List<URI> systemURIs = new ArrayList<URI>(); URIQueryResultList result = getAutoTierPolicies(attributeMap, policyName); // Iterate through the policies Iterator<URI> iterator = result.iterator(); while (iterator.hasNext()) { AutoTieringPolicy policy = _objectCache.queryObject(AutoTieringPolicy.class, iterator.next()); // If policy is tiering capable. if (policy.getPolicyEnabled() && !systemURIs.contains(policy.getStorageSystem())) { systemURIs.add(policy.getStorageSystem()); } } // process the pools and check if the pool's system matches with the policy system. for (StoragePool pool : pools) { if (pool.getAutoTieringEnabled() && systemURIs.contains(pool.getStorageDevice())) { filteredPools.add(pool); } } return filteredPools; } private boolean isAutoTieringEnabledOnStorageSystem(URI storageSystemURI) { StorageSystem system = _objectCache.queryObject(StorageSystem.class, storageSystemURI); // if fast is disabled then skip it too. if (null != system && system.getAutoTieringEnabled()) { return true; } return false; } private boolean doesGivenProvisionTypeMatchFastPolicy( String provisioningtype, AutoTieringPolicy policy) { if (null == provisioningtype || VirtualPool.ProvisioningType.NONE.toString().equalsIgnoreCase(provisioningtype)) { return true; } if (AutoTieringPolicy.ProvisioningType.All.toString().equalsIgnoreCase( policy.getProvisioningType())) { return true; } if (provisioningtype.equalsIgnoreCase(VirtualPool.ProvisioningType.Thick.toString()) && AutoTieringPolicy.ProvisioningType.ThicklyProvisioned.toString() .equalsIgnoreCase(policy.getProvisioningType())) { return true; } if (provisioningtype.equalsIgnoreCase(VirtualPool.ProvisioningType.Thin.toString()) && AutoTieringPolicy.ProvisioningType.ThinlyProvisioned.toString() .equalsIgnoreCase(policy.getProvisioningType())) { return true; } return false; } private boolean isValidAutoTieringPolicy(AutoTieringPolicy policy) { if (null == policy) { return false; } if (!policy.getPolicyEnabled()) { return false; } return true; } /** * Check whether tiering is enabled on the given system or not. * If true: fetch & return all tiering policies of the system. * If false: return nothing. * * @param device : device of the pool. * @return */ private Set<String> fetchTieringPoliciesForHDS(StorageSystem device) { Set<String> policyNameSet = new HashSet<String>(); URIQueryResultList tieringPolicyResult = new URIQueryResultList(); _objectCache.getDbClient().queryByConstraint(ContainmentConstraint.Factory .getStorageDeviceFASTPolicyConstraint(device.getId()), tieringPolicyResult); Iterator<URI> tieringPolicyItr = tieringPolicyResult.iterator(); while (tieringPolicyItr.hasNext()) { AutoTieringPolicy tierPolicy = _objectCache.queryObject( AutoTieringPolicy.class, tieringPolicyItr.next()); if (null != tierPolicy && tierPolicy.getPolicyEnabled()) { policyNameSet.add(tierPolicy.getPolicyName()); } } return policyNameSet; } /** * Verify whether policies associated with pool are FAST enabled or not for VMAX storage systems. * true: pool has FAST enabled policies. * false: pool doesn't support FAST. * * @param poolID : ID of the Pool. * @return */ private Set<String> fetchFastPoliciesForVMAX(URI poolID) { Set<String> policyNameSet = new HashSet<String>(); URIQueryResultList fastPolicyResult = new URIQueryResultList(); _objectCache.getDbClient().queryByConstraint(AlternateIdConstraint.Factory.getPoolFASTPolicyConstraint(poolID.toString()), fastPolicyResult); Iterator<URI> fastPolicyItr = fastPolicyResult.iterator(); while (fastPolicyItr.hasNext()) { AutoTieringPolicy tierPolicy = _objectCache.queryObject(AutoTieringPolicy.class, fastPolicyItr.next()); if (null != tierPolicy && tierPolicy.getPolicyEnabled()) { policyNameSet.add(tierPolicy.getPolicyName()); } } return policyNameSet; } /** * Fetches the AutoTieringPolicies from the DB for a given policyName and uniquepolicyname selection. * * @param attributeMap * @param policyName * @return */ private URIQueryResultList getAutoTierPolicies(Map<String, Object> attributeMap, String policyName) { URIQueryResultList result = new URIQueryResultList(); boolean uniquePolicyNames = (boolean) attributeMap.get(Attributes.unique_policy_names.toString()); // check if pool fast policy name is not if (!uniquePolicyNames) { _objectCache.getDbClient().queryByConstraint( AlternateIdConstraint.Factory.getAutoTieringPolicyByNativeGuidConstraint(policyName), result); } else { _objectCache.getDbClient().queryByConstraint( AlternateIdConstraint.Factory.getFASTPolicyByNameConstraint(policyName), result); } return result; } /** * Filter the passed list of storage pools to only those that match the passed auto tiering policy. * * @param policyName The auto tiering policy name. * @param attributeMap The matcher attribute map. * @param pools The complete list of pools to be filtered. * * @return The filtered list of pools matching the policy with the passed name. */ private List<StoragePool> getAutoTieringPoolsOnExternalSystem(String policyName, Map<String, Object> attributeMap, List<StoragePool> pools) { Set<String> policyPools = new HashSet<String>(); URIQueryResultList result = getAutoTierPolicies(attributeMap, policyName); Iterator<URI> iterator = result.iterator(); while (iterator.hasNext()) { AutoTieringPolicy policy = _objectCache.queryObject(AutoTieringPolicy.class, iterator.next()); if (isValidAutoTieringPolicy(policy) && isAutoTieringEnabledOnStorageSystem(policy.getStorageSystem()) && doesGivenProvisionTypeMatchFastPolicy(attributeMap.get( Attributes.provisioning_type.toString()).toString(), policy)) { if (null != policy.getPools()) { policyPools.addAll(policy.getPools()); } } } List<StoragePool> filteredPools = new ArrayList<StoragePool>(); Iterator<StoragePool> poolIterator = pools.iterator(); while (poolIterator.hasNext()) { StoragePool pool = poolIterator.next(); // check whether pool matching with vpool or not. // if it doesn't match remove it from all pools. if (policyPools.contains(pool.getId().toString())) { filteredPools.add(pool); } else { _logger.info("Ignoring pool {} as it doesn't belongs to FAST policy.", pool.getNativeGuid()); } } return filteredPools; } }