/* * Copyright (c) 2008-2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource.blockingestorchestration; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.api.service.impl.resource.utils.PropertySetterUtil; import com.emc.storageos.api.service.impl.resource.utils.VolumeIngestionUtil; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.SupportedVolumeCharacterstics; import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.SupportedVolumeInformation; public class IngestStrategyFactory { public static final boolean DISREGARD_PROTECTION = true; private static final Logger _logger = LoggerFactory.getLogger(IngestStrategyFactory.class); private BlockIngestOrchestrator blockVolumeIngestOrchestrator; private BlockIngestOrchestrator blockRemoteReplicationIngestOrchestrator; private BlockIngestOrchestrator blockRecoverPointIngestOrchestrator; private BlockIngestOrchestrator blockVplexVolumeIngestOrchestrator; private BlockIngestExportOrchestrator maskPerHostIngestOrchestrator; private BlockIngestExportOrchestrator multipleMaskPerHostIngestOrchestrator; private BlockIngestExportOrchestrator unexportedVolumeIngestOrchestrator; private BlockIngestOrchestrator blockSnapshotIngestOrchestrator; private BlockIngestOrchestrator blockMirrorIngestOrchestrator; private final Map<String, IngestStrategy> ingestStrategyMap; private final Map<String, IngestExportStrategy> ingestExportStrategyMap; private DbClient _dbClient; public void setDbClient(DbClient dbClient) { _dbClient = dbClient; } public DbClient getDbClient() { return _dbClient; } public BlockIngestOrchestrator getBlockVolumeIngestOrchestrator() { return blockVolumeIngestOrchestrator; } public void setBlockVolumeIngestOrchestrator( BlockIngestOrchestrator blockVolumeIngestOrchestrator) { this.blockVolumeIngestOrchestrator = blockVolumeIngestOrchestrator; } public BlockIngestOrchestrator getBlockRemoteReplicationIngestOrchestrator() { return blockRemoteReplicationIngestOrchestrator; } public void setBlockRemoteReplicationIngestOrchestrator( BlockIngestOrchestrator blockRemoteReplicationIngestOrchestrator) { this.blockRemoteReplicationIngestOrchestrator = blockRemoteReplicationIngestOrchestrator; } public BlockIngestOrchestrator getBlockVplexVolumeIngestOrchestrator() { return blockVplexVolumeIngestOrchestrator; } public void setBlockVplexVolumeIngestOrchestrator( BlockIngestOrchestrator blockVplexVolumeIngestOrchestrator) { this.blockVplexVolumeIngestOrchestrator = blockVplexVolumeIngestOrchestrator; } public void setBlockRecoverPointIngestOrchestrator( BlockIngestOrchestrator blockRecoverPointIngestOrchestrator) { this.blockRecoverPointIngestOrchestrator = blockRecoverPointIngestOrchestrator; } public BlockIngestOrchestrator getBlockSnapshotIngestOrchestrator() { return blockSnapshotIngestOrchestrator; } public void setBlockSnapshotIngestOrchestrator( BlockIngestOrchestrator blockSnapshotIngestOrchestrator) { this.blockSnapshotIngestOrchestrator = blockSnapshotIngestOrchestrator; } public BlockIngestOrchestrator getBlockMirrorIngestOrchestrator() { return blockMirrorIngestOrchestrator; } public void setBlockMirrorIngestOrchestrator( BlockIngestOrchestrator blockMirrorIngestOrchestrator) { this.blockMirrorIngestOrchestrator = blockMirrorIngestOrchestrator; } public BlockIngestExportOrchestrator getMaskPerHostIngestOrchestrator() { return maskPerHostIngestOrchestrator; } public void setMaskPerHostIngestOrchestrator( BlockIngestExportOrchestrator maskPerHostIngestOrchestrator) { this.maskPerHostIngestOrchestrator = maskPerHostIngestOrchestrator; } public BlockIngestExportOrchestrator getMultipleMaskPerHostIngestOrchestrator() { return multipleMaskPerHostIngestOrchestrator; } public void setMultipleMaskPerHostIngestOrchestrator( BlockIngestExportOrchestrator multipleMaskPerHostIngestOrchestrator) { this.multipleMaskPerHostIngestOrchestrator = multipleMaskPerHostIngestOrchestrator; } public BlockIngestExportOrchestrator getUnexportedVolumeIngestOrchestrator() { return unexportedVolumeIngestOrchestrator; } public void setUnexportedVolumeIngestOrchestrator( BlockIngestExportOrchestrator unexportedVolumeIngestOrchestrator) { this.unexportedVolumeIngestOrchestrator = unexportedVolumeIngestOrchestrator; } public IngestStrategyFactory() { this.ingestStrategyMap = new HashMap<String, IngestStrategy>(); this.ingestExportStrategyMap = new HashMap<String, IngestExportStrategy>(); } public enum ReplicationStrategy { LOCAL, REMOTE, VPLEX, RP } public enum VolumeType { VOLUME, SNAPSHOT, CLONE, MIRROR } public enum IngestExportStrategyEnum { /* * MASK_PER_HOST : * Arrays whose existing masking containers cannot be modeled as export mask in ViPR DB * are candidates for this mask per host behavior. * Here, during provisioning ViPR creates a logical container Export mask for each Host to get exported * through ViPR.Its guaranteed that there will be always only 1 export mask available in ViPR Db at any * point of time. * * XtremIO,HDS are examples. */ MASK_PER_HOST("xtremio,hds,unity"), /* * MULTIPLE_MASK_PER_HOST : * Arrays whose existing masking containers can be modeled to export mask in ViPR DB * are candidates for this multiple mask per host behavior. * Here, during provisioning ViPR creates an export mask object for every masking container * found in the Array. There is no restriction of one export mask per host , as the export masks created in * ViPR DB are actually a replica of what's there in Array. * * VMAX,VNX Block are examples */ MULTIPLE_MASK_PER_HOST("vmax,vnxblock,vplex"), NO_MASK("vnxe"); private String ingestStrategy; IngestExportStrategyEnum(String ingestStrategy) { this.ingestStrategy = ingestStrategy; } public String getIngestStrategy() { return ingestStrategy; } public static IngestExportStrategyEnum getIngestStrategy(String strategyName) { IngestExportStrategyEnum exportStrategy = null; for (IngestExportStrategyEnum strategy : copyOfValues) { if (strategy.getIngestStrategy().contains(strategyName)) { exportStrategy = strategy; break; } } if (exportStrategy == null) { // for driver sdk managed systems exportStrategy = IngestExportStrategyEnum.MASK_PER_HOST; } return exportStrategy; } private static final IngestExportStrategyEnum[] copyOfValues = values(); } public enum IngestStrategyEnum { LOCAL_VOLUME, LOCAL_SNAPSHOT, LOCAL_MIRROR, LOCAL_CLONE, REMOTE_VOLUME, VPLEX_VOLUME, RP_VOLUME, NONE; public static IngestStrategyEnum getIngestStrategy(String strategyName) { _logger.debug("looking for a strategy for strategy name: " + strategyName); for (IngestStrategyEnum strategy : copyOfValues) { if (strategy.name().equals(strategyName)) { return strategy; } } return NONE; } private static final IngestStrategyEnum[] copyOfValues = values(); } public IngestExportStrategy getIngestExportStrategy(IngestExportStrategyEnum strategyEnum) { IngestExportStrategy ingestStrategy = new IngestExportStrategy(); ingestStrategy.setDbClient(_dbClient); switch (strategyEnum) { /* * MASK_PER_HOST: * Ingest Block Object, where the masking containers on Array CANNOT be * modeled as Export mask in ViPR. * * Eg: Ingest Exported HDS Remote Replicated Volume into ViPR */ case MASK_PER_HOST: ingestStrategy.setIngestExportOrchestrator(maskPerHostIngestOrchestrator); break; /* * MULTIPLE_MASK_PER_HOST: * Ingest Block Object, where the masking containers on Array CAN be * modeled as Export mask in ViPR. * * Eg: Ingest Exported VMAX Remote Replicated Volume (SRDF) into ViPR */ case MULTIPLE_MASK_PER_HOST: ingestStrategy.setIngestExportOrchestrator(multipleMaskPerHostIngestOrchestrator); break; case NO_MASK: ingestStrategy.setIngestExportOrchestrator(unexportedVolumeIngestOrchestrator); break; default: break; } return ingestStrategy; } /** * Based on the strategy key, ingest strategy object will be associated * with corresponding ingestResource and ingestExport orchestrators. * * @param strategyEnum * @return */ public IngestStrategy getIngestStrategy(IngestStrategyEnum strategyEnum) { IngestStrategy ingestStrategy = new IngestStrategy(); ingestStrategy.setDbClient(_dbClient); switch (strategyEnum) { case REMOTE_VOLUME: ingestStrategy.setIngestResourceOrchestrator(blockRemoteReplicationIngestOrchestrator); break; case LOCAL_CLONE: case LOCAL_VOLUME: ingestStrategy.setIngestResourceOrchestrator(blockVolumeIngestOrchestrator); break; case LOCAL_SNAPSHOT: ingestStrategy.setIngestResourceOrchestrator(blockSnapshotIngestOrchestrator); break; case LOCAL_MIRROR: ingestStrategy.setIngestResourceOrchestrator(blockMirrorIngestOrchestrator); break; case VPLEX_VOLUME: ingestStrategy.setIngestResourceOrchestrator(blockVplexVolumeIngestOrchestrator); break; case RP_VOLUME: ingestStrategy.setIngestResourceOrchestrator(blockRecoverPointIngestOrchestrator); break; default: break; } return ingestStrategy; } /** * Retrieves the proper ingestion strategy for the given UnManagedVolume. * * @param unManagedVolume unmanaged volume * @param disregardProtection disregard RP properties when determining strategy (required when RP orch. is ingesting backing vols) * @return ingestion strategy */ public IngestStrategy buildIngestStrategy(UnManagedVolume unManagedVolume, boolean disregardProtection) { String remoteMirrorEnabledInVolume = unManagedVolume.getVolumeCharacterstics().get( SupportedVolumeCharacterstics.REMOTE_MIRRORING.toString()); String replicationStrategy; boolean isVplexVolume = VolumeIngestionUtil.isVplexVolume(unManagedVolume); boolean isRpEnabled = VolumeIngestionUtil.checkUnManagedResourceIsRecoverPointEnabled(unManagedVolume); if (!disregardProtection && isRpEnabled) { replicationStrategy = ReplicationStrategy.RP.name(); } else if (isVplexVolume) { replicationStrategy = ReplicationStrategy.VPLEX.name(); } else if (null == remoteMirrorEnabledInVolume || !Boolean.parseBoolean(remoteMirrorEnabledInVolume)) { replicationStrategy = ReplicationStrategy.LOCAL.name(); } else { replicationStrategy = ReplicationStrategy.REMOTE.name(); } // Since a VPLEX backend volume may also be a snapshot target volume, we want to // make sure we use the local volume ingest strategy when the volume is a VPLEX backend // volume. String volumeType = VolumeType.VOLUME.name(); if ((VolumeIngestionUtil.isSnapshot(unManagedVolume)) && (!VolumeIngestionUtil.isVplexBackendVolume(unManagedVolume))) { volumeType = VolumeType.SNAPSHOT.name(); } else if (VolumeIngestionUtil.isMirror(unManagedVolume)) { volumeType = VolumeType.MIRROR.name(); } String strategyKey = replicationStrategy + "_" + volumeType; _logger.info("strategy key is " + strategyKey); if (null == ingestStrategyMap.get(strategyKey)) { IngestStrategy strategy = getIngestStrategy(IngestStrategyEnum.getIngestStrategy(strategyKey)); _logger.debug("ingest strategy map does not contain key, adding " + strategyKey + " for " + strategy); ingestStrategyMap.put(strategyKey, strategy); } return ingestStrategyMap.get(strategyKey); } public IngestExportStrategy buildIngestExportStrategy(UnManagedVolume unManagedVolume) { boolean isVolumeExported = Boolean.parseBoolean(unManagedVolume.getVolumeCharacterstics().get( SupportedVolumeCharacterstics.IS_VOLUME_EXPORTED.toString())); // being RP enabled implies the volume is exported to the RP device boolean isRpEnabled = VolumeIngestionUtil.checkUnManagedResourceIsRecoverPointEnabled(unManagedVolume); String systemType = PropertySetterUtil.extractValueFromStringSet(SupportedVolumeInformation.SYSTEM_TYPE.toString(), unManagedVolume.getVolumeInformation()); _logger.info("system type is " + systemType); IngestExportStrategyEnum exportStrategy = IngestExportStrategyEnum.NO_MASK; if (isVolumeExported || isRpEnabled) { exportStrategy = IngestExportStrategyEnum.getIngestStrategy(systemType); } _logger.info("export strategy is " + exportStrategy.name()); if (null == ingestExportStrategyMap.get(exportStrategy.name())) { IngestExportStrategy strategy = getIngestExportStrategy(exportStrategy); _logger.info("ingest strategy map does not contain key, adding " + exportStrategy + " for " + strategy); ingestExportStrategyMap.put(exportStrategy.name(), strategy); } return ingestExportStrategyMap.get(exportStrategy.name()); } }