/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.placement; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.api.service.authorization.PermissionsHelper; import com.emc.storageos.api.service.impl.placement.FileMirrorRecommendation.Target; import com.emc.storageos.api.service.impl.placement.FileRecommendation.FileType; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.FileReplicaPolicyTarget; import com.emc.storageos.db.client.model.FileReplicaPolicyTargetMap; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.PolicyStorageResource; import com.emc.storageos.db.client.model.Project; 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.VirtualArray; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.fileorchestrationcontroller.FileOrchestrationUtils; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.volumecontroller.AttributeMatcher; import com.emc.storageos.volumecontroller.AttributeMatcher.Attributes; import com.emc.storageos.volumecontroller.Recommendation; import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper; public class FileMirrorScheduler implements Scheduler { public final Logger _log = LoggerFactory .getLogger(FileMirrorScheduler.class); private static final String SCHEDULER_NAME = "filemirror"; private DbClient _dbClient; private StorageScheduler _storageScheduler; private FileStorageScheduler _fileScheduler; public void setStorageScheduler(final StorageScheduler storageScheduler) { _storageScheduler = storageScheduler; } public void setDbClient(final DbClient dbClient) { _dbClient = dbClient; } public void setFileScheduler(FileStorageScheduler fileScheduler) { _fileScheduler = fileScheduler; } @Autowired protected PermissionsHelper _permissionsHelper = null; /** * get list mirror recommendation for mirror file shares(local or remote) * Select and return one or more storage pools where the filesystem(s) should be created. The * placement logic is based on: - varray, only storage devices in the given varray are * candidates - destination varrays - vpool, specifies must-meet & best-meet service * specifications - access-protocols: storage pools must support all protocols specified in * vpool - file replication: if yes, only select storage pools with this capability - * best-match, select storage pools which meets desired performance - provision-mode: thick/thin * * @param varray * varray requested for source * @param project * for the storage * @param vpool * vpool requested * @param capabilities * vpool capabilities parameters * @return list of Recommendation objects to satisfy the request */ @Override public List getRecommendationsForResources(VirtualArray varray, Project project, VirtualPool vpool, VirtualPoolCapabilityValuesWrapper capabilities) { List<FileRecommendation> recommendations = null; if (capabilities.getFileReplicationType().equalsIgnoreCase(VirtualPool.FileReplicationType.REMOTE.name())) { recommendations = getRemoteMirrorRecommendationsForResources(varray, project, vpool, capabilities); } else { recommendations = getLocalMirrorRecommendationsForResources(varray, project, vpool, capabilities); } return recommendations; } private PolicyStorageResource findMatchedPolicyStorageResource(List<PolicyStorageResource> storageSystemResources, FileRecommendation sourceFileRecommendation) { for (PolicyStorageResource strRes : storageSystemResources) { if (sourceFileRecommendation.getSourceStorageSystem().equals(strRes.getStorageSystem())) { if (sourceFileRecommendation.getvNAS() != null && sourceFileRecommendation.getvNAS().equals(strRes.getNasServer())) { return strRes; } else if (strRes.getNasServer() != null && strRes.getNasServer().toString().contains("PhysicalNAS")) { return strRes; } } } return null; } private void findAndUpdateMatchedPolicyStorageResource(List<PolicyStorageResource> storageSystemResources, FileRecommendation sourceFileRecommendation, VirtualPoolCapabilityValuesWrapper capabilities) { PolicyStorageResource matchedPolicyResource = findMatchedPolicyStorageResource(storageSystemResources, sourceFileRecommendation); if (matchedPolicyResource != null) { _log.info("Found the valid existing policy storage resource for system {} nas server {}", matchedPolicyResource.getStorageSystem(), matchedPolicyResource.getNasServer()); FileReplicaPolicyTargetMap targetMap = matchedPolicyResource.getFileReplicaPolicyTargetMap(); if (targetMap != null && !targetMap.isEmpty()) { for (FileReplicaPolicyTarget target : targetMap.values()) { if (target.getNasServer() != null && target.getStorageSystem() != null) { capabilities.put(VirtualPoolCapabilityValuesWrapper.TARGET_NAS_SERVER, URI.create(target.getNasServer())); capabilities.put(VirtualPoolCapabilityValuesWrapper.TARGET_STORAGE_SYSTEM, URI.create(target.getStorageSystem())); break; } } } } return; } /* local mirror related functions */ /** * get list Recommendation for Local Mirror * * @param vArray * @param project * @param vPool * @param capabilities * @return */ public List getRemoteMirrorRecommendationsForResources(VirtualArray vArray, Project project, VirtualPool vPool, VirtualPoolCapabilityValuesWrapper capabilities) { List<FileRecommendation> targetFileRecommendations = null; List<FileMirrorRecommendation> fileMirrorRecommendations = new ArrayList<FileMirrorRecommendation>(); // Get the source file system recommendations!!! capabilities.put(VirtualPoolCapabilityValuesWrapper.PERSONALITY, VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_SOURCE); // Verify the replication policy was applied!! // Get the policy storage resources for applied policy // Choose the right target for the source List<PolicyStorageResource> storageSystemResources = null; if (!capabilities.isVpoolProjectPolicyAssign()) { storageSystemResources = FileOrchestrationUtils.getFilePolicyStorageResources(_dbClient, vPool, project, null); if (storageSystemResources != null && !storageSystemResources.isEmpty()) { _log.info("Found replication policy for vpool and project, so get all source recommedation to match target"); capabilities.put(VirtualPoolCapabilityValuesWrapper.GET_ALL_SOURCE_RECOMMENDATIONS, true); } } List<FileRecommendation> sourceFileRecommendations = new ArrayList<FileRecommendation>(); // For vPool change get the recommendations from source file system!!! if (capabilities.createMirrorExistingFileSystem()) { sourceFileRecommendations = getFileRecommendationsForSourceFS(vArray, vPool, capabilities); // Remove the source file system from capabilities list // otherwise, try to find the remote pools from the same source system!!! capabilities.removeCapabilityEntry(VirtualPoolCapabilityValuesWrapper.SOURCE_STORAGE_SYSTEM); } else { // Get the recommendation for source from vpool!!! sourceFileRecommendations = _fileScheduler.getRecommendationsForResources(vArray, project, vPool, capabilities); // Remove the source storage system from capabilities list // otherwise, try to find the remote pools from the same source system!!! if (capabilities.getFileProtectionSourceStorageDevice() != null) { capabilities.removeCapabilityEntry(VirtualPoolCapabilityValuesWrapper.FILE_PROTECTION_SOURCE_STORAGE_SYSTEM); } } if (capabilities.getAllSourceRecommnedations()) { capabilities.removeCapabilityEntry(VirtualPoolCapabilityValuesWrapper.GET_ALL_SOURCE_RECOMMENDATIONS); } // Process the each recommendations for targets for (FileRecommendation sourceFileRecommendation : sourceFileRecommendations) { String srcSystemType = sourceFileRecommendation.getDeviceType(); Set<String> systemTypes = new StringSet(); systemTypes.add(srcSystemType); // Based on the source recommendation nas server, should pick the right target nas server. // Both source and target nas servers should be similar. // If sourceFileRecommendation.getvNAS() is null means, the recommendation is for physical nas server!! // Remove the existing source nas server if any!! if (capabilities.getSourceVirtualNasServer() != null) { capabilities.removeCapabilityEntry(VirtualPoolCapabilityValuesWrapper.SOURCE_VIRTUAL_NAS_SERVER); } // add the new vnas server of current source recommendations!!! if (sourceFileRecommendation.getvNAS() != null) { capabilities.put(VirtualPoolCapabilityValuesWrapper.SOURCE_VIRTUAL_NAS_SERVER, sourceFileRecommendation.getvNAS()); } // Findout is there any policy was created for the source recommendations!!! if (capabilities.getTargetNasServer() != null) { capabilities.removeCapabilityEntry(VirtualPoolCapabilityValuesWrapper.TARGET_NAS_SERVER); } if (capabilities.getTargetStorageSystem() != null) { capabilities.removeCapabilityEntry(VirtualPoolCapabilityValuesWrapper.TARGET_STORAGE_SYSTEM); } if (storageSystemResources != null && !storageSystemResources.isEmpty()) { findAndUpdateMatchedPolicyStorageResource(storageSystemResources, sourceFileRecommendation, capabilities); } for (String targetVArry : capabilities.getFileReplicationTargetVArrays()) { // Process for target !!! FileMirrorRecommendation fileMirrorRecommendation = new FileMirrorRecommendation(sourceFileRecommendation); VirtualPool targetVPool = _dbClient.queryObject(VirtualPool.class, capabilities.getFileReplicationTargetVPool()); VirtualArray targetVArray = _dbClient.queryObject(VirtualArray.class, URI.create(targetVArry)); // Filter the target storage pools!!! Map<String, Object> attributeMap = new HashMap<String, Object>(); attributeMap.put(Attributes.system_type.toString(), systemTypes); attributeMap.put(Attributes.remote_copy_mode.toString(), capabilities.getFileRpCopyMode()); attributeMap.put(Attributes.source_storage_system.name(), sourceFileRecommendation.getSourceStorageSystem().toString()); capabilities.put(VirtualPoolCapabilityValuesWrapper.PERSONALITY, VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_TARGET); // Get target recommendations!!! targetFileRecommendations = _fileScheduler.placeFileShare(targetVArray, targetVPool, capabilities, project, attributeMap); if (targetFileRecommendations == null || targetFileRecommendations.isEmpty()) { _log.info("No target recommendation found, so ignore the source recommedation as well."); continue; } String copyMode = capabilities.getFileRpCopyMode(); if (targetFileRecommendations != null && !targetFileRecommendations.isEmpty()) { // prepare the target recommendation FileRecommendation targetRecommendation = targetFileRecommendations.get(0); prepareTargetFileRecommendation(copyMode, targetVArray, targetRecommendation, fileMirrorRecommendation); fileMirrorRecommendations.add(fileMirrorRecommendation); } } // File file system provisioning // Got sufficient number of recommendations!! if (!capabilities.isVpoolProjectPolicyAssign() && fileMirrorRecommendations.size() >= capabilities.getResourceCount()) { break; } } return fileMirrorRecommendations; } /* local mirror related functions */ /** * get list Recommendation for Local Mirror * * @param vArray * @param project * @param vPool * @param capabilities * @return */ public List getLocalMirrorRecommendationsForResources(VirtualArray vArray, Project project, VirtualPool vPool, VirtualPoolCapabilityValuesWrapper capabilities) { List<FileRecommendation> targetFileRecommendations = null; List<FileMirrorRecommendation> fileMirrorRecommendations = new ArrayList<FileMirrorRecommendation>(); List<FileRecommendation> sourceFileRecommendations = new ArrayList<FileRecommendation>(); // For vPool change get the recommendations from source file system!!! if (capabilities.createMirrorExistingFileSystem()) { sourceFileRecommendations = getFileRecommendationsForSourceFS(vArray, vPool, capabilities); } else { // Get the recommendation for source from vpool!!! sourceFileRecommendations = _fileScheduler.getRecommendationsForResources(vArray, project, vPool, capabilities); } // process the each recommendations for targets for (FileRecommendation sourceFileRecommendation : sourceFileRecommendations) { // set the source file recommendation FileMirrorRecommendation fileMirrorRecommendation = new FileMirrorRecommendation(sourceFileRecommendation); // attribute map of target storagesystem and varray Map<String, Object> attributeMap = new HashMap<String, Object>(); Set<String> storageSystemSet = new HashSet<String>(); storageSystemSet.add(sourceFileRecommendation.getSourceStorageSystem().toString()); attributeMap.put(AttributeMatcher.Attributes.storage_system.name(), storageSystemSet); Set<String> virtualArraySet = new HashSet<String>(); virtualArraySet.add(vArray.getId().toString()); attributeMap.put(AttributeMatcher.Attributes.varrays.name(), virtualArraySet); // get target recommendations -step2 targetFileRecommendations = _fileScheduler.placeFileShare(vArray, vPool, capabilities, project, attributeMap); String copyMode = capabilities.getFileRpCopyMode(); if (targetFileRecommendations != null && !targetFileRecommendations.isEmpty()) { // prepare the target recommendation FileRecommendation targetRecommendation = targetFileRecommendations.get(0); prepareTargetFileRecommendation(copyMode, vArray, targetRecommendation, fileMirrorRecommendation); fileMirrorRecommendations.add(fileMirrorRecommendation); } } return fileMirrorRecommendations; } private void prepareTargetFileRecommendation(final String fsCopyMode, final VirtualArray targetVarray, FileRecommendation targetFileRecommendation, FileMirrorRecommendation fileMirrorRecommendation) { // Set target recommendations!!! Target target = new Target(); target.setTargetPool(targetFileRecommendation.getSourceStoragePool()); target.setTargetStorageDevice(targetFileRecommendation.getSourceStorageSystem()); if (targetFileRecommendation.getStoragePorts() != null) { target.setTargetStoragePortUris(targetFileRecommendation.getStoragePorts()); } if (targetFileRecommendation.getvNAS() != null) { target.setTargetvNASURI(targetFileRecommendation.getvNAS()); } if (fileMirrorRecommendation.getVirtualArrayTargetMap() == null) { fileMirrorRecommendation.setVirtualArrayTargetMap(new HashMap<URI, FileMirrorRecommendation.Target>()); } fileMirrorRecommendation.getVirtualArrayTargetMap().put(targetVarray.getId(), target); // File replication copy mode fileMirrorRecommendation.setCopyMode(fsCopyMode); } /** * Gets and verifies that the target varrays passed in the request are accessible to the tenant. * * @param project * A reference to the project. * @param vpool * class of service, contains target varrays * @return A reference to the varrays * @throws java.net.URISyntaxException * @throws com.emc.storageos.db.exceptions.DatabaseException */ public static List<VirtualArray> getTargetVirtualArraysForVirtualPool(final Project project, final VirtualPool vpool, final DbClient dbClient, final PermissionsHelper permissionHelper) { List<VirtualArray> targetVirtualArrays = new ArrayList<VirtualArray>(); if (VirtualPool.getFileRemoteProtectionSettings(vpool, dbClient) != null) { for (URI targetVirtualArray : VirtualPool.getFileRemoteProtectionSettings(vpool, dbClient) .keySet()) { VirtualArray nh = dbClient.queryObject(VirtualArray.class, targetVirtualArray); targetVirtualArrays.add(nh); permissionHelper.checkTenantHasAccessToVirtualArray( project.getTenantOrg().getURI(), nh); } } return targetVirtualArrays; } @Override public List<Recommendation> getRecommendationsForVpool(VirtualArray vArray, Project project, VirtualPool vPool, VpoolUse vPoolUse, VirtualPoolCapabilityValuesWrapper capabilities, Map<VpoolUse, List<Recommendation>> currentRecommendations) { throw DeviceControllerException.exceptions.operationNotSupported(); } private FileRecommendation getSourceRecommendationParameters(FileShare sourceFs, StorageSystem storageSystem) { FileRecommendation fileRecommendation = new FileRecommendation(); fileRecommendation.setSourceStorageSystem(sourceFs.getStorageDevice()); fileRecommendation.setFileType(FileType.FILE_SYSTEM_EXISTING_SOURCE); fileRecommendation.setVirtualArray(sourceFs.getVirtualArray()); fileRecommendation.setDeviceType(storageSystem.getSystemType()); // set vnas Server if (sourceFs.getVirtualNAS() != null) { fileRecommendation.setvNAS(sourceFs.getVirtualNAS()); } // set the storageports if (sourceFs.getStoragePort() != null) { List<URI> ports = new ArrayList<URI>(); ports.add(sourceFs.getStoragePort()); fileRecommendation.setStoragePorts(ports); } return fileRecommendation; } private List<FileRecommendation> getFileRecommendationsForSourceFS(VirtualArray vArray, VirtualPool vPool, VirtualPoolCapabilityValuesWrapper capabilities) { List<FileRecommendation> sourceFileRecommendations = new ArrayList<FileRecommendation>(); // Get the source file system and storage system // which was set at in FileService // to construct the source recommendations!! FileShare sourceFs = capabilities.getSourceFileSystem(); StorageSystem storageSystem = capabilities.getSourceStorageDevice(); // Get the Matched pools from target virtual pool // Verify that at least a matched pools from source storage system!!! List<StoragePool> candidatePools = _storageScheduler.getMatchingPools(vArray, vPool, capabilities, null); boolean gotMatchedPoolForSource = false; for (StoragePool pool : candidatePools) { if (pool.getStorageDevice().toString().equalsIgnoreCase(sourceFs.getStorageDevice().toString())) { gotMatchedPoolForSource = true; break; } } if (!gotMatchedPoolForSource) { _log.error("File system vpool change::No matched storage pools from source storage"); throw APIException.badRequests.noMatchingStoragePoolsForFileSystemVpoolChange(vArray.getId(), vPool.getId()); } sourceFileRecommendations.add(getSourceRecommendationParameters(sourceFs, storageSystem)); return sourceFileRecommendations; } @Override public String getSchedulerName() { return SCHEDULER_NAME; } @Override public boolean handlesVpool(VirtualPool vPool, VpoolUse vPoolUse) { return false; } }