/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource.utils.vpoolvalidators;
import org.springframework.util.CollectionUtils;
import com.emc.storageos.api.service.impl.resource.utils.VirtualPoolValidator;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.StringSetMap;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.VirtualPool.ResourcePlacementPolicyType;
import com.emc.storageos.db.client.model.VirtualPool.SystemType;
import com.emc.storageos.db.client.util.CommonTransformerFunctions;
import com.emc.storageos.model.vpool.BlockVirtualPoolParam;
import com.emc.storageos.model.vpool.BlockVirtualPoolProtectionParam;
import com.emc.storageos.model.vpool.BlockVirtualPoolProtectionUpdateParam;
import com.emc.storageos.model.vpool.BlockVirtualPoolUpdateParam;
import com.emc.storageos.model.vpool.ProtectionSourcePolicy;
import com.emc.storageos.model.vpool.VirtualPoolHighAvailabilityParam;
import com.emc.storageos.model.vpool.VirtualPoolProtectionRPChanges;
import com.emc.storageos.model.vpool.VirtualPoolProtectionRPParam;
import com.emc.storageos.model.vpool.VirtualPoolRemoteMirrorProtectionParam;
import com.emc.storageos.model.vpool.VirtualPoolRemoteProtectionUpdateParam;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper;
public class PlacementPolicyValidator extends VirtualPoolValidator<BlockVirtualPoolParam, BlockVirtualPoolUpdateParam> {
@Override
public void setNextValidator(VirtualPoolValidator validator) {
_nextValidator = validator;
}
@Override
protected void validateVirtualPoolUpdateAttributeValue(
VirtualPool vPool, BlockVirtualPoolUpdateParam updateParam, DbClient dbClient) {
if (updateParam.getPlacementPolicy() == null) {
// validate policy with system type, high availability, protection update
if (ResourcePlacementPolicyType.array_affinity.name().equals(vPool.getPlacementPolicy())) {
// current placement policy is array affinity, and it is not being updated
// only need to validate with system type, high availability, protection update, not current values of those
validateSystemType(updateParam.getSystemType(), null);
validateHighAvailability(updateParam.getHighAvailability(), null);
validateProtection(updateParam.getProtection(), null);
}
} else if (isArrayAffinity(updateParam.getPlacementPolicy())) { // validate policy with system type, high availability, protection update
// or current values
validateSystemType(updateParam.getSystemType(), vPool);
validateHighAvailability(updateParam.getHighAvailability(), vPool);
validateProtection(updateParam.getProtection(), vPool);
}
}
@Override
protected boolean isUpdateAttributeOn(BlockVirtualPoolUpdateParam updateParam) {
// must validate update of system type, high availability and protection for current array affinity policy
// if policy is not being updated
return updateParam != null &&
(updateParam.getPlacementPolicy() != null || updateParam.getSystemType() != null ||
updateParam.getHighAvailability() != null || updateParam.getProtection() != null);
}
@Override
protected void validateVirtualPoolCreateAttributeValue(BlockVirtualPoolParam createParam, DbClient dbClient) {
if (isArrayAffinity(createParam.getPlacementPolicy())) {
validateSystemType(createParam.getSystemType(), null);
validateHighAvailability(createParam.getHighAvailability(), null);
validateProtection(createParam.getProtection());
}
}
@Override
protected boolean isCreateAttributeOn(BlockVirtualPoolParam createParam) {
return createParam.getPlacementPolicy() != null;
}
private boolean isArrayAffinity(String policyName) {
ResourcePlacementPolicyType policyType = ResourcePlacementPolicyType.lookup(policyName);
if (policyType == null) {
throw APIException.badRequests.unsupportedPlacementPolicy(policyName);
}
return policyType.equals(ResourcePlacementPolicyType.array_affinity);
}
/**
* Checks to see if the updated system type or current system type has the system types that support array affinity
*
* @param system systemType being updated
* @param vPool Virtual Pool (null for creating new virtual pool, or validating current value is not necessary)
*/
private void validateSystemType(String system, VirtualPool vPool) {
// validate system type is vmax/vnxblock/xtremio/unity if aray_affinity is used
// Array affinity is only supported for these array types
if (system != null) {
if (!VirtualPool.SystemType.NONE.name().equals(system)) {
SystemType systemType = SystemType.lookup(system);
if (systemType != null && !systemType.equals(SystemType.vmax) &&
!systemType.equals(SystemType.vnxblock) && !systemType.equals(SystemType.xtremio) &&
!systemType.equals(SystemType.unity)) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForSystemType(system);
}
}
} else if (vPool != null) {
StringSet systemTypes = null;
StringSetMap arrayInfo = vPool.getArrayInfo();
if (arrayInfo != null && !arrayInfo.isEmpty()) {
systemTypes = arrayInfo.get(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE);
}
if (systemTypes != null && !systemTypes.isEmpty() && !systemTypes.contains(VirtualPool.SystemType.NONE.name())) {
if (!systemTypes.contains(SystemType.vmax.name()) && !systemTypes.contains(SystemType.vnxblock.name()) && !systemTypes.contains(SystemType.xtremio.name()) &&
!systemTypes.contains(SystemType.unity.name())) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForSystemType(CommonTransformerFunctions.collectionString(systemTypes));
}
}
}
}
/**
* Validate high availability
* Array affinity policy cannot be used for VPool with high availability
*
* @param haParam VirtualPoolHighAvailabilityPara
* @param vPool Virtual Pool (null for creating new virtual pool, or validating current value is not necessary)
*/
private void validateHighAvailability(VirtualPoolHighAvailabilityParam haParam, VirtualPool vPool) {
if (haParam != null) {
if (VirtualPool.HighAvailabilityType.vplex_local.name().equals(haParam.getType()) ||
VirtualPool.HighAvailabilityType.vplex_distributed.name().equals(haParam.getType())) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForHighAvailability();
}
} else if (vPool != null) {
if (VirtualPool.vPoolSpecifiesHighAvailability(vPool) || VirtualPool.vPoolSpecifiesHighAvailabilityDistributed(vPool)) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForHighAvailability();
}
}
}
/**
* Validates protection
* Array affinity policy cannot be used for VPool with RP or remote copies
*
* @param protectionParam BlockVirtualPoolProtectionParam
*/
private void validateProtection(BlockVirtualPoolProtectionParam protectionParam) {
if (protectionParam != null) {
VirtualPoolProtectionRPParam rpParam = protectionParam.getRecoverPoint();
if (rpParam != null) {
if (!CollectionUtils.isEmpty(rpParam.getCopies())) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForRPOrRemoteCopies();
}
ProtectionSourcePolicy rpPolicy = rpParam.getSourcePolicy();
if (rpPolicy != null &&
(rpPolicy.getJournalSize() != null || rpPolicy.getJournalVarray() != null ||
rpPolicy.getJournalVpool() != null || rpPolicy.getRemoteCopyMode() != null ||
rpPolicy.getRpoType() != null || rpPolicy.getRpoValue() != null ||
rpPolicy.getStandbyJournalVarray() != null || rpPolicy.getStandbyJournalVpool() != null)) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForRPOrRemoteCopies();
}
}
VirtualPoolRemoteMirrorProtectionParam remoteProtection = protectionParam.getRemoteCopies();
if (remoteProtection != null) {
if (!CollectionUtils.isEmpty(remoteProtection.getRemoteCopySettings())) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForRPOrRemoteCopies();
}
}
}
}
/**
* Validates protection
* Array affinity policy cannot be used for VPool with RP or remote copies
*
* @param protectionParam BlockVirtualPoolProtectionUpdateParam
* @param vPool Virtual Pool (null for creating new virtual pool, or validating current value is not necessary)
*/
private void validateProtection(BlockVirtualPoolProtectionUpdateParam protectionParam, VirtualPool vPool) {
if (protectionParam != null) {
VirtualPoolProtectionRPChanges rpChanges = protectionParam.getRecoverPoint();
if (rpChanges != null) {
if ((rpChanges.getAdd() != null && !rpChanges.getAdd().isEmpty()) ||
(rpChanges.getRemove() != null && !rpChanges.getRemove().isEmpty())
|| rpChanges.getSourcePolicy() != null) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForRPOrRemoteCopies();
}
}
VirtualPoolRemoteProtectionUpdateParam remoteCopies = protectionParam.getRemoteCopies() ;
if (remoteCopies != null) {
if ((remoteCopies.getAdd() != null && !remoteCopies.getAdd().isEmpty()) ||
(remoteCopies.getRemove() != null && !remoteCopies.getRemove().isEmpty())) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForRPOrRemoteCopies();
}
}
} else if (vPool != null) {
if (VirtualPool.vPoolSpecifiesProtection(vPool) || VirtualPool.vPoolSpecifiesSRDF(vPool)) {
throw APIException.badRequests.arrayAffinityPlacementPolicyNotAllowedForRPOrRemoteCopies();
}
}
}
}