/* * Copyright (c) 2008-2011 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.fast; import static com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.processor.AutoTieringPolicyProcessorHelper.getAutoTieringPolicyByNameFromDB; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.URIUtil; 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.StorageSystem; import com.emc.storageos.db.client.model.Volume; 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.google.common.base.Strings; /** * Processor used in retrieving FAST Policies for both * VMAX and VNX. * Goal: * For a Discovered Storage System, get its associated FastPolicies * Only UserDefined Policies are considered for VMAX * Right now, due to limitations in SMI-S Model, using the predefined Global * Policies in VMAX to filter. * In case of VNX, only 4 default Policies are available. * * VmaxfastPolciies will be added to vmaxPolicyList & vnxfastPolicies added to vnxPolicyList * This list is being used later to get Tiers and corresponding Pools for vmax * and to get Volumes and Pools for vnx. * * Each policy will be associated with a default Bourne Created Device Group Name based on * Provisioning Type. All volumes created using this fast Policy Name ends up added into this * Bourne created Storage Group. * * Once the policy objects are created, we generate the expected device Group Name for the * policy based on Provisioning Type.If Provisioning Type is thickly provisioned, then * Bourne Created Device Group would be PolicyName-thickDeviceGroup, if thin, then * Policy-thinDeviceGroup, if ProvisioningType is All, then PolicyName-thinandthickDeviceGroup * * The above list of expectedDeviceGroupNames would be used later to identify whether there is a need * to create Bourne Created Storage Group for this Policy. */ public class FASTPolicyProcessor extends AbstractFASTPolicyProcessor { private Logger _logger = LoggerFactory.getLogger(FASTPolicyProcessor.class); private List<AutoTieringPolicy> _newFastPolicies; private List<AutoTieringPolicy> _updateFastPolicies; private DbClient _dbClient; public enum GlobalVMAXPolicies { GlobalThickDataMovementPolicy, GlobalThinDataMovementPolicy, GlobalWorkloadStatisticsCollectionPolicy; public static boolean contains(String policy) { try { GlobalVMAXPolicies.valueOf(policy); return true; } catch (Exception e) { return false; } } } @Override public void processResult( Operation operation, Object resultObj, Map<String, Object> keyMap) throws BaseCollectionException { try { @SuppressWarnings("unchecked") final Iterator<CIMInstance> it = (Iterator<CIMInstance>) resultObj; _newFastPolicies = new ArrayList<AutoTieringPolicy>(); _updateFastPolicies = new ArrayList<AutoTieringPolicy>(); _dbClient = (DbClient) keyMap.get(Constants.dbClient); AccessProfile profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE); URI storageSystemURI = profile.getSystemId(); Set<String> policyNames = new HashSet<String>(); boolean vnxStartHighThenAutoTierPolicyCreated = false; while (it.hasNext()) { CIMInstance policyObjectInstance = it.next(); CIMObjectPath policyObjectPath = policyObjectInstance.getObjectPath(); String systemName = policyObjectPath.getKey(Constants.SYSTEMNAME).getValue().toString(); if (!systemName.contains((String) keyMap.get(Constants._serialID))) { continue; } String[] array = systemName.split(Constants.PATH_DELIMITER_REGEX); String policyID = getFASTPolicyID(policyObjectPath); // Trim the policyID from "-+-" to "+" if necessary Boolean usingSMIS80 = (Boolean) keyMap.get(Constants.USING_SMIS80_DELIMITERS); if ((null != usingSMIS80) && (true == usingSMIS80)) { policyID = policyID.replaceAll(Constants.SMIS_80_STYLE, Constants.SMIS_PLUS_REGEX); } AutoTieringPolicy policy = getAutoTieringPolicyByNameFromDB(policyID, _dbClient); String policyRuleName = policyObjectPath.getKey(Constants.POLICYRULENAME) .getValue().toString(); policyNames.add(policyRuleName); String policyEnabled = policyObjectInstance.getPropertyValue( Constants.ENABLED).toString(); String provisioningType = AutoTieringPolicy.ProvisioningType .getType(policyObjectInstance.getPropertyValue( Constants.PROVISIONING_TYPE).toString()); /** * Only user Defined Policies are considered for VMAX * For VNX, only default policies are present, there is no concept of userDefined */ if (!Constants.SYMMETRIX.equalsIgnoreCase(array[0]) && !Constants.CLARIION.equalsIgnoreCase(array[0])) { _logger.info("Unsupported FAST Policy :{}", policyID); return; } String fastPolicyServiceConstant = getFASTPolicyServiceConstant(array[0], policyRuleName); if (null != fastPolicyServiceConstant) { createFASTPolicy(policyID, policy, policyRuleName, storageSystemURI, policyEnabled, provisioningType); addPath(keyMap, fastPolicyServiceConstant, policyObjectPath); keyMap.put(policyRuleName, policyObjectPath); if (fastPolicyServiceConstant.equals(Constants.VMAXFASTPOLICIES)) { addDeviceGroupNamesToSetUsedInVerifyingExistence(policyRuleName, keyMap, provisioningType); addDeviceGroupNamesToSetUsedInVerifyingFASTPolicyRelationShipExistence(policyRuleName, keyMap, provisioningType); } else if (fastPolicyServiceConstant.equals(Constants.VNXFASTPOLICIES) && !vnxStartHighThenAutoTierPolicyCreated) { /** * NOTE: start_high_then_auto_tier policy will not be discovered, thus must * create it for VNX in ViPR if not created already. */ String startHighThenAutoTierPolicyName = Constants.START_HIGH_THEN_AUTO_TIER_POLICY_NAME; policyNames.add(startHighThenAutoTierPolicyName); String startHighThenAutTierPolicyId = getFASTPolicyID(systemName, startHighThenAutoTierPolicyName); AutoTieringPolicy startHighThenAutTierPolicy = getAutoTieringPolicyByNameFromDB(startHighThenAutTierPolicyId, _dbClient); createFASTPolicy( startHighThenAutTierPolicyId, startHighThenAutTierPolicy, startHighThenAutoTierPolicyName, storageSystemURI, "1", AutoTieringPolicy.ProvisioningType.All.name()); vnxStartHighThenAutoTierPolicyCreated = true; } } } _dbClient.createObject(_newFastPolicies); _dbClient.persistObject(_updateFastPolicies); performPolicyBookKeeping(policyNames, storageSystemURI); } catch (Exception e) { _logger.error("FAST Policy Processing failed", e); } } /** * if the policy had been deleted from the Array, the rediscovery cycle should set the fast Policy to inactive if that policy * has no volumes associated. * * @param policyNames * @param storageSystemURI * @throws IOException */ private void performPolicyBookKeeping(Set<String> policyNames, URI storageSystemURI) throws IOException { URIQueryResultList policyList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory .getStorageDeviceFASTPolicyConstraint(storageSystemURI), policyList); Iterator<AutoTieringPolicy> policyIterator = _dbClient.queryIterativeObjects(AutoTieringPolicy.class, policyList, true); while (policyIterator.hasNext()) { AutoTieringPolicy policyObject = policyIterator.next(); String policyName = policyObject.getPolicyName(); if (Constants.START_HIGH_THEN_AUTO_TIER_POLICY_NAME.equals(policyName) || // If a VMAX3 SLO AutoTierPolicy, do not process here !Strings.isNullOrEmpty(policyObject.getVmaxSLO())) { continue; } /** * Since START_HIGH_THEN_AUTO_TIER_POLICY is ViPR created policy, no need to clean up */ if (!policyNames.contains(policyName) && !policyHasVolume(policyObject)) { policyObject.setPolicyEnabled(false); if (policyObject.getPools() != null) { policyObject.getPools().clear(); } else { _logger.info("Policy {} does not have pools", policyObject.getId()); } _logger.info("Marking Policy {}({}) inactive as it is not discovered", policyName, policyObject.getId()); policyObject.setInactive(true); _dbClient.updateObject(policyObject); } } } /** * Checks if any volume has been created with this Policy. */ private boolean policyHasVolume(AutoTieringPolicy policyObject) { // Look for volumes through pools as there is no relation index between Policy and Volume if (policyObject.getPools() != null) { for (String pool : policyObject.getPools()) { URIQueryResultList volumeList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory .getStoragePoolVolumeConstraint(URI.create(pool)), volumeList); Iterator<Volume> volumeIterator = _dbClient.queryIterativeObjects(Volume.class, volumeList, true); if (volumeIterator.hasNext()) { return true; } } } return false; } private String getFASTPolicyServiceConstant(String arrayType, String policyRuleName) { // if arrayType is symmetrix if (Constants.CLARIION.equalsIgnoreCase(arrayType)) { return Constants.VNXFASTPOLICIES; } if (Constants.SYMMETRIX.equalsIgnoreCase(arrayType) && !GlobalVMAXPolicies.contains(policyRuleName)) { return Constants.VMAXFASTPOLICIES; } return null; } /** * List of Device Group Names is used to verify whether the Storage Group already exists in Provider * * @param policyRuleName * @param keyMap */ @SuppressWarnings("unchecked") private void addDeviceGroupNamesToSetUsedInVerifyingExistence( String policyRuleName, Map<String, Object> keyMap, String provisioningType) { List<String> deviceNamesExistence = (List<String>) keyMap .get(Constants.USED_IN_CHECKING_GROUPNAMES_EXISTENCE); if (AutoTieringPolicy.ProvisioningType.ThicklyProvisioned.toString().equalsIgnoreCase( provisioningType)) { deviceNamesExistence.add(policyRuleName + Constants.HYPHEN + Constants.THICKDEVICEGROUP); } else if (AutoTieringPolicy.ProvisioningType.ThinlyProvisioned.toString() .equalsIgnoreCase(provisioningType)) { deviceNamesExistence.add(policyRuleName + Constants.HYPHEN + Constants.THINDEVICEGROUP); } else if (AutoTieringPolicy.ProvisioningType.All.toString() .equalsIgnoreCase(provisioningType)) { deviceNamesExistence .add(policyRuleName + Constants.HYPHEN + Constants.THINANDTHICKDEVICEGROUP); } } /** * List of Device Group Names is used to verify whether the Storage Group is associated with FAST Policy * already. * * @param policyRuleName * @param keyMap */ @SuppressWarnings("unchecked") private void addDeviceGroupNamesToSetUsedInVerifyingFASTPolicyRelationShipExistence( String policyRuleName, Map<String, Object> keyMap, String provisioningType) { List<String> deviceNamesPolicyRelationExistence = (List<String>) keyMap .get(Constants.USED_IN_CHECKING_GROUPNAMES_TO_FASTPOLICY); if (AutoTieringPolicy.ProvisioningType.ThicklyProvisioned.toString().equalsIgnoreCase( provisioningType)) { deviceNamesPolicyRelationExistence.add(policyRuleName + Constants.HYPHEN + Constants.THICKDEVICEGROUP); } else if (AutoTieringPolicy.ProvisioningType.ThinlyProvisioned.toString() .equalsIgnoreCase(provisioningType)) { deviceNamesPolicyRelationExistence.add(policyRuleName + Constants.HYPHEN + Constants.THINDEVICEGROUP); } else if (AutoTieringPolicy.ProvisioningType.All.toString() .equalsIgnoreCase(provisioningType)) { deviceNamesPolicyRelationExistence.add(policyRuleName + Constants.HYPHEN + Constants.THINANDTHICKDEVICEGROUP); } } /** * create FAST Policy Object * s * * @param policyName * @param policy * @throws IOException */ private void createFASTPolicy( String policyID, AutoTieringPolicy policy, String policyRuleName, URI storageSystemURI, String policyEnabled, String provisioningType) throws IOException { boolean newPolicy = false; if (null == policy) { newPolicy = true; policy = new AutoTieringPolicy(); policy.setId(URIUtil.createId(AutoTieringPolicy.class)); policy.setStorageSystem(storageSystemURI); policy.setNativeGuid(policyID); policy.setSystemType(getDeviceType(storageSystemURI)); } policy.setLabel(policyRuleName); policy.setPolicyName(policyRuleName); policy.setPolicyEnabled(policyEnabled.equalsIgnoreCase("1")); policy.setProvisioningType(provisioningType); if (newPolicy) { _newFastPolicies.add(policy); } else { _updateFastPolicies.add(policy); } } private String getDeviceType(URI storageSystemURI) throws IOException { StorageSystem system = _dbClient.queryObject(StorageSystem.class, storageSystemURI); if (null != system) { return system.getSystemType(); } return null; } /** * Filter out Global Rules in VMAX, as LocalRule alone applies for userDefinedPolicies. * Not used right now * * @param policyObjectInstance * @return boolean */ private boolean isVMAXUserDefinedPolicy(CIMInstance policyObjectInstance) { String[] rulediscriminator = (String[]) policyObjectInstance .getPropertyValue(Constants.RULEDISCRIMINATOR); if (null == rulediscriminator) { return false; } for (String rule : rulediscriminator) { if (Constants.LOCALRULE.equalsIgnoreCase(rule)) { return true; } } return false; } @Override protected void setPrerequisiteObjects(List<Object> inputArgs) throws BaseCollectionException { // TODO Auto-generated method stub } }