Search in sources :

Example 1 with ExportMaskPlacementDescriptor

use of com.emc.storageos.volumecontroller.impl.block.ExportMaskPlacementDescriptor in project coprhd-controller by CoprHD.

the class VPlexBackendManager method chooseBackendExportMask.

/**
 * Choose one of the existing Export Masks (on VMAX: masking views) if possible in
 * which to place the volume to be exported to the VPlex. Otherwise ExportMask(s)
 * will be generated and one will be chosen from the generated set.
 *
 * @param vplex
 *            [IN] - VPlex storage system
 * @param array
 *            [IN] - Storage Array storage system
 * @param varrayURI
 *            [IN] - Virtual array
 * @param volumeMap
 *            [IN] - Map of URI to their corresponding Volume object
 * @param stepId
 *            the workflow step id used find the workflow where the existing zone information is stored
 * @return ExportMaskPlacementDescriptor - data structure that will indicate the mapping of ExportMasks to
 *         ExportGroups and ExportMasks to Volumes.
 * @throws ControllerException
 */
public ExportMaskPlacementDescriptor chooseBackendExportMask(StorageSystem vplex, StorageSystem array, URI varrayURI, Map<URI, Volume> volumeMap, String stepId) throws ControllerException {
    _log.info(String.format("Searching for existing ExportMasks between Vplex %s (%s) and Array %s (%s) in Varray %s", vplex.getLabel(), vplex.getNativeGuid(), array.getLabel(), array.getNativeGuid(), varrayURI));
    long startTime = System.currentTimeMillis();
    // The volumeMap can contain volumes from different arrays. We are interested only in the ones for 'array'.
    Map<URI, Volume> volumesForArray = filterVolumeMap(volumeMap, array);
    // Build the data structures used for analysis and validation.
    buildDataStructures(vplex, array, varrayURI);
    VplexBackEndMaskingOrchestrator vplexBackendOrchestrator = getOrch(array);
    BlockStorageDevice storageDevice = _blockDeviceController.getDevice(array.getSystemType());
    // Lock operation.
    String lockName = _vplexApiLockManager.getLockName(vplex.getId(), _cluster, array.getId());
    boolean lockAcquired = false;
    try {
        if (_vplexApiLockManager != null) {
            lockAcquired = _vplexApiLockManager.acquireLock(lockName, MAX_LOCK_WAIT_SECONDS);
            if (!lockAcquired) {
                _log.info("Timed out waiting on lock- PROCEEDING ANYWAY!");
            }
        }
        // Initialize the placement data structure
        ExportMaskPlacementDescriptor placementDescriptor = ExportMaskPlacementDescriptor.create(_tenantURI, _projectURI, vplex, array, varrayURI, volumesForArray, _idToInitiatorMap.values());
        // VplexBackEndMaskingOrchestrator#suggestExportMasksForPlacement should fill in the rest of the
        // placement data structures, such that decisions on how to reuse the ExportMasks can be done here.
        // At a minimum, this placement is done based on reading the ExportMasks off the backend array based on the
        // initiators.
        // Customizations can be done per array based on other factors. Most notably, for the case of VMAX, this
        // would
        // place volumes in appropriate ExportMasks based on the volume's AutoTieringPolicy relationship.
        vplexBackendOrchestrator.suggestExportMasksForPlacement(array, storageDevice, _initiators, placementDescriptor);
        // Apply the filters that will remove any ExportMasks that do not fit the expected VPlex masking paradigm
        Set<URI> invalidMasks = filterExportMasksByVPlexRequirements(vplex, array, varrayURI, placementDescriptor);
        // If there were any invalid masks found, we can redo the volume placement into
        // an alternative ExportMask (if there are any listed by the descriptor)
        putUnplacedVolumesIntoAlternativeMask(placementDescriptor);
        // If not, we will attempt to generate some.
        if (!placementDescriptor.hasMasks()) {
            _log.info("There weren't any ExportMasks in the placementDescriptor. Creating new ExportMasks for the volumes.");
            // Did not find any reusable ExportMasks. Either there were some that matched initiators, but did not
            // meeting the
            // VPlex criteria, or there were no existing masks for the backend at all.
            Map<URI, Volume> volumesToPlace = placementDescriptor.getVolumesToPlace();
            createVPlexBackendExportMasksForVolumes(vplex, array, varrayURI, placementDescriptor, invalidMasks, volumesToPlace, stepId);
        } else if (placementDescriptor.hasUnPlacedVolumes()) {
            _log.info("There were some reusable ExportMasks found, but not all volumes got placed. Will create an ExportMask to " + "hold these unplaced volumes.");
            // There were some matching ExportMasks found on the backend array, but we also have some
            // unplaced
            // volumes. We need to create new ExportMasks to hold these unplaced volumes.
            // We will leave the placement hint to whatever was determined by the suggestExportMasksForPlacement
            // call
            Map<URI, Volume> unplacedVolumes = placementDescriptor.getUnplacedVolumes();
            createVPlexBackendExportMasksForVolumes(vplex, array, varrayURI, placementDescriptor, invalidMasks, unplacedVolumes, stepId);
        }
        // At this point, we have:
        // 
        // a). Requested that the backend StorageArray provide us with a list of ExportMasks that can support the
        // initiators + volumes.
        // b). Processed the suggested ExportMasks in case they had their names changed
        // c). Filtered out any ExportMasks that do not fit the VPlex masking paradigm
        // OR
        // d). Created a set of new ExportMasks to support the initiators + volumes
        // 
        // We will now run the final placement based on a strategy determined by looking at the placementDescriptor
        VPlexBackendPlacementStrategyFactory.create(_dbClient, placementDescriptor).execute();
        long elapsed = System.currentTimeMillis() - startTime;
        _log.info(String.format("PlacementDescriptor processing took %f seconds", (double) elapsed / (double) 1000));
        _log.info(String.format("PlacementDescriptor was created:%n%s", placementDescriptor.toString()));
        return placementDescriptor;
    } finally {
        if (lockAcquired) {
            _vplexApiLockManager.releaseLock(lockName);
        }
    }
}
Also used : BlockStorageDevice(com.emc.storageos.volumecontroller.BlockStorageDevice) Volume(com.emc.storageos.db.client.model.Volume) VplexBackEndMaskingOrchestrator(com.emc.storageos.volumecontroller.impl.block.VplexBackEndMaskingOrchestrator) ExportMaskPlacementDescriptor(com.emc.storageos.volumecontroller.impl.block.ExportMaskPlacementDescriptor) URI(java.net.URI) Map(java.util.Map) HashMap(java.util.HashMap) StringSetMap(com.emc.storageos.db.client.model.StringSetMap)

Example 2 with ExportMaskPlacementDescriptor

use of com.emc.storageos.volumecontroller.impl.block.ExportMaskPlacementDescriptor in project coprhd-controller by CoprHD.

the class VPlexDeviceController method createWorkflowStepsForBlockVolumeExport.

/**
 * Create workflow steps in the passed workflow to create export groups for the
 * front end ports of the passed storage systems to the backend ports of the
 * passed VPlex storage system for the purpose of exposing volumes on these
 * storage system to the VPlex.
 *
 * @param workflow
 *            The workflow to which the export steps are added.
 * @param vplexSystem
 *            A reference to the VPlex storage system.
 * @param storageSystemMap
 *            The list of storage systems to export.
 * @param volumeMap
 *            The volumes to be exported.
 * @param projectURI
 *            The project reference.
 * @param tenantURI
 *            The tenant reference.
 * @param dependantStepId
 *            The dependent step if, typically a volume creation step.
 *
 * @throws IOException
 *             When an error occurs.
 * @throws ControllerException
 */
private String createWorkflowStepsForBlockVolumeExport(Workflow workflow, StorageSystem vplexSystem, Map<URI, StorageSystem> storageSystemMap, Map<URI, Volume> volumeMap, URI projectURI, URI tenantURI, String dependantStepId) throws IOException, ControllerException {
    String lastStep = dependantStepId;
    // The following adds a rollback step to forget the volumes if something
    // goes wrong. This is a nop on provisioning.
    lastStep = addRollbackStepToForgetVolumes(workflow, vplexSystem.getId(), new ArrayList<URI>(volumeMap.keySet()), lastStep);
    String forgetRBStep = lastStep;
    URI vplexURI = vplexSystem.getId();
    // Populate the container for the export workflow step generation
    for (Map.Entry<URI, StorageSystem> storageEntry : storageSystemMap.entrySet()) {
        URI storageSystemURI = storageEntry.getKey();
        StorageSystem storageSystem = storageEntry.getValue();
        URI varray = getVolumesVarray(storageSystem, volumeMap.values());
        _log.info(String.format("Creating ExportGroup for storage system %s (%s) in Virtual Aarray[(%s)]", storageSystem.getLabel(), storageSystemURI, varray));
        if (varray == null) {
            // For whatever reason, there were no Volumes for this Storage System found, so we
            // definitely do not want to create anything. Log a warning and continue.
            _log.warn(String.format("No Volumes for storage system %s (%s), no need to create an ExportGroup.", storageSystem.getLabel(), storageSystemURI));
            continue;
        }
        // Get the initiator port map for this VPLEX and storage system
        // for this volumes virtual array.
        VPlexBackendManager backendMgr = new VPlexBackendManager(_dbClient, this, _blockDeviceController, _blockScheduler, _networkDeviceController, projectURI, tenantURI, _vplexApiLockManager, coordinator);
        Map<URI, List<StoragePort>> initiatorPortMap = backendMgr.getInitiatorPortsForArray(vplexURI, storageSystemURI, varray);
        // If there are no networks that can be zoned, error.
        if (initiatorPortMap.isEmpty()) {
            throw DeviceControllerException.exceptions.noNetworksConnectingVPlexToArray(vplexSystem.getNativeGuid(), storageSystem.getNativeGuid());
        }
        // Select from an existing ExportMask if possible
        ExportMaskPlacementDescriptor descriptor = backendMgr.chooseBackendExportMask(vplexSystem, storageSystem, varray, volumeMap, lastStep);
        // refresh export masks per XIO storage array
        boolean needRefresh = storageSystem.deviceIsType(DiscoveredDataObject.Type.xtremio);
        // For every ExportMask in the descriptor ...
        for (URI exportMaskURI : descriptor.getPlacedMasks()) {
            // Create steps to place each set of volumes into its assigned ExportMask
            ExportGroup exportGroup = descriptor.getExportGroupForMask(exportMaskURI);
            ExportMask exportMask = descriptor.getExportMask(exportMaskURI);
            Map<URI, Volume> placedVolumes = descriptor.getPlacedVolumes(exportMaskURI);
            if (needRefresh) {
                BlockStorageDevice device = _blockDeviceController.getDevice(storageSystem.getSystemType());
                device.refreshExportMask(storageSystem, exportMask);
                needRefresh = false;
                ;
            }
            // Add the workflow steps.
            lastStep = backendMgr.addWorkflowStepsToAddBackendVolumes(workflow, lastStep, exportGroup, exportMask, placedVolumes, varray, vplexSystem, storageSystem, forgetRBStep);
        }
    }
    return lastStep;
}
Also used : ExportMask(com.emc.storageos.db.client.model.ExportMask) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) BlockStorageDevice(com.emc.storageos.volumecontroller.BlockStorageDevice) Volume(com.emc.storageos.db.client.model.Volume) ExportMaskPlacementDescriptor(com.emc.storageos.volumecontroller.impl.block.ExportMaskPlacementDescriptor) ApplicationAddVolumeList(com.emc.storageos.volumecontroller.ApplicationAddVolumeList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

Volume (com.emc.storageos.db.client.model.Volume)2 BlockStorageDevice (com.emc.storageos.volumecontroller.BlockStorageDevice)2 ExportMaskPlacementDescriptor (com.emc.storageos.volumecontroller.impl.block.ExportMaskPlacementDescriptor)2 URI (java.net.URI)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)1 ExportGroup (com.emc.storageos.db.client.model.ExportGroup)1 ExportMask (com.emc.storageos.db.client.model.ExportMask)1 NamedURI (com.emc.storageos.db.client.model.NamedURI)1 OpStatusMap (com.emc.storageos.db.client.model.OpStatusMap)1 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)1 StringMap (com.emc.storageos.db.client.model.StringMap)1 StringSetMap (com.emc.storageos.db.client.model.StringSetMap)1 ApplicationAddVolumeList (com.emc.storageos.volumecontroller.ApplicationAddVolumeList)1 VplexBackEndMaskingOrchestrator (com.emc.storageos.volumecontroller.impl.block.VplexBackEndMaskingOrchestrator)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1