use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class BlockStorageScheduler method calculateExportPathParamForVolumes.
/**
* Given a collection of volume URIs, generates the ExportPathParam
* values for all volumes (block objects)
* in the collection. These are assumed to belong to (or about to belong to) one ExportMask.
* The maxPath value from any of the volumes will be returned, along with
* the corresponding pathsPerInitiator.
*
* @param blockObjectURIs Collection<URI>
* @param overrideNumPaths - if greater than zero, will override the calculation and be returned.
* @return numPaths
*/
// public ExportPathParams calculateExportPathParmForVolumes(Collection<URI> blockObjectURIs,
// Integer overrideNumPaths) {
// return calculateExportPathParamForVolumes(blockObjectURIs, overrideNumPaths, null);
// }
/**
* Given a collection of volume URIs, generates the ExportPathParam
* values for all volumes (block objects) in the collection.
* These are assumed to belong to (or about to belong to) one ExportMask.
* The maxPath value from any of the volumes will be returned, along with
* the corresponding pathsPerInitiator.
*
* @param blockObjectURIs Collection<URI>
* @param overrideNumPaths - if greater than zero, will override the calculation and be returned.
* @param storageSystemURI URI of Storage System, if not null, filters out
* BlockObjects created on other systems
* @param exportGroupURI exportGroupURI
* @return numPaths
*/
public ExportPathParams calculateExportPathParamForVolumes(Collection<URI> blockObjectURIs, Integer overrideNumPaths, URI storageSystemURI, URI exportGroupURI) {
ExportPathParams param = new ExportPathParams(0, 0, 0);
// Look up the exportGroup
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
// If overrideNumPaths is set, do that with pathsPerInitiator=2
if (overrideNumPaths != null && overrideNumPaths > 0) {
param = new ExportPathParams(overrideNumPaths, 0, 0);
param.setAllowFewerPorts(true);
return param;
}
if (blockObjectURIs != null) {
for (URI uri : blockObjectURIs) {
BlockObject blockObject = BlockObject.fetch(_dbClient, uri);
if (blockObject == null) {
continue;
}
if (storageSystemURI != null && !storageSystemURI.equals(blockObject.getStorageController())) {
continue;
}
ExportPathParams volParam = null;
if (exportGroup != null) {
// Check to see if the ExportGroup has path parameters for volume
if (exportGroup.getPathParameters().containsKey(uri.toString())) {
URI exportPathParamsUri = URI.create(exportGroup.getPathParameters().get(uri.toString()));
volParam = _dbClient.queryObject(ExportPathParams.class, exportPathParamsUri);
}
}
if (volParam == null || volParam.getMaxPaths() == null || volParam.getMaxPaths() == 0) {
// Otherwise check use the Vpool path parameters
URI vPoolURI = getBlockObjectVPoolURI(blockObject, _dbClient);
URI pgURI = null;
if (volParam != null) {
pgURI = volParam.getPortGroup();
}
volParam = getExportPathParam(blockObject, vPoolURI, _dbClient);
if (pgURI != null) {
volParam.setPortGroup(pgURI);
}
}
if (volParam.getMaxPaths() > param.getMaxPaths()) {
param = volParam;
}
}
}
if (param.getMaxPaths() == 0) {
param = ExportPathParams.getDefaultParams();
}
return param;
}
use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class ExportPathUpdater method validateChangePathParams.
/**
* This routine is called by the API service to validate that the change path parameters
* call will succeed. For now only the following are allowed:
* A. Increasing maxPaths with pathsPerInitiator the same.
* The following are disallowed:
* X. Decreasing maxPaths
* Y. Changing pathsPerInitiator.
*
* @param storageURI
* @param exportGroupURI
* @param volume (BlockObject)
* @param newParam ExportPathParam new parameters being proposed
*/
private void validateChangePathParams(URI storageURI, URI exportGroupURI, BlockObject volume, ExportPathParams newParam) {
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
_log.info(String.format("Validating path parameters for volume %s (%s)", volume.getLabel(), volume.getId()));
Set<URI> volumeURISet = new HashSet<URI>();
volumeURISet.add(volume.getId());
// Check that the ExportGroup has not overridden the Vpool path parameters.
if (exportGroup.getPathParameters().containsKey(volume.getId().toString())) {
// Cannot do a Vpool path change because parameters have been set in Export Group
_log.info(String.format("No changes will be made to ExportGroup %s (%s) because it has explicit path parameters overiding the Vpool", exportGroup.getLabel(), exportGroup.getId()));
return;
}
// Search through the Export Masks looking for any containing this Volume.
// We only process ViPR created Export Masks, others are ignored.
List<ExportMask> masks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, storageURI);
for (ExportMask mask : masks) {
if (!mask.hasVolume(volume.getId())) {
continue;
}
if (mask.getCreatedBySystem() == false || mask.getZoningMap() == null) {
_log.info(String.format("ExportMask %s not ViPR created, and will be ignored", mask.getMaskName()));
continue;
}
ExportPathParams maskParam = BlockStorageScheduler.calculateExportPathParamForExportMask(_dbClient, mask);
if (newParam.getPathsPerInitiator() > maskParam.getPathsPerInitiator()) {
// We want to increase pathsPerInitiator
throw APIException.badRequests.cannotChangeVpoolPathsPerInitiator(exportGroup.getLabel(), mask.getMaskName());
} else if (newParam.getMaxPaths() < maskParam.getMaxPaths()) {
// We want to decreates maxPaths
throw APIException.badRequests.cannotReduceVpoolMaxPaths(exportGroup.getLabel(), mask.getMaskName());
}
}
}
use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class ExportPathUpdater method generateExportGroupChangePathParamsWorkflow.
/**
* Generates the workflow steps to change path parameters of an ExportGroup.
* The volume is used to determine the path parameters (from its Vpool).
*
* @param workflow
* @param blockScheduler
* @param orchestrator
* @param storage -- StorageSystem
* @param exportGroup
* @param volume
* @param token -- Task token
* @throws Exception
*/
public void generateExportGroupChangePathParamsWorkflow(Workflow workflow, BlockStorageScheduler blockScheduler, MaskingOrchestrator orchestrator, StorageSystem storage, ExportGroup exportGroup, BlockObject volume, String token) throws Exception {
Set<URI> volumeURISet = new HashSet<URI>();
volumeURISet.add(volume.getId());
// Check that the ExportGroup has not overridden the Vpool path parameters.
if (exportGroup.getPathParameters().containsKey(volume.getId().toString())) {
// Cannot do a Vpool path change because parameters have been set in Export Group
_log.info(String.format("No changes will be made to ExportGroup %s (%s) because it has explicit path parameters overiding the Vpool", exportGroup.getLabel(), exportGroup.getId()));
return;
}
ExportPathParams newParam = blockScheduler.calculateExportPathParamForVolumes(volumeURISet, 0, storage.getId(), exportGroup.getId());
_log.info("New path parameters requested: " + newParam.toString());
// Search through the Export Masks looking for any containing this Volume.
// We only process ViPR created Export Masks, others are ignored.
List<ExportMask> masks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, storage.getId());
for (ExportMask mask : masks) {
if (!mask.hasVolume(volume.getId())) {
continue;
}
// introduced until ViPR 1.1.
if (mask.getCreatedBySystem() == false || mask.getZoningMap() == null) {
_log.info(String.format("ExportMask %s not ViPR created, and will be ignored", mask.getMaskName()));
continue;
}
ExportPathParams maskParam = BlockStorageScheduler.calculateExportPathParamForExportMask(_dbClient, mask);
_log.info(String.format("Existing mask %s (%s) path parameters: %s", mask.getMaskName(), mask.getId(), maskParam.toString()));
if (newParam.getPathsPerInitiator() > maskParam.getPathsPerInitiator()) {
_log.info("Increase paths per initiator not supported");
// We want to increase paths per initiator
// Not supported yet, code will be added here.
} else if (newParam.getMaxPaths() > maskParam.getMaxPaths()) {
// We want to increase MaxPaths.
// Determine the currently unused Initiators.
List<URI> unusedInitiators = getUnusedInitiators(exportGroup, mask);
if (!unusedInitiators.isEmpty()) {
_log.info(String.format("Increasing max_paths from %d to %d", maskParam.getMaxPaths(), newParam.getMaxPaths()));
orchestrator.increaseMaxPaths(workflow, storage, exportGroup, mask, unusedInitiators, token);
}
} else if (newParam.getMaxPaths() < maskParam.getMaxPaths()) {
_log.info("Decrease max paths not supported");
// We want to lower MaxPaths. See if no other volume has a higher MaxPaths.
// Not supported yet, code will be added here.
}
}
}
use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class StoragePortsAssignerTest method testAllocationAssignment.
/**
* Test port allocation and assignment.
*
* @param contexts -- Array of PortAllocationContext structures, one for each Network.
* @param hostToNetToInitiators -- Map of host to map of network URI to Initiators
* @param maxPaths -- max_paths variable
* @param minPaths -- mininmum number of paths to provision
* @param pathsPerInitiator -- desired number of paths per initiator
* @param initiatorsPerPort -- maximum number of initiators in a host using same port
* @param arrayType -- String array type
* @param existingAssignments - previously assigned Initiator to StoragePort list mappings
*/
public static Map<Initiator, List<StoragePort>> testAllocationAssignment(PortAllocationContext[] contexts, Map<URI, Map<URI, List<Initiator>>> hostToNetToInitiators, int maxPaths, int minPaths, int pathsPerInitiator, int initiatorsPerPort, String arrayType, Map<Initiator, List<StoragePort>> existingAssignments) throws Exception {
Map<URI, List<Initiator>> net2InitiatorsMap = makeNet2InitiatorsMap(hostToNetToInitiators);
Map<Initiator, List<StoragePort>> assignments = new HashMap<Initiator, List<StoragePort>>();
if (pathsPerInitiator > maxPaths) {
return assignments;
}
ExportPathParams pathParams = new ExportPathParams(maxPaths, minPaths, pathsPerInitiator);
pathParams.setMaxInitiatorsPerPort(initiatorsPerPort);
try {
for (int i = 0; i < contexts.length; i++) {
contexts[i].reinitialize();
}
Map<URI, PortAllocationContext> net2ContextMap = new HashMap<URI, PortAllocationContext>();
for (int i = 0; i < contexts.length; i++) {
PortAllocationContext context = contexts[i];
net2ContextMap.put(context._initiatorNetwork.getId(), context);
}
// Map the existing (already allocated) StoragePorts to their Networks.
Map<URI, Set<StoragePort>> existingPortsMap = generateNetworkToStoragePortsMap(existingAssignments);
// Make a Map of Network to existing Initiators
Map<URI, Set<Initiator>> existingInitiatorsMap = generateNetworkToInitiatorsMap(existingAssignments);
// Compute the number of Ports needed for each Network
StoragePortsAssigner assigner = StoragePortsAssignerFactory.getAssigner(arrayType);
List<URI> networkOrder = new ArrayList<URI>();
Map<URI, Integer> net2PortsNeeded = assigner.getPortsNeededPerNetwork(net2InitiatorsMap, pathParams, existingPortsMap, existingInitiatorsMap, false, networkOrder);
// For each Network, allocate the ports required, and then assign the ports.
StoragePortsAllocator allocator = new StoragePortsAllocator();
Map<URI, List<StoragePort>> netToPortsAllocated = new HashMap<URI, List<StoragePort>>();
PortAllocationContext previousContext = null;
for (URI netURI : networkOrder) {
Integer portsNeeded = net2PortsNeeded.get(netURI);
if (portsNeeded == 0) {
System.out.println("No ports to be assigned for net: " + netURI);
continue;
}
// Get the context for this network.
PortAllocationContext context = net2ContextMap.get(netURI);
// Copy context from the previous allocation.
if (previousContext != null) {
context.copyPreviousNetworkContext(previousContext);
}
previousContext = context;
List<StoragePort> portsAllocated = allocator.allocatePortsForNetwork(portsNeeded, context, false, existingPortsMap.get(netURI), true, null);
netToPortsAllocated.put(netURI, portsAllocated);
}
// Now for each host, do the port assignment.
for (Map.Entry<URI, Map<URI, List<Initiator>>> entry : hostToNetToInitiators.entrySet()) {
System.out.println("Assign ports for host " + entry.getKey());
assigner.assignPortsToHost(assignments, entry.getValue(), netToPortsAllocated, pathParams, existingAssignments, entry.getKey(), null, null, null);
}
List<String> assignmentStrings = new ArrayList<String>();
for (Initiator initiator : assignments.keySet()) {
StringBuilder buf = new StringBuilder();
buf.append(initiator.getHostName() + "-" + initiator.getInitiatorPort() + " -> ");
List<StoragePort> ports = assignments.get(initiator);
if (ports == null) {
buf.append("<ignored>");
} else {
for (StoragePort port : assignments.get(initiator)) {
buf.append(port.getPortName() + " ");
}
}
buf.append(" ");
assignmentStrings.add(buf.toString());
}
Collections.sort(assignmentStrings);
for (String line : assignmentStrings) {
System.out.println(line);
}
verifyAssignments(assignments, arrayType, maxPaths, pathsPerInitiator, initiatorsPerPort, net2InitiatorsMap, existingAssignments);
} catch (PlacementException ex) {
System.out.println("PlacementException: " + ex.getMessage());
} catch (Exception ex) {
System.out.println("ERROR: " + ex.getMessage());
throw ex;
}
return assignments;
}
use of com.emc.storageos.db.client.model.ExportPathParams in project coprhd-controller by CoprHD.
the class VPlexDeviceController method checkForExistingStorageViews.
/**
* Checks for the existence of an existing Storage View on the VPLEX device based
* on the host's initiator ports. Returns a flag indicating whether or not a
* storage view was actually found on the device.
*
* @param client
* a VPLEX API client instance
* @param targetPortToPwwnMap
* cached storage port data from the VPLEX API
* @param vplexSystem
* a StorageSystem object representing the VPLEX system
* @param vplexCluster
* a String indicating which VPLEX question to look at
* @param inits
* the host initiators of the host in question
* @param exportGroup
* the ViPR export group
* @param varrayUri
* -- NOTE! The varrayUri may not be the same as the one in ExportGroup
* @param blockObjectMap
* the map of URIs to block volumes for export
* @param exportMasksToUpdateOnDevice
* collection of ExportMasks to update
* @param exportMasksToUpdateOnDeviceWithInitiators
* a map of ExportMasks to initiators
* @param exportMasksToUpdateOnDeviceWithStoragePorts
* a map of ExportMasks to storage ports
* @param opId
* the workflow step id used to find the workflow to store/load zoning map
* @return whether or not a storage view was actually found on the device
*/
private boolean checkForExistingStorageViews(VPlexApiClient client, Map<String, String> targetPortToPwwnMap, StorageSystem vplexSystem, String vplexCluster, List<Initiator> inits, ExportGroup exportGroup, URI varrayUri, Map<URI, Integer> blockObjectMap, List<ExportMask> exportMasksToUpdateOnDevice, Map<URI, List<Initiator>> exportMasksToUpdateOnDeviceWithInitiators, Map<URI, List<URI>> exportMasksToUpdateOnDeviceWithStoragePorts, Boolean[] doInitiatorRefresh, String opId) throws Exception {
boolean foundMatchingStorageView = false;
List<String> initiatorNames = getInitiatorNames(vplexSystem.getSerialNumber(), vplexCluster, client, inits.iterator(), doInitiatorRefresh);
long start = new Date().getTime();
List<VPlexStorageViewInfo> storageViewInfos = client.getStorageViewsContainingInitiators(vplexCluster, initiatorNames);
long elapsed = new Date().getTime() - start;
_log.info("TIMER: finding storage views containing initiators took {} ms", elapsed);
if (storageViewInfos.size() > 1) {
List<String> names = new ArrayList<String>();
for (VPlexStorageViewInfo info : storageViewInfos) {
names.add(info.getName());
}
// list of storage view names and initiators.
throw VPlexApiException.exceptions.tooManyExistingStorageViewsFound(Joiner.on(", ").join(names), Joiner.on(", ").join(initiatorNames));
} else if (storageViewInfos.size() == 1) {
_log.info("a matching storage view was found on the VPLEX device, so ViPR will import it.");
VPlexStorageViewInfo storageView = storageViewInfos.get(0);
foundMatchingStorageView = true;
// Grab the storage ports that have been allocated for this
// existing mask.
List<String> storagePorts = storageView.getPorts();
if (storagePorts != null && storagePorts.isEmpty()) {
_log.warn("No storage ports were found in the existing storage view {}, cannot reuse.", storageView.getName());
return false;
}
// convert storage view target ports like P0000000046E01E80-A0-FC02
// to port wwn format that ViPR better understands like 0x50001442601e8002
List<String> portWwns = new ArrayList<String>();
for (String storagePort : storagePorts) {
if (targetPortToPwwnMap.keySet().contains(storagePort)) {
portWwns.add(WwnUtils.convertWWN(targetPortToPwwnMap.get(storagePort), WwnUtils.FORMAT.COLON));
}
}
List<String> storagePortURIs = ExportUtils.storagePortNamesToURIs(_dbClient, portWwns);
_log.info("this storage view contains storage port URIs: " + storagePortURIs);
// storageview is from.
if (storagePortURIs == null || storagePortURIs.isEmpty()) {
_log.warn("No storage ports managed by ViPR were found in the existing storage view {}, cannot reuse", storageView.getName());
return false;
}
List<String> initiatorPorts = storageView.getInitiatorPwwns();
for (Initiator init : inits) {
String port = init.getInitiatorPort();
String normalizedName = Initiator.normalizePort(port);
_log.info(" looking at initiator " + normalizedName + " host " + VPlexUtil.getInitiatorHostResourceName(init));
if (initiatorPorts.contains(normalizedName)) {
_log.info(" found a matching initiator for " + normalizedName + " host " + VPlexUtil.getInitiatorHostResourceName(init) + " in storage view " + storageView.getName());
}
}
ExportMask exportMask = new ExportMask();
exportMask.setMaskName(storageView.getName());
exportMask.setStorageDevice(vplexSystem.getId());
exportMask.setId(URIUtil.createId(ExportMask.class));
exportMask.setCreatedBySystem(false);
exportMask.setNativeId(storageView.getPath());
List<Initiator> initsToAdd = new ArrayList<Initiator>();
for (Initiator init : inits) {
// add all the the initiators the user has requested to add
// to the exportMask initiators list
exportMask.addInitiator(init);
exportMask.addToUserCreatedInitiators(init);
String normalInit = Initiator.normalizePort(init.getInitiatorPort());
if (!storageView.getInitiatorPwwns().contains(normalInit)) {
initsToAdd.add(init);
}
}
exportMask.setStoragePorts(storagePortURIs);
// Update the tracking containers
exportMask.addToExistingVolumesIfAbsent(storageView.getWwnToHluMap());
exportMask.addToExistingInitiatorsIfAbsent(initiatorPorts);
// Create zoningMap for the matched initiators and storagePorts
_networkDeviceController.updateZoningMapForInitiators(exportGroup, exportMask, false);
_dbClient.createObject(exportMask);
if (!initsToAdd.isEmpty()) {
ExportPathParams pathParams = _blockScheduler.calculateExportPathParamForVolumes(blockObjectMap.keySet(), exportGroup.getNumPaths(), vplexSystem.getId(), exportGroup.getId());
// Try to assign new ports by passing in existingMap
Map<URI, List<URI>> assignments = _blockScheduler.assignStoragePorts(vplexSystem, exportGroup, initsToAdd, exportMask.getZoningMap(), pathParams, null, _networkDeviceController, varrayUri, opId);
// Consolidate the prezoned ports with the new assignments to get the total ports needed in the mask
if (assignments != null && !assignments.isEmpty()) {
// Update zoningMap if there are new assignments
exportMask = ExportUtils.updateZoningMap(_dbClient, exportMask, assignments, exportMasksToUpdateOnDeviceWithStoragePorts);
}
}
exportMasksToUpdateOnDevice.add(exportMask);
// add the initiators to the map for the exportMask that do not exist
// already in the storage view as to create steps to add those initiators
exportMasksToUpdateOnDeviceWithInitiators.put(exportMask.getId(), initsToAdd);
// Storage ports that needs to be added will be calculated in the
// add storage ports method from the zoning Map.
exportMasksToUpdateOnDeviceWithStoragePorts.put(exportMask.getId(), new ArrayList<URI>());
/*currently the Export Mask is added to the Export Group after all the hosts are being processed
Change made for COP-31815
This is so that ViPR can discover this ExportMask in the function:
VPlexDEviceController.getInitiatorExportMasks
*/
exportGroup.addExportMask(exportMask.getId());
_dbClient.updateObject(exportGroup);
}
return foundMatchingStorageView;
}
Aggregations