/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource.utils.vpoolvalidators; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.api.service.impl.resource.utils.VirtualPoolValidator; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.StoragePool; 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.VpoolRemoteCopyProtectionSettings; import com.emc.storageos.db.client.model.VpoolRemoteCopyProtectionSettings.CopyModes; import com.emc.storageos.model.vpool.BlockVirtualPoolParam; import com.emc.storageos.model.vpool.BlockVirtualPoolUpdateParam; import com.emc.storageos.model.vpool.VirtualPoolRemoteProtectionVirtualArraySettingsParam; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.volumecontroller.impl.smis.SRDFOperations.Mode; import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper; public class RemoteMirrorProtectionValidator extends VirtualPoolValidator<BlockVirtualPoolParam, BlockVirtualPoolUpdateParam> { private static final Logger _logger = LoggerFactory .getLogger(RemoteMirrorProtectionValidator.class); private static final String SYMMETRIX = "SYMMETRIX"; @Override public void setNextValidator(@SuppressWarnings("rawtypes") final VirtualPoolValidator validator) { _nextValidator = validator; } private void checkSystemIsVMAX(final VirtualPool cos, final BlockVirtualPoolUpdateParam updateParam) { StringSetMap arrayInfo = cos.getArrayInfo(); if ((null == arrayInfo || null == arrayInfo .get(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE)) && (null == updateParam.getSystemType() || VirtualPool.SystemType.NONE.name() .equalsIgnoreCase(updateParam.getSystemType()))) { throw APIException.badRequests .parameterOnlySupportedForVmax("SRDF Remote Protection: Check A"); } if (null != updateParam.getSystemType()) { if (!VirtualPool.SystemType.vmax.toString().equalsIgnoreCase( updateParam.getSystemType())) { throw APIException.badRequests .parameterOnlySupportedForVmax("SRDF Remote Protection"); } } else if (null != arrayInfo && null != arrayInfo.get(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE)) { StringSet deviceTypes = arrayInfo .get(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE); if (!deviceTypes.contains(VirtualPool.SystemType.vmax.toString())) { throw APIException.badRequests .parameterOnlySupportedForVmax("SRDF Remote Protection: Check C"); } } } // Only vmax arrays allowed as srdf targets private void validateSRDFTargetAsVMAX(URI virtualPool, DbClient dbClient) { if (null != virtualPool) { VirtualPool targetVPool = dbClient.queryObject(VirtualPool.class, virtualPool); List<StoragePool> targetPools = VirtualPool.getValidStoragePools(targetVPool, dbClient, true); for (StoragePool targetPool : targetPools) { if (!targetPool.getNativeGuid().toUpperCase().contains(SYMMETRIX)) { throw APIException.badRequests.vmaxAllowedOnlyAsSrdfTargets(); } } } } @Override protected void validateVirtualPoolUpdateAttributeValue(final VirtualPool vpool, final BlockVirtualPoolUpdateParam updateParam, final DbClient dbClient) { if (!VirtualPool.vPoolSpecifiesSRDF(vpool)) { // this code is not added under updateAttributeOn, as SRDF CopyModes // can be updated without altering Add or remove _logger.info("Not SRDF Specified"); return; } validateVPlexProtection(updateParam, dbClient); checkSystemIsVMAX(vpool, updateParam); Map<URI, VpoolRemoteCopyProtectionSettings> remoteSettingsMap = VirtualPool.getRemoteProtectionSettings(vpool, dbClient); if (remoteSettingsMap != null && !remoteSettingsMap.isEmpty()) { for (VpoolRemoteCopyProtectionSettings remoteSettings : remoteSettingsMap.values()) { validateSRDFTargetAsVMAX(remoteSettings.getVirtualPool(), dbClient); } } Map<String, List<String>> mapping = VirtualPool .groupRemoteCopyModesByVPool(vpool, dbClient); List<String> availableCopyModes = new ArrayList<String>(); _logger.info("Multi Volume Consistency {} :", vpool.getMultivolumeConsistency()); if (mapping != null) { for (Collection<String> copyModes : mapping.values()) { availableCopyModes.addAll(copyModes); } } int frequency = Collections.frequency(availableCopyModes, Mode.ASYNCHRONOUS.toString()); if (frequency > 1) { throw APIException.badRequests.unsupportedConfigurationWithMultipleAsyncModes(); } } @Override protected boolean isCreateAttributeOn(final BlockVirtualPoolParam createParam) { _logger.info("Entered Remote Protection Validator"); if (null == createParam.getProtection() || null == createParam.getProtection().getRemoteCopies() || null == createParam.getProtection().getRemoteCopies().getRemoteCopySettings() || createParam.getProtection().getRemoteCopies().getRemoteCopySettings().isEmpty()) { return false; } return true; } /** * check VMAX system in VPool * * @param createParam */ private void checkSystemTypeIsVMAX(final BlockVirtualPoolParam createParam) { if (null == createParam.getSystemType() || createParam.getSystemType().equalsIgnoreCase(NONE)) { throw APIException.badRequests.parameterOnlySupportedForVmax("SRDF Remote Protection"); } if (!VirtualPool.SystemType.vmax.toString().equalsIgnoreCase(createParam.getSystemType())) { throw APIException.badRequests.parameterOnlySupportedForVmax("SRDF Remote Protection"); } } /** * check RP or VPlex enabled in VPool * * @param createParam */ private void checkForVPlexProtectionEnabled( final BlockVirtualPoolParam createParam, DbClient dbClient) { // RP not allowed if SRDF Protection is specified in VPOOL if (null != createParam.getProtection() && null != createParam.getProtection().getRecoverPoint() && null != createParam.getProtection().getRecoverPoint().getCopies() && !createParam.getProtection().getRecoverPoint().getCopies().isEmpty()) { throw APIException.badRequests.parameterRPNotSupportedWithSRDF(); } // VPLEX checks with SRDF if (createParam.specifiesHighAvailability()) { // SRDF Copy Mode Active not supported with Vplex if (createParam.hasRemoteCopyProtection()) { for (VirtualPoolRemoteProtectionVirtualArraySettingsParam remoteSettings : createParam .getProtection().getRemoteCopies().getRemoteCopySettings()) { if (Mode.ACTIVE.name().equals(remoteSettings.getRemoteCopyMode())) { throw APIException.badRequests.vplexNotSupportedWithSRDFActive(); } if (null != remoteSettings.getVpool()) { URI uri = remoteSettings.getVpool(); VirtualPool vpool = dbClient.queryObject(VirtualPool.class, uri); if (vpool != null && VirtualPool.vPoolSpecifiesHighAvailabilityDistributed(vpool)) { throw APIException.badRequests.vplexDistributedNotSupportedOnSRDFTarget(); } } } } } } /** * Check vplex / srdf compatibility on update. * * @param updateParam -- BlockVirtualPoolUpdateParam * @param dbClient -- database handle */ private void validateVPlexProtection( final BlockVirtualPoolUpdateParam updateParam, DbClient dbClient) { // VPLEX checks with SRDF if (updateParam.specifiesHighAvailability()) { // SRDF Copy Mode Active not supported with Vplex if (updateParam.getProtection() != null && updateParam.getProtection().getRemoteCopies()!= null && updateParam.getProtection().getRemoteCopies().getAdd() != null) { for (VirtualPoolRemoteProtectionVirtualArraySettingsParam remoteSettings : updateParam.getProtection().getRemoteCopies().getAdd()) { if (Mode.ACTIVE.name().equals(remoteSettings.getRemoteCopyMode())) { throw APIException.badRequests.vplexNotSupportedWithSRDFActive(); } if (null != remoteSettings.getVpool()) { URI uri = remoteSettings.getVpool(); VirtualPool vpool = dbClient.queryObject(VirtualPool.class, uri); if (vpool != null && VirtualPool.vPoolSpecifiesHighAvailabilityDistributed(vpool)) { throw APIException.badRequests.vplexDistributedNotSupportedOnSRDFTarget(); } } } } } } @Override protected void validateVirtualPoolCreateAttributeValue(final BlockVirtualPoolParam createParam, final DbClient dbClient) { _logger.info("Entered Remote Protection creation validator"); // RP or VPlex enabled checkForVPlexProtectionEnabled(createParam, dbClient); // remote Mirroring is applicable only for VMAX system type checkSystemTypeIsVMAX(createParam); // Validate whether remote Copy Settings are valid for the source VPool // If vArrays are not given, then no validation needed, as by default all the vArrays are // applicable for this VPool. if (null == createParam.getVarrays()) { return; } if (createParam.hasRemoteCopyProtection()) { List<String> availableCopyModes = new ArrayList(); for (VirtualPoolRemoteProtectionVirtualArraySettingsParam remoteSettings : createParam .getProtection().getRemoteCopies().getRemoteCopySettings()) { VirtualPool vPool = null; if (remoteSettings.getVpool() != null) { validateSRDFTargetAsVMAX(remoteSettings.getVpool(), dbClient); vPool = dbClient.queryObject(VirtualPool.class, remoteSettings.getVpool()); } checkVArrayIsValidForVPool(remoteSettings, vPool, createParam); if (null == remoteSettings.getRemoteCopyMode()) { availableCopyModes.add(Mode.ASYNCHRONOUS.toString()); } else if (CopyModes.lookup(remoteSettings.getRemoteCopyMode())) { availableCopyModes.add(remoteSettings.getRemoteCopyMode()); } else { throw APIException.badRequests.invalidCopyMode(remoteSettings.getRemoteCopyMode()); } } int frequency = Collections.frequency(availableCopyModes, Mode.ASYNCHRONOUS.toString()); if (frequency > 1) { throw APIException.badRequests.unsupportedConfigurationWithMultipleAsyncModes(); } } } /** * For each remote setting, check given VArray is part of attached VArrays of given remote VPool * * @param remoteSettings * @param dbClient * @param createParam */ private void checkVArrayIsValidForVPool( final VirtualPoolRemoteProtectionVirtualArraySettingsParam remoteSettings, final VirtualPool vPool, final BlockVirtualPoolParam createParam) { if (null != vPool) { if (null != vPool.getVirtualArrays() && !vPool.getVirtualArrays().contains(remoteSettings.getVarray().toString())) { throw APIException.badRequests.vArrayUnSupportedForGivenVPool(vPool.getId(), remoteSettings.getVarray()); } } else { Set<String> vArrays = createParam.getVarrays(); if (null != vArrays && !vArrays.contains(remoteSettings.getVarray().toString())) { throw APIException.badRequests.vArrayUnSupportedForGivenVPool(remoteSettings.getVarray(), remoteSettings.getVarray()); } } } @Override protected boolean isUpdateAttributeOn(final BlockVirtualPoolUpdateParam updateParam) { // Add and Remove Sizes will be 0, if only copyMode is changed. if (null == updateParam.getProtection() || null == updateParam.getProtection().getRemoteCopies() || null == updateParam.getProtection().getRemoteCopies().getAdd() || null == updateParam.getProtection().getRemoteCopies().getRemove()) { _logger.debug("Remote Mirror Protection called"); return false; } return true; } }