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);
}
}
}
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;
}
Aggregations