Search in sources :

Example 1 with ExportPathParams

use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.

the class AbstractDefaultMaskingOrchestrator method determineInitiatorToExportMaskPlacements.

/**
 * Routine will examine the ExportGroup object's ExportMask and the passed in map of
 * compute-resource-to-initiators map to produce a mapping of the ExportMasks'
 * initiator port name to a list of ExportMask URIs.
 *
 * @param exportGroup
 *            [in] - ExportGroup object to examine
 * @param storage
 * @param computeResourceToInitiators
 *            [in] - Mapping of compute resource string key to
 *            list of Initiator URIs. @return Map of String to set of URIs. The key will be
 *            Initiator.normalizePort(initiator.portName).
 * @param partialMasks
 *            [out] - list of masks that were found to be "partial" masks, where there are multiple masks that make
 *            up one
 *            compute resource
 *            Value will be set of ExportMask URIs.
 */
protected Map<String, Set<URI>> determineInitiatorToExportMaskPlacements(ExportGroup exportGroup, URI storage, Map<String, List<URI>> computeResourceToInitiators, Map<String, Set<URI>> initiatorToExportMapOnArray, Map<String, URI> portNameToInitiatorURI, Set<URI> partialMasks) {
    Map<String, Set<URI>> initiatorToExportMaskURIMap = new HashMap<String, Set<URI>>();
    Map<String, Set<URI>> computeResourceToExportMaskMap = ExportMaskUtils.mapComputeResourceToExportMask(_dbClient, exportGroup, storage);
    Set<URI> allExportMaskURIs = new HashSet<>();
    // associated with the ExportGroup
    for (Map.Entry<String, List<URI>> entry : computeResourceToInitiators.entrySet()) {
        String computeResource = entry.getKey();
        List<URI> initiatorSet = entry.getValue();
        if (computeResourceToExportMaskMap.get(computeResource) != null) {
            for (URI exportMaskURI : computeResourceToExportMaskMap.get(computeResource)) {
                if (exportMaskURI == null) {
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - No ExportMask for compute resource %s in ExportGroup %s", computeResource, exportGroup.getLabel()));
                    continue;
                }
                for (URI initiatorURI : initiatorSet) {
                    Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
                    if (initiator == null) {
                        continue;
                    }
                    String normalizedName = Initiator.normalizePort(initiator.getInitiatorPort());
                    Set<URI> exportMaskURIs = initiatorToExportMaskURIMap.get(normalizedName);
                    if (exportMaskURIs == null) {
                        exportMaskURIs = new TreeSet<URI>();
                        initiatorToExportMaskURIMap.put(normalizedName, exportMaskURIs);
                    }
                    exportMaskURIs.add(exportMaskURI);
                }
            }
        }
    }
    // when combined, make up a cluster masking view
    for (Map.Entry<String, Set<URI>> entry : initiatorToExportMapOnArray.entrySet()) {
        allExportMaskURIs.addAll(entry.getValue());
    }
    Collection<URI> volumes = new HashSet<URI>();
    if (exportGroup.getVolumes() != null) {
        volumes = Collections2.transform(exportGroup.getVolumes().keySet(), CommonTransformerFunctions.FCTN_STRING_TO_URI);
    }
    ExportPathParams exportPathParams = _blockScheduler.calculateExportPathParamForVolumes(volumes, 0, storage, exportGroup.getId());
    _log.info(String.format("determineInitiatorToExportMaskPlacements - ExportGroup=%s, exportPathParams=%s", exportGroup.getId().toString(), exportPathParams));
    URI portGroup = exportPathParams.getPortGroup();
    _log.info(String.format("Port group: %s", portGroup));
    // Update mapping based on what is seen on the array
    for (Map.Entry<String, Set<URI>> entry : initiatorToExportMapOnArray.entrySet()) {
        String portName = entry.getKey();
        // Validate this initiator and determine if it exists in the database
        URI initiatorURI = portNameToInitiatorURI.get(portName);
        if (initiatorURI == null) {
            URIQueryResultList uris = new URIQueryResultList();
            _dbClient.queryByConstraint(AlternateIdConstraint.Factory.getInitiatorPortInitiatorConstraint(portName), uris);
            if (!uris.iterator().hasNext()) {
                // There is no such initiator
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Could not find initiator port %s in DB", portName));
                continue;
            }
            initiatorURI = uris.iterator().next();
        }
        // We should have a non-null initiator URI at this point
        Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
        if (initiator == null) {
            _log.info(String.format("determineInitiatorToExportMaskPlacements - Initiator %s does not exist in DB", initiatorURI.toString()));
            continue;
        }
        _log.info(String.format("determineInitiatorToExportMaskPlacements - Scanning masks that contain initiator %s to see if those masks qualify for consideration for re-use", initiator.getInitiatorPort()));
        // This container is for capturing those ExportMasks that we find to
        // be matching based on the initiators, but unusable based on the
        // StoragePorts that the mask has. Basically, in order for a mask to
        // be considered a match, the initiators have to match, but the
        // StoragePorts have to be in the same Network as the ExportGroup's
        // VArray Network.
        Map<URI, Map<String, String>> masksWithUnmatchedStoragePorts = new HashMap<URI, Map<String, String>>();
        // Take a look at the ExportMask's initiators to see what compute resource that they support.
        String computeResource = ExportUtils.computeResourceForInitiator(exportGroup, initiator);
        List<URI> uriList = computeResourceToInitiators.get(computeResource);
        List<String> portsForComputeResource = new ArrayList<String>();
        Iterator<Initiator> iterator = _dbClient.queryIterativeObjects(Initiator.class, uriList);
        while (iterator.hasNext()) {
            portsForComputeResource.add(iterator.next().getInitiatorPort());
        }
        // At this point we have a non-null initiator object that we can use in the mapping
        Map<URI, Integer> maskToTotalMatchingPorts = new HashMap<URI, Integer>();
        int totalPorts = 0;
        Set<URI> candidateExportMaskURIs = new HashSet<URI>();
        Set<URI> exportMaskURIs = entry.getValue();
        for (URI exportMaskURI : exportMaskURIs) {
            ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
            if (mask == null || mask.getInactive()) {
                continue;
            }
            _log.info(String.format("determineInitiatorToExportMaskPlacements - Checking to see if we can consider mask %s, given its initiators, storage ports, and volumes", mask.getMaskName()));
            // Check for NO_VIPR. If found, avoid this mask.
            if (mask.getMaskName() != null && mask.getMaskName().toUpperCase().contains(ExportUtils.NO_VIPR)) {
                _log.info(String.format("ExportMask %s disqualified because the name contains %s (in upper or lower case) to exclude it", mask.getMaskName(), ExportUtils.NO_VIPR));
                continue;
            }
            Map<String, String> storagePortToNetworkName = new HashMap<String, String>();
            if (mask.getCreatedBySystem()) {
                if (mask.getResource().equals(computeResource)) {
                    if (maskHasPortGroup(mask, portGroup) && maskHasStoragePortsInExportVarray(exportGroup, mask, initiator, storagePortToNetworkName)) {
                        _log.info(String.format("determineInitiatorToExportMaskPlacements - ViPR-created mask %s qualifies for consideration for re-use", mask.getMaskName()));
                        candidateExportMaskURIs.add(exportMaskURI);
                        totalPorts += storagePortToNetworkName.keySet().size();
                        maskToTotalMatchingPorts.put(exportMaskURI, totalPorts);
                    // Ingest Fix : In ingest case, more than 1 export mask with createdBySystem flag set to
                    // true is possible
                    // remove the break statement
                    // break; First ViPR-created ExportMask associated with the resource, we will use
                    } else {
                        masksWithUnmatchedStoragePorts.put(exportMaskURI, storagePortToNetworkName);
                        _log.info(String.format("determineInitiatorToExportMaskPlacements - ViPR-created mask %s does not qualify for consideration for re-use due to storage ports mismatch with varray.", mask.getMaskName()));
                    }
                } else {
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - ViPR-created mask %s does not qualify for consideration for re-use due to compute resource mismatch.", mask.getMaskName()));
                }
            } else if (maskHasInitiatorsBasedOnExportType(exportGroup, mask, initiator, portsForComputeResource) || maskHasInitiatorsBasedOnExportType(exportGroup, mask, allExportMaskURIs, portsForComputeResource, partialMasks)) {
                if (maskHasPortGroup(mask, portGroup) && maskHasStoragePortsInExportVarray(exportGroup, mask, initiator, storagePortToNetworkName)) {
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - Pre-existing mask %s qualifies for consideration for re-use", mask.getMaskName()));
                    // This is a non-ViPR create ExportMask and it has the initiator
                    // as an existing initiator. Add it this as a matching candidate
                    candidateExportMaskURIs.add(exportMaskURI);
                    // We don't have zone ingest information for pre-existing masks, so for the purpose of
                    // matching more coexistence masks, we assume there are zones from every port to every
                    // initiator in the mask.
                    // Existing Initiators - initiators which are not userAdded.
                    int existingInitiators = mask.getExistingInitiators() == null ? 0 : mask.getExistingInitiators().size();
                    int userAddedInitators = mask.getUserAddedInitiators() == null ? 0 : mask.getUserAddedInitiators().size();
                    int totalInitiators = existingInitiators + userAddedInitators;
                    totalPorts += storagePortToNetworkName.keySet().size() * totalInitiators;
                    maskToTotalMatchingPorts.put(exportMaskURI, totalPorts);
                } else {
                    masksWithUnmatchedStoragePorts.put(exportMaskURI, storagePortToNetworkName);
                    _log.info(String.format("determineInitiatorToExportMaskPlacements - Pre-existing mask %s does not qualify for consideration for re-use due to storage ports mismatch with varray.", mask.getMaskName()));
                }
            } else {
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Pre-existing mask %s does not qualify for consideration for re-use due to initiators not suitable for export group type.", mask.getMaskName()));
            }
        }
        if (!candidateExportMaskURIs.isEmpty()) {
            if (validateCandidateMasksAgainstExportPathParams(exportPathParams, maskToTotalMatchingPorts)) {
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Initiator %s (%s) will be mapped to these ExportMask URIs: %s", portName, initiatorURI.toString(), Joiner.on(',').join(exportMaskURIs)));
                initiatorToExportMaskURIMap.put(portName, candidateExportMaskURIs);
            }
        } else {
            if (masksWithUnmatchedStoragePorts.isEmpty()) {
                _log.info(String.format("determineInitiatorToExportMaskPlacements - Could not find ExportMask to which %s can be associated", portName));
            } else {
                // We found matching exports on the array, but they were not viable due to
                // the StoragePorts used (they were pointing to a different VArray), so we should
                // warn the user in this case. We will likely still attempt to make a new mask,
                // so if the user doesn't prefer that, this message will tell them why we took that
                // path.
                StringBuilder exportMaskInfo = new StringBuilder();
                for (Map.Entry<URI, Map<String, String>> maskToStoragePortsEntry : masksWithUnmatchedStoragePorts.entrySet()) {
                    URI exportMaskURI = maskToStoragePortsEntry.getKey();
                    Map<String, String> storagePortToNetworks = maskToStoragePortsEntry.getValue();
                    ExportMask mask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
                    exportMaskInfo.append(String.format("MaskingView=%s StoragePorts [ %s ]%n", mask.getMaskName(), Joiner.on(',').join(storagePortToNetworks.entrySet())));
                }
                VirtualArray virtualArray = _dbClient.queryObject(VirtualArray.class, exportGroup.getVirtualArray());
                Exception e = DeviceControllerException.exceptions.existingExportFoundButWithSPsInDifferentNetwork(virtualArray.getLabel(), exportMaskInfo.toString());
                _log.warn(e.getMessage());
            }
        }
    }
    _log.info(String.format("determineInitiatorToExportMaskPlacements - initiatorToExportMaskURIMap: %s", Joiner.on(',').join(initiatorToExportMaskURIMap.entrySet())));
    return initiatorToExportMaskURIMap;
}
Also used : VirtualArray(com.emc.storageos.db.client.model.VirtualArray) Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) URI(java.net.URI) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) Initiator(com.emc.storageos.db.client.model.Initiator) List(java.util.List) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) HashSet(java.util.HashSet) ExportMask(com.emc.storageos.db.client.model.ExportMask) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint) ContainmentConstraint(com.emc.storageos.db.client.constraint.ContainmentConstraint) WorkflowException(com.emc.storageos.workflow.WorkflowException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) IOException(java.io.IOException) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams)

Example 2 with ExportPathParams

use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.

the class BlockService method verifyVirtualPoolChangeSupportedForVolumeAndVirtualPool.

/**
 * Determines whether or not the passed VirtualPool change for the passed Volume is
 * supported. Throws a ServiceCodeException when the vpool change is not
 * supported.
 *
 * @param volume
 *            A reference to the volume.
 * @param newVpool
 *            A reference to the new VirtualPool.
 */
private void verifyVirtualPoolChangeSupportedForVolumeAndVirtualPool(Volume volume, VirtualPool newVpool) {
    // Currently, Vpool change is only supported for volumes on
    // VPlex storage systems and volumes (both regular and VPLEX i.e. RP+VPLEX) that are currently
    // unprotected by RP to a Vpool that has RP, as long as the source volume doesn't have to move.
    VirtualPool currentVpool = _dbClient.queryObject(VirtualPool.class, volume.getVirtualPool());
    URI systemURI = volume.getStorageController();
    StorageSystem system = _dbClient.queryObject(StorageSystem.class, systemURI);
    String systemType = system.getSystemType();
    StringBuffer notSuppReasonBuff = new StringBuffer();
    notSuppReasonBuff.setLength(0);
    /**
     * Do not support following vpool change operations for the volume part of application
     * 1. Move into Vplex
     * 2. Add RecoverPoint
     * 3. Remove RecoverPoint
     * 4. Add SRDF
     */
    if (volume.getApplication(_dbClient) != null) {
        // Move into VPLEX
        if (!VirtualPool.vPoolSpecifiesHighAvailability(currentVpool) && VirtualPool.vPoolSpecifiesHighAvailability(newVpool)) {
            notSuppReasonBuff.append("Non VPLEX volumes in applications cannot be moved into VPLEX pools");
            throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
        }
        // Add recoverPoint
        if (!VirtualPool.vPoolSpecifiesProtection(currentVpool) && VirtualPool.vPoolSpecifiesProtection(newVpool)) {
            notSuppReasonBuff.append("Non RP volumes in applications cannot be moved into RP pools");
            throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
        }
        // Remove RecoverPoint
        if (VirtualPool.vPoolSpecifiesProtection(currentVpool) && !VirtualPool.vPoolSpecifiesProtection(newVpool)) {
            notSuppReasonBuff.append("RP volumes in applications cannot be moved into non RP pools");
            throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
        }
        // Add SRDF
        if (!VirtualPool.vPoolSpecifiesSRDF(currentVpool) && VirtualPool.vPoolSpecifiesSRDF(newVpool)) {
            notSuppReasonBuff.append("volumes in applications cannot be moved into SRDF pools");
            throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
        }
    }
    // Check if an Export Path Params change.
    if (VirtualPoolChangeAnalyzer.isSupportedPathParamsChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
        ExportPathUpdater updater = new ExportPathUpdater(_dbClient);
        ExportPathParams newParam = new ExportPathParams(newVpool.getNumPaths(), newVpool.getMinPaths(), newVpool.getPathsPerInitiator());
        updater.validateChangePathParams(volume.getId(), newParam);
        _log.info("New VPool specifies an Export Path Params change");
        return;
    }
    // Check if it is an Auto-tiering policy change.
    notSuppReasonBuff.setLength(0);
    if (VirtualPoolChangeAnalyzer.isSupportedAutoTieringPolicyAndLimitsChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
        _log.info("New VPool specifies an Auto-tiering policy change");
        return;
    }
    if (VirtualPoolChangeAnalyzer.isSupportedReplicationModeChange(currentVpool, newVpool, notSuppReasonBuff)) {
        _log.info("New VPool specifies a replication mode change");
        return;
    }
    if (DiscoveredDataObject.Type.vplex.name().equals(systemType)) {
        _log.info("Volume is a VPlex virtual volume.");
        // the Vpool specifies a different grade of disk drives.
        if (!VirtualPool.vPoolSpecifiesHighAvailability(newVpool)) {
            _log.info("New VirtualPool does not specify VPlex high availability.");
            throw new ServiceCodeException(ServiceCode.API_VOLUME_VPOOL_CHANGE_DISRUPTIVE, "New VirtualPool {0} does not specify vplex high availability", new Object[] { newVpool.getId() });
        } else {
            notSuppReasonBuff.setLength(0);
            // can be exposed in the Migration Services catalog to support RP+VPLEX Data Migrations.
            if (volume.checkPersonality(Volume.PersonalityTypes.METADATA)) {
                if (VirtualPoolChangeAnalyzer.vpoolChangeRequiresMigration(currentVpool, newVpool)) {
                    verifyVPlexVolumeForDataMigration(volume, currentVpool, newVpool, _dbClient);
                    return;
                }
            }
            // if the request is trying to remove RP protection.
            if (volume.checkForRp() && VirtualPool.vPoolSpecifiesProtection(currentVpool) && !VirtualPool.vPoolSpecifiesProtection(newVpool)) {
                notSuppReasonBuff.setLength(0);
                if (!VirtualPoolChangeAnalyzer.isSupportedRPRemoveProtectionVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
                    throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
                }
            } else if (VirtualPool.vPoolSpecifiesRPVPlex(newVpool)) {
                notSuppReasonBuff.setLength(0);
                // Check to see if any of the operations for protected vpool to protected vpool changes are supported
                if (VirtualPool.vPoolSpecifiesRPVPlex(currentVpool)) {
                    if (VirtualPoolChangeAnalyzer.isSupportedRPVPlexMigrationVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff, null)) {
                        verifyVPlexVolumeForDataMigration(volume, currentVpool, newVpool, _dbClient);
                    } else if (!VirtualPoolChangeAnalyzer.isSupportedUpgradeToMetroPointVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
                        _log.warn("RP Change Protection VirtualPool change for volume is not supported: {}", notSuppReasonBuff.toString());
                        throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
                    }
                } else // Otherwise, check to see if we're trying to protect a VPLEX volume.
                if (!VirtualPoolChangeAnalyzer.isSupportedAddRPProtectionVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
                    _log.warn("RP+VPLEX VirtualPool change for volume is not supported: {}", notSuppReasonBuff.toString());
                    throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
                } else if (BlockFullCopyUtils.volumeHasFullCopySession(volume, _dbClient)) {
                    // Full copies not supported for RP protected volumes.
                    throw APIException.badRequests.volumeForRPVpoolChangeHasFullCopies(volume.getLabel());
                }
            } else {
                VirtualPoolChangeOperationEnum vplexVpoolChangeOperation = VirtualPoolChangeAnalyzer.getSupportedVPlexVolumeVirtualPoolChangeOperation(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff);
                if (vplexVpoolChangeOperation == null) {
                    _log.warn("VPlex volume VirtualPool change not supported {}", notSuppReasonBuff.toString());
                    throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
                } else if (VPlexUtil.isVolumeBuiltOnBlockSnapshot(_dbClient, volume)) {
                    // created using the target volume of a block snapshot.
                    throw APIException.badRequests.vpoolChangeNotAllowedVolumeIsExposedSnapshot(volume.getId().toString());
                } else if (vplexVpoolChangeOperation == VirtualPoolChangeOperationEnum.VPLEX_DATA_MIGRATION) {
                    verifyVPlexVolumeForDataMigration(volume, currentVpool, newVpool, _dbClient);
                }
            }
        }
    } else if (DiscoveredDataObject.Type.vmax.name().equals(systemType) || DiscoveredDataObject.Type.vnxblock.name().equals(systemType) || DiscoveredDataObject.Type.hds.name().equals(systemType) || DiscoveredDataObject.Type.xtremio.name().equals(systemType) || DiscoveredDataObject.Type.ibmxiv.name().equals(systemType) || DiscoveredDataObject.Type.unity.name().equals(systemType)) {
        if (VirtualPool.vPoolSpecifiesHighAvailability(newVpool)) {
            // VNX/VMAX import to VPLEX cases
            notSuppReasonBuff.setLength(0);
            if (!VirtualPoolChangeAnalyzer.isVPlexImport(volume, currentVpool, newVpool, notSuppReasonBuff) || (!VirtualPoolChangeAnalyzer.doesVplexVpoolContainVolumeStoragePool(volume, newVpool, notSuppReasonBuff))) {
                _log.warn("VNX/VMAX cos change for volume is not supported: {}", notSuppReasonBuff.toString());
                throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
            }
            if (volume.isVolumeExported(_dbClient)) {
                throw APIException.badRequests.cannotImportExportedVolumeToVplex(volume.getId());
            } else if (BlockFullCopyUtils.volumeHasFullCopySession(volume, _dbClient)) {
                // The backend would have a full copy, but the VPLEX volume would not.
                throw APIException.badRequests.volumeForVpoolChangeHasFullCopies(volume.getLabel());
            } else {
                // Can't be imported if it has snapshot sessions, because we
                // don't currently support these behind VPLEX.
                List<BlockSnapshotSession> snapSessions = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, BlockSnapshotSession.class, ContainmentConstraint.Factory.getParentSnapshotSessionConstraint(volume.getId()));
                if (!snapSessions.isEmpty()) {
                    throw APIException.badRequests.cannotImportVolumeWithSnapshotSessions(volume.getLabel());
                }
            }
        } else if (VirtualPool.vPoolSpecifiesProtection(newVpool)) {
            // VNX/VMAX import to RP cases (currently one)
            notSuppReasonBuff.setLength(0);
            if (!VirtualPoolChangeAnalyzer.isSupportedAddRPProtectionVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
                _log.warn("VirtualPool change to Add RP Protection for volume is not supported: {}", notSuppReasonBuff.toString());
                throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
            } else if (BlockFullCopyUtils.volumeHasFullCopySession(volume, _dbClient)) {
                // Full copies not supported for RP protected volumes.
                throw APIException.badRequests.volumeForRPVpoolChangeHasFullCopies(volume.getLabel());
            } else {
                // Can't add RP if it has snapshot sessions, because we
                // don't currently support these for RP protected volumes.
                List<BlockSnapshotSession> snapSessions = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, BlockSnapshotSession.class, ContainmentConstraint.Factory.getParentSnapshotSessionConstraint(volume.getId()));
                if (!snapSessions.isEmpty()) {
                    throw APIException.badRequests.volumeForRPVpoolChangeHasSnapshotSessions(volume.getLabel());
                }
            }
        } else if (VirtualPool.vPoolSpecifiesProtection(currentVpool) && !VirtualPool.vPoolSpecifiesProtection(newVpool)) {
            notSuppReasonBuff.setLength(0);
            if (!VirtualPoolChangeAnalyzer.isSupportedRPRemoveProtectionVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
                throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
            }
        } else if (VirtualPool.vPoolSpecifiesSRDF(newVpool)) {
            // VMAX import to SRDF cases (currently one)
            notSuppReasonBuff.setLength(0);
            if (!VirtualPoolChangeAnalyzer.isSupportedSRDFVolumeVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
                _log.warn("VMAX VirtualPool change for volume is not supported: {}", notSuppReasonBuff.toString());
                throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
            } else if (BlockFullCopyUtils.volumeHasFullCopySession(volume, _dbClient)) {
                // Full copy not supported for volumes with asynchronous copy mode.
                Map<URI, VpoolRemoteCopyProtectionSettings> remoteCopySettingsMap = VirtualPool.getRemoteProtectionSettings(newVpool, _dbClient);
                VpoolRemoteCopyProtectionSettings remoteCopyProtectionSettings = remoteCopySettingsMap.values().iterator().next();
                if (SupportedCopyModes.ASYNCHRONOUS.toString().equalsIgnoreCase(remoteCopyProtectionSettings.getCopyMode())) {
                    throw APIException.badRequests.volumeForSRDFVpoolChangeHasFullCopies(volume.getLabel());
                }
            }
        } else if (!NullColumnValueGetter.isNullNamedURI(volume.getSrdfParent()) || (volume.getSrdfTargets() != null && !volume.getSrdfTargets().isEmpty())) {
            // Cannot move SRDF Volume to non SRDF VPool
            throw APIException.badRequests.srdfVolumeVPoolChangeToNonSRDFVPoolNotSupported(volume.getId());
        } else if (VirtualPool.vPoolSpecifiesMirrors(newVpool, _dbClient)) {
            notSuppReasonBuff.setLength(0);
            if (!VirtualPoolChangeAnalyzer.isSupportedAddMirrorsVirtualPoolChange(volume, currentVpool, newVpool, _dbClient, notSuppReasonBuff)) {
                _log.warn("VirtualPool change to add continuous copies for volume {} is not supported: {}", volume.getId(), notSuppReasonBuff.toString());
                throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
            }
        } else {
            String errMsg = "there was an invalid property mismatch between source and target vPools.";
            _log.error(errMsg);
            notSuppReasonBuff.append(errMsg);
            throw APIException.badRequests.changeToVirtualPoolNotSupported(newVpool.getLabel(), notSuppReasonBuff.toString());
        }
    } else {
        _log.info("VirtualPool change volume is not a vplex, vmax or vnxblock volume");
        throw new ServiceCodeException(ServiceCode.API_VOLUME_VPOOL_CHANGE_DISRUPTIVE, "VirtualPool change is not supported for volume {0}", new Object[] { volume.getId() });
    }
}
Also used : ExportPathUpdater(com.emc.storageos.volumecontroller.placement.ExportPathUpdater) VpoolRemoteCopyProtectionSettings(com.emc.storageos.db.client.model.VpoolRemoteCopyProtectionSettings) BlockSnapshotSession(com.emc.storageos.db.client.model.BlockSnapshotSession) VirtualPoolChangeOperationEnum(com.emc.storageos.model.vpool.VirtualPoolChangeOperationEnum) ServiceCodeException(com.emc.storageos.svcs.errorhandling.resources.ServiceCodeException) VirtualPool(com.emc.storageos.db.client.model.VirtualPool) URI(java.net.URI) NullColumnValueGetter.isNullURI(com.emc.storageos.db.client.util.NullColumnValueGetter.isNullURI) ITLRestRepList(com.emc.storageos.model.block.export.ITLRestRepList) VirtualPoolChangeList(com.emc.storageos.model.vpool.VirtualPoolChangeList) BlockSnapshotSessionList(com.emc.storageos.model.block.BlockSnapshotSessionList) ArrayList(java.util.ArrayList) TaskList(com.emc.storageos.model.TaskList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) NamedVolumesList(com.emc.storageos.model.block.NamedVolumesList) BulkList(com.emc.storageos.api.service.impl.response.BulkList) MigrationList(com.emc.storageos.model.block.MigrationList) SearchedResRepList(com.emc.storageos.api.service.impl.response.SearchedResRepList) MirrorList(com.emc.storageos.model.block.MirrorList) SnapshotList(com.emc.storageos.model.SnapshotList) BlockObject(com.emc.storageos.db.client.model.BlockObject) DiscoveredDataObject(com.emc.storageos.db.client.model.DiscoveredDataObject) DataObject(com.emc.storageos.db.client.model.DataObject) Map(java.util.Map) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams)

Example 3 with ExportPathParams

use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.

the class ExportGroupService method removeBlockObjectsFromPathParamMap.

/**
 * For all the block objects in the list, checks to see if they are associated with an ExportPathParam object.
 * If so they are removed. If there are no remaining block objects, the ExportPathParam is deleted.
 *
 * @param blockObjectURIs
 * @param exportGroup
 */
void removeBlockObjectsFromPathParamMap(Collection<URI> blockObjectURIs, ExportGroup exportGroup) {
    // For each BlockObject, remove its association to a ExportPathParam.
    for (URI blockObjectURI : blockObjectURIs) {
        String pathParamId = exportGroup.getPathParameters().get(blockObjectURI.toString());
        if (pathParamId == null) {
            continue;
        }
        exportGroup.removeFromPathParameters(blockObjectURI);
        // If there are no more entries for the given ExportPathParam, mark it for deletion
        if (!exportGroup.getPathParameters().containsValue(pathParamId)) {
            URI pathParamURI = URI.create(pathParamId);
            ExportPathParams pathParam = _dbClient.queryObject(ExportPathParams.class, pathParamURI);
            if (pathParam != null) {
                _dbClient.markForDeletion(pathParam);
            }
        }
    }
}
Also used : NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams)

Example 4 with ExportPathParams

use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.

the class ExportGroupService method validateNoConflictingExports.

/**
 * Throw an error if we cannot override the Vpool path parameters because there is already
 * an existing export from the indicated host(s) to storage array(s).
 *
 * @param exportGroup
 * @param arrayURIs
 * @param pathParam -- New ExportPathParams to be used
 */
private void validateNoConflictingExports(ExportGroup exportGroup, Set<URI> arrayURIs, ExportPathParams pathParam) {
    _log.info("Requested path parameters: " + pathParam.toString());
    Map<String, String> conflictingMasks = new HashMap<String, String>();
    StringSet initiators = exportGroup.getInitiators();
    if (initiators == null) {
        // No initiators currently in export, nothing to do
        return;
    }
    for (String initiatorId : initiators) {
        Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(initiatorId));
        if (initiator == null || initiator.getInactive()) {
            continue;
        }
        // Look up all the Export Masks for this Initiator
        List<ExportMask> exportMasks = ExportUtils.getInitiatorExportMasks(initiator, _dbClient);
        for (ExportMask exportMask : exportMasks) {
            // If this mask is for the same Host and Storage combination, we cannot override
            if (arrayURIs.contains(exportMask.getStorageDevice())) {
                ExportPathParams maskParam = BlockStorageScheduler.calculateExportPathParamForExportMask(_dbClient, exportMask);
                _log.info(String.format("Existing mask %s (%s) parameters: %s", exportMask.getMaskName(), exportMask.getId(), maskParam));
                // i.e. maskParams.ppi = pathParms.ppi and pathParams.minPath <= maskParams.maxpath <= pathParams.maxPath
                if (pathParam.getPathsPerInitiator() == maskParam.getPathsPerInitiator() && (pathParam.getMinPaths() <= maskParam.getMaxPaths() && maskParam.getMaxPaths() <= pathParam.getMaxPaths())) {
                    _log.info(String.format("Export mask %s is compatible with the requested parameters", exportMask.getMaskName()));
                } else {
                    StorageSystem system = _dbClient.queryObject(StorageSystem.class, exportMask.getStorageDevice());
                    String hostName = (initiator.getHostName() != null) ? initiator.getHostName() : initiatorId;
                    String systemName = (system != null) ? system.getLabel() : exportMask.getStorageDevice().toString();
                    if (!conflictingMasks.containsKey(hostName)) {
                        String msg = String.format("Export Mask %s for Host %s and Array %s has %d paths and paths_per_initiator %d", exportMask.getMaskName(), hostName, systemName, maskParam.getMaxPaths(), maskParam.getPathsPerInitiator());
                        conflictingMasks.put(hostName, msg);
                    }
                }
            }
        }
    }
    if (!conflictingMasks.isEmpty()) {
        StringBuilder builder = new StringBuilder();
        for (Entry<String, String> entry : conflictingMasks.entrySet()) {
            if (builder.length() != 0) {
                builder.append("; ");
            }
            builder.append(entry.getValue());
        }
        throw APIException.badRequests.cannotOverrideVpoolPathsBecauseExistingExports(builder.toString());
    }
}
Also used : HashMap(java.util.HashMap) Initiator(com.emc.storageos.db.client.model.Initiator) ExportMask(com.emc.storageos.db.client.model.ExportMask) StringSet(com.emc.storageos.db.client.model.StringSet) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 5 with ExportPathParams

use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.

the class ExportGroupService method pathsAdjustment.

/**
 * Export paths adjustment
 *
 * @param id The export group id
 * @param param The parameters including addedPaths, removedPaths, storage system URI, exportPathParameters,
 *                  and waitBeforeRemovePaths
 * @brief Initiate port allocations for export
 * @return The pending task
 * @throws ControllerException
 */
@PUT
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/paths-adjustment")
@CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL })
public TaskResourceRep pathsAdjustment(@PathParam("id") URI id, ExportPathsAdjustmentParam param) throws ControllerException {
    // Basic validation of ExportGroup and the request
    ExportGroup exportGroup = queryObject(ExportGroup.class, id, true);
    if (exportGroup.checkInternalFlags(DataObject.Flag.DELETION_IN_PROGRESS)) {
        throw BadRequestException.badRequests.deletionInProgress(exportGroup.getClass().getSimpleName(), exportGroup.getLabel());
    }
    validateExportGroupNoPendingEvents(exportGroup);
    validateSuspendSetForNonDiscoverableHosts(exportGroup, param.getWaitBeforeRemovePaths(), param.getRemovedPaths().isEmpty());
    ArgValidator.checkUri(param.getStorageSystem());
    StorageSystem system = queryObject(StorageSystem.class, param.getStorageSystem(), true);
    // Log the input parameters
    param.logParameters(_log);
    // Get the virtual array, default to Export Group varray. Validate it matches.
    URI varray = param.getVirtualArray();
    if (varray != null) {
        boolean validVarray = varray.equals(exportGroup.getVirtualArray());
        if (exportGroup.getAltVirtualArrays() != null && varray.toString().equals(exportGroup.getAltVirtualArrays().get(system.getId().toString()))) {
            validVarray = true;
        }
        if (!validVarray) {
            throw APIException.badRequests.varrayNotInExportGroup(varray.toString());
        }
    } else {
        varray = exportGroup.getVirtualArray();
    }
    validatePathAdjustment(exportGroup, system, param, varray);
    Boolean wait = new Boolean(param.getWaitBeforeRemovePaths());
    String task = UUID.randomUUID().toString();
    Operation op = initTaskStatus(exportGroup, task, Operation.Status.pending, ResourceOperationTypeEnum.EXPORT_PATHS_ADJUSTMENT);
    // persist the export group to the database
    _dbClient.updateObject(exportGroup);
    auditOp(OperationTypeEnum.EXPORT_PATH_ADJUSTMENT, true, AuditLogManager.AUDITOP_BEGIN, exportGroup.getLabel(), exportGroup.getId().toString(), exportGroup.getVirtualArray().toString(), exportGroup.getProject().toString());
    TaskResourceRep taskRes = toTask(exportGroup, task, op);
    BlockExportController exportController = getExportController();
    _log.info("Submitting export path adjustment request.");
    Map<URI, List<URI>> addedPaths = convertInitiatorPathParamToMap(param.getAdjustedPaths());
    Map<URI, List<URI>> removedPaths = convertInitiatorPathParamToMap(param.getRemovedPaths());
    ExportPathParams pathParam = new ExportPathParams(param.getExportPathParameters(), exportGroup);
    exportController.exportGroupPortRebalance(param.getStorageSystem(), id, varray, addedPaths, removedPaths, pathParam, wait, task);
    return taskRes;
}
Also used : ExportGroup(com.emc.storageos.db.client.model.ExportGroup) BlockExportController(com.emc.storageos.volumecontroller.BlockExportController) TaskResourceRep(com.emc.storageos.model.TaskResourceRep) ITLRestRepList(com.emc.storageos.model.block.export.ITLRestRepList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) BulkList(com.emc.storageos.api.service.impl.response.BulkList) SearchedResRepList(com.emc.storageos.api.service.impl.response.SearchedResRepList) Operation(com.emc.storageos.db.client.model.Operation) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) ExportPathParams(com.emc.storageos.db.client.model.ExportPathParams) Path(javax.ws.rs.Path) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) PUT(javax.ws.rs.PUT) CheckPermission(com.emc.storageos.security.authorization.CheckPermission)

Aggregations

ExportPathParams (com.emc.storageos.db.client.model.ExportPathParams)39 URI (java.net.URI)33 ArrayList (java.util.ArrayList)26 List (java.util.List)21 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)17 Initiator (com.emc.storageos.db.client.model.Initiator)17 HashMap (java.util.HashMap)17 ExportMask (com.emc.storageos.db.client.model.ExportMask)13 HashSet (java.util.HashSet)13 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)12 NamedURI (com.emc.storageos.db.client.model.NamedURI)12 Map (java.util.Map)11 StringMap (com.emc.storageos.db.client.model.StringMap)8 StoragePortGroup (com.emc.storageos.db.client.model.StoragePortGroup)6 StringSet (com.emc.storageos.db.client.model.StringSet)6 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)6 ApplicationAddVolumeList (com.emc.storageos.volumecontroller.ApplicationAddVolumeList)6 Workflow (com.emc.storageos.workflow.Workflow)6 BlockObject (com.emc.storageos.db.client.model.BlockObject)5 StoragePort (com.emc.storageos.db.client.model.StoragePort)5