use of com.emc.storageos.volumecontroller.BlockStorageDevice in project coprhd-controller by CoprHD.
the class VplexCinderMaskingOrchestrator method createOrAddVolumesToExportMask.
@Override
public void createOrAddVolumesToExportMask(URI arrayURI, URI exportGroupURI, URI exportMaskURI, Map<URI, Integer> volumeMap, List<URI> initiatorURIs, TaskCompleter completer, String stepId) {
_log.debug("START - createOrAddVolumesToExportMask");
try {
WorkflowStepCompleter.stepExecuting(stepId);
StorageSystem array = _dbClient.queryObject(StorageSystem.class, arrayURI);
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
// If the exportMask isn't found, or has been deleted, fail, ask user to retry.
if (exportMask == null || exportMask.getInactive()) {
_log.info(String.format("ExportMask %s deleted or inactive, failing", exportMaskURI));
ServiceError svcerr = VPlexApiException.errors.createBackendExportMaskDeleted(exportMaskURI.toString(), arrayURI.toString());
WorkflowStepCompleter.stepFailed(stepId, svcerr);
return;
}
// Protect concurrent operations by locking {host, array} dupple.
// Lock will be released when work flow step completes.
List<String> lockKeys = ControllerLockingUtil.getHostStorageLockKeys(_dbClient, ExportGroupType.Host, StringSetUtil.stringSetToUriList(exportMask.getInitiators()), arrayURI);
getWorkflowService().acquireWorkflowStepLocks(stepId, lockKeys, LockTimeoutValue.get(LockType.VPLEX_BACKEND_EXPORT));
// Refresh the ExportMask
BlockStorageDevice device = _blockController.getDevice(array.getSystemType());
List<Initiator> initiators = new ArrayList<Initiator>();
for (String initiatorId : exportMask.getInitiators()) {
Initiator initiator = _dbClient.queryObject(Initiator.class, URI.create(initiatorId));
if (initiator != null) {
initiators.add(initiator);
}
}
if (!exportMask.hasAnyVolumes()) {
/*
* We are creating this ExportMask on the hardware! (Maybe not
* the first time though...)
*/
// Fetch the targets
List<URI> targets = new ArrayList<URI>();
for (String targetId : exportMask.getStoragePorts()) {
targets.add(URI.create(targetId));
}
if (volumeMap != null) {
for (URI volume : volumeMap.keySet()) {
exportMask.addVolume(volume, volumeMap.get(volume));
}
}
_dbClient.updateObject(exportMask);
_log.debug(String.format("Calling doExportCreate on the device %s", array.getId().toString()));
device.doExportCreate(array, exportMask, volumeMap, initiators, targets, completer);
} else {
_log.debug(String.format("Calling doExportAddVolumes on the device %s", array.getId().toString()));
device.doExportAddVolumes(array, exportMask, initiators, volumeMap, completer);
}
} catch (Exception ex) {
_log.error("Failed to create or add volumes to export mask for cinder: ", ex);
VPlexApiException vplexex = DeviceControllerExceptions.vplex.addStepsForCreateVolumesFailed(ex);
WorkflowStepCompleter.stepFailed(stepId, vplexex);
}
_log.debug("END - createOrAddVolumesToExportMask");
}
use of com.emc.storageos.volumecontroller.BlockStorageDevice in project coprhd-controller by CoprHD.
the class XIVMaskingOrchestrator method exportGroupAddInitiators.
@Override
public void exportGroupAddInitiators(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, String token) throws Exception {
BlockStorageDevice device = getDevice();
ExportOrchestrationTask taskCompleter = new ExportOrchestrationTask(exportGroupURI, token);
StorageSystem storage = _dbClient.queryObject(StorageSystem.class, storageURI);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
// Set up workflow steps.
Workflow workflow = _workflowService.getNewWorkflow(MaskingWorkflowEntryPoints.getInstance(), "exportGroupAddInitiators", true, token);
Map<URI, List<URI>> zoneMasksToInitiatorsURIs = new HashMap<URI, List<URI>>();
Map<URI, Map<URI, Integer>> zoneNewMasksToVolumeMap = new HashMap<URI, Map<URI, Integer>>();
List<URI> hostURIs = new ArrayList<URI>();
Map<String, URI> portNameToInitiatorURI = new HashMap<String, URI>();
List<String> portNames = new ArrayList<String>();
// Populate the port WWN/IQNs (portNames) and the
// mapping of the WWN/IQNs to Initiator URIs
processInitiators(exportGroup, initiatorURIs, portNames, portNameToInitiatorURI, hostURIs);
// Populate a map of volumes on the storage device
List<BlockObject> blockObjects = new ArrayList<BlockObject>();
Map<URI, Integer> volumeMap = new HashMap<URI, Integer>();
if (exportGroup.getVolumes() != null) {
for (Map.Entry<String, String> entry : exportGroup.getVolumes().entrySet()) {
URI boURI = URI.create(entry.getKey());
Integer hlu = Integer.valueOf(entry.getValue());
BlockObject bo = BlockObject.fetch(_dbClient, boURI);
if (bo.getStorageController().equals(storageURI)) {
volumeMap.put(boURI, hlu);
blockObjects.add(bo);
}
}
}
// We always want to have the full list of initiators for the hosts involved in
// this export. This will allow the export operation to always find any
// existing exports for a given host.
queryHostInitiatorsAndAddToList(portNames, portNameToInitiatorURI, initiatorURIs, hostURIs);
boolean anyOperationsToDo = false;
Map<String, Set<URI>> matchingExportMaskURIs = device.findExportMasks(storage, portNames, false);
// Need to maintain separate Export mask for Cluster and Host.
// So remove off the Export mask not matching to the Export Group.
filterExportMaskForGroup(exportGroup, matchingExportMaskURIs);
if (!matchingExportMaskURIs.isEmpty()) {
// There were some exports out there that already have some or all of the
// initiators that we are attempting to add. We need to only add
// volumes to those existing exports.
List<URI> initiatorURIsCopy = new ArrayList<URI>();
initiatorURIsCopy.addAll(initiatorURIs);
// This loop will determine a list of volumes to update per export mask
Map<URI, Map<URI, Integer>> existingMasksToUpdateWithNewVolumes = new HashMap<URI, Map<URI, Integer>>();
Map<URI, Set<Initiator>> existingMasksToUpdateWithNewInitiators = new HashMap<URI, Set<Initiator>>();
for (Map.Entry<String, Set<URI>> entry : matchingExportMaskURIs.entrySet()) {
URI initiatorURI = portNameToInitiatorURI.get(entry.getKey());
Initiator initiator = _dbClient.queryObject(Initiator.class, initiatorURI);
initiatorURIsCopy.remove(initiatorURI);
// Get a list of the ExportMasks that were matched to the initiator
List<URI> exportMaskURIs = new ArrayList<URI>();
exportMaskURIs.addAll(entry.getValue());
List<ExportMask> masks = _dbClient.queryObject(ExportMask.class, exportMaskURIs);
_log.info(String.format("initiator %s is in these masks {%s}", initiator.getInitiatorPort(), Joiner.on(',').join(exportMaskURIs)));
for (ExportMask mask : masks) {
// 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;
}
_log.info(String.format("mask %s has initiator %s", mask.getMaskName(), initiator.getInitiatorPort()));
if (!mask.getInactive() && mask.getStorageDevice().equals(storageURI)) {
// already in the masks to the placement list
for (BlockObject blockObject : blockObjects) {
if (!mask.hasExistingVolume(blockObject.getWWN()) && !mask.hasUserAddedVolume(blockObject.getWWN())) {
Map<URI, Integer> newVolumesMap = existingMasksToUpdateWithNewVolumes.get(mask.getId());
if (newVolumesMap == null) {
newVolumesMap = new HashMap<URI, Integer>();
existingMasksToUpdateWithNewVolumes.put(mask.getId(), newVolumesMap);
}
newVolumesMap.put(blockObject.getId(), volumeMap.get(blockObject.getId()));
}
}
if (mask.getCreatedBySystem()) {
// in our export group, because we would simply add to them.
if (mask.getInitiators() != null) {
for (String existingMaskInitiatorStr : mask.getInitiators()) {
// Now look at it from a different angle. Which one of our export group initiators
// are NOT in the current mask? And if so, if it belongs to the same host as an existing one,
// we should add it to this mask.
Iterator<URI> initiatorIter = initiatorURIsCopy.iterator();
while (initiatorIter.hasNext()) {
Initiator initiatorCopy = _dbClient.queryObject(Initiator.class, initiatorIter.next());
if (!mask.hasInitiator(initiatorCopy.getId().toString())) {
Initiator existingMaskInitiator = _dbClient.queryObject(Initiator.class, URI.create(existingMaskInitiatorStr));
if (initiatorCopy.getHost().equals(existingMaskInitiator.getHost())) {
// Add to the list of initiators we need to add to this mask
Set<Initiator> existingMaskInitiators = existingMasksToUpdateWithNewInitiators.get(mask.getId());
if (existingMaskInitiators == null) {
existingMaskInitiators = new HashSet<Initiator>();
existingMasksToUpdateWithNewInitiators.put(mask.getId(), existingMaskInitiators);
}
if (!existingMaskInitiators.contains(initiatorCopy)) {
existingMaskInitiators.add(initiatorCopy);
}
// remove this from the list of initiators we'll make a new mask
initiatorIter.remove();
// from
}
}
}
}
}
} else {
// Insert this initiator into the mask's list of initiators managed by the system.
// This will get persisted below.
mask.addInitiator(initiator);
}
}
// Update the list of volumes and initiators for the mask
Map<URI, Integer> volumeMapForExistingMask = existingMasksToUpdateWithNewVolumes.get(mask.getId());
if (volumeMapForExistingMask != null && !volumeMapForExistingMask.isEmpty()) {
mask.addVolumes(volumeMapForExistingMask);
}
Set<Initiator> initiatorSetForExistingMask = existingMasksToUpdateWithNewInitiators.get(mask.getId());
if (initiatorSetForExistingMask != null && initiatorSetForExistingMask.isEmpty()) {
mask.addInitiators(initiatorSetForExistingMask);
}
updateZoningMap(exportGroup, mask);
_dbClient.updateAndReindexObject(mask);
// TODO: All export group modifications should be moved to completers
exportGroup.addExportMask(mask.getId());
_dbClient.updateAndReindexObject(exportGroup);
}
}
// The initiatorURIsCopy was used in the foreach initiator loop to see
// which initiators already exist in a mask. If it is non-empty,
// then it means there are initiators that are new,
// so let's add them to the main tracker
Map<URI, List<URI>> hostInitiatorMap = new HashMap<URI, List<URI>>();
if (!initiatorURIsCopy.isEmpty()) {
for (URI newExportMaskInitiator : initiatorURIsCopy) {
Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
List<URI> initiatorSet = hostInitiatorMap.get(initiator.getHost());
if (initiatorSet == null) {
initiatorSet = new ArrayList<URI>();
hostInitiatorMap.put(initiator.getHost(), initiatorSet);
}
initiatorSet.add(initiator.getId());
_log.info(String.format("host = %s, " + "initiators to add: %d, " + "existingMasksToUpdateWithNewVolumes.size = %d", initiator.getHost(), hostInitiatorMap.get(initiator.getHost()).size(), existingMasksToUpdateWithNewVolumes.size()));
}
}
for (URI host : hostInitiatorMap.keySet()) {
// Create two steps, one for Zoning, one for the ExportGroup actions.
// This step is for zoning. It is not specific to a single NetworkSystem,
// as it will look at all the initiators and targets and compute the
// zones required (which might be on multiple NetworkSystems.)
GenExportMaskCreateWorkflowResult result = generateExportMaskCreateWorkflow(workflow, EXPORT_GROUP_ZONING_TASK, storage, exportGroup, hostInitiatorMap.get(host), volumeMap, token);
zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
anyOperationsToDo = true;
}
_log.info(String.format("existingMasksToUpdateWithNewVolumes.size = %d", existingMasksToUpdateWithNewVolumes.size()));
String attachGroupSnapshot = checkForSnapshotsToCopyToTarget(workflow, storage, null, volumeMap, existingMasksToUpdateWithNewVolumes.values());
// At this point we have a mapping of all the masks that we need to update with new volumes
// stepMap [URI, String] => [Export Mask URI, StepId of previous task i.e. Add volumes work flow.]
Map<URI, String> stepMap = new HashMap<URI, String>();
for (Map.Entry<URI, Map<URI, Integer>> entry : existingMasksToUpdateWithNewVolumes.entrySet()) {
ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
Map<URI, Integer> volumesToAdd = entry.getValue();
_log.info(String.format("adding these volumes %s to mask %s", Joiner.on(",").join(volumesToAdd.keySet()), mask.getMaskName()));
List<URI> volumeURIs = new ArrayList<URI>();
volumeURIs.addAll(volumesToAdd.keySet());
stepMap.put(entry.getKey(), generateDeviceSpecificAddVolumeWorkFlow(workflow, attachGroupSnapshot, storage, exportGroup, mask, volumesToAdd, volumeURIs, null));
anyOperationsToDo = true;
}
// At this point we have a mapping of all the masks that we need to update with new initiators
for (Entry<URI, Set<Initiator>> entry : existingMasksToUpdateWithNewInitiators.entrySet()) {
ExportMask mask = _dbClient.queryObject(ExportMask.class, entry.getKey());
Set<Initiator> initiatorsToAdd = entry.getValue();
List<URI> initiatorsURIs = new ArrayList<URI>();
for (Initiator initiator : initiatorsToAdd) {
initiatorsURIs.add(initiator.getId());
}
_log.info(String.format("adding these initiators %s to mask %s", Joiner.on(",").join(initiatorsURIs), mask.getMaskName()));
String previousStep = attachGroupSnapshot;
if (stepMap.get(entry.getKey()) != null) {
previousStep = stepMap.get(entry.getKey());
}
Map<URI, List<URI>> maskToInitiatorsMap = new HashMap<URI, List<URI>>();
maskToInitiatorsMap.put(mask.getId(), initiatorURIs);
generateDeviceSpecificAddInitiatorWorkFlow(workflow, previousStep, storage, exportGroup, mask, Arrays.asList(), initiatorsURIs, maskToInitiatorsMap, token);
anyOperationsToDo = true;
}
} else {
// None of the initiators that we're trying to add exist on the
// array in some export. We need to find the ExportMask that was created by
// the system and add the new initiator(s) to it.
boolean foundASystemCreatedMask = false;
Map<String, List<URI>> hostInitiatorMap = new HashMap<String, List<URI>>();
if (!initiatorURIs.isEmpty()) {
for (URI newExportMaskInitiator : initiatorURIs) {
Initiator initiator = _dbClient.queryObject(Initiator.class, newExportMaskInitiator);
if (initiator != null) {
String hostURIString = initiator.getHost().toString();
List<URI> initiatorSet = hostInitiatorMap.get(hostURIString);
if (initiatorSet == null) {
hostInitiatorMap.put(initiator.getHost().toString(), new ArrayList<URI>());
initiatorSet = hostInitiatorMap.get(hostURIString);
}
initiatorSet.add(initiator.getId());
_log.info(String.format("host = %s, " + "initiators to add: %d, ", initiator.getHost(), hostInitiatorMap.get(hostURIString).size()));
}
}
}
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
if (!exportMasks.isEmpty()) {
_log.info("There are export masks for this group. Adding initiators.");
// the storage system that were created by Bourne and are still active.
for (ExportMask exportMask : exportMasks) {
if (exportMask != null && !exportMask.getInactive() && exportMask.getStorageDevice().equals(storageURI) && exportMask.getCreatedBySystem()) {
List<URI> newInitiators = hostInitiatorMap.get(exportMask.getResource());
if (newInitiators != null && !newInitiators.isEmpty()) {
zoneMasksToInitiatorsURIs.put(exportMask.getId(), newInitiators);
generateDeviceSpecificExportMaskAddInitiatorsWorkflow(workflow, EXPORT_GROUP_ZONING_TASK, storage, exportGroup, exportMask, null, newInitiators, token);
foundASystemCreatedMask = true;
anyOperationsToDo = true;
}
}
}
}
if (!foundASystemCreatedMask) {
_log.info("There are no masks for this export. Need to create anew.");
for (String host : hostInitiatorMap.keySet()) {
// Zoning is done for the new masks identified i.e. zoneNewMasksToVolumeMap.
GenExportMaskCreateWorkflowResult result = generateDeviceSpecificExportMaskCreateWorkFlow(workflow, EXPORT_GROUP_ZONING_TASK, storage, exportGroup, hostInitiatorMap.get(host), volumeMap, token);
zoneNewMasksToVolumeMap.put(result.getMaskURI(), volumeMap);
anyOperationsToDo = true;
}
}
}
if (anyOperationsToDo) {
if (!zoneNewMasksToVolumeMap.isEmpty()) {
List<URI> exportMaskList = new ArrayList<URI>();
exportMaskList.addAll(zoneNewMasksToVolumeMap.keySet());
Map<URI, Integer> overallVolumeMap = new HashMap<URI, Integer>();
for (Map<URI, Integer> oneVolumeMap : zoneNewMasksToVolumeMap.values()) {
overallVolumeMap.putAll(oneVolumeMap);
}
generateDeviceSpecificZoningCreateWorkflow(workflow, null, exportGroup, exportMaskList, overallVolumeMap);
}
if (!zoneMasksToInitiatorsURIs.isEmpty()) {
generateDeviceSpecificZoningAddInitiatorsWorkflow(workflow, null, exportGroup, zoneMasksToInitiatorsURIs);
}
String successMessage = String.format("Successfully exported to initiators on StorageArray %s", storage.getLabel());
workflow.executePlan(taskCompleter, successMessage);
} else {
taskCompleter.ready(_dbClient);
}
}
use of com.emc.storageos.volumecontroller.BlockStorageDevice in project coprhd-controller by CoprHD.
the class XIVMaskingOrchestrator method updateVolumeHLU.
/**
* Finds Next available HLU for the Host/Hosts (Cluster) and updates the
* volume Map to the next HLU reference if user has chosen system to decide on HLU number
*
* @param system
* Storage Array on which export operation is executed
* @param initiatorURIs
* List of Host initiators
* @param volumeMap
* Volume and HLU mapping.
*/
private void updateVolumeHLU(StorageSystem system, Collection<URI> initiatorURIs, Map<URI, Integer> volumeMap) {
boolean findHLU = false;
// Loop through the volume entries to see if there is a request for Auto HLU.
for (Entry<URI, Integer> volumeMapEntry : volumeMap.entrySet()) {
if (volumeMapEntry.getValue() == -1) {
findHLU = true;
break;
}
}
// If auto HLU then start finding out the next HLU
if (findHLU) {
BlockStorageDevice device = getDevice();
Map<URI, List<Integer>> initiatorToHLUsMap = device.doFindHostHLUs(system, initiatorURIs);
Iterator<Entry<URI, List<Integer>>> initiatorToHLUsItr = initiatorToHLUsMap.entrySet().iterator();
Set<Integer> usedHLUs = new HashSet<Integer>();
// Get the list of available HLU on array and then add that to the Set of common used HLUs
while (initiatorToHLUsItr.hasNext()) {
Entry<URI, List<Integer>> initiatorHLUs = initiatorToHLUsItr.next();
usedHLUs.addAll(initiatorHLUs.getValue());
}
// Update Volume Map to the next available HLU.
int nextHLU = 1;
for (Entry<URI, Integer> volumeMapEntry : volumeMap.entrySet()) {
while (usedHLUs.contains(nextHLU)) {
nextHLU++;
}
// Max allowed HLU number for XIV is 511. Restricting it to that number.
if (nextHLU < MAX_HLU) {
_log.debug("Updating HLU of Volume {} from {} to " + nextHLU, volumeMapEntry.getKey(), volumeMapEntry.getValue());
volumeMap.put(volumeMapEntry.getKey(), nextHLU);
nextHLU++;
} else {
DeviceControllerException.errors.volumeReachedMaxExports(volumeMapEntry.getKey().toString(), nextHLU, new Throwable());
}
}
}
}
use of com.emc.storageos.volumecontroller.BlockStorageDevice in project coprhd-controller by CoprHD.
the class CinderMaskingOrchestrator method getDevice.
@Override
public BlockStorageDevice getDevice() {
BlockStorageDevice device = CINDER_BLOCK_DEVICE.get();
synchronized (CINDER_BLOCK_DEVICE) {
if (device == null) {
device = (BlockStorageDevice) ControllerServiceImpl.getBean(CINDER_STORAGE_DEVICE);
CINDER_BLOCK_DEVICE.compareAndSet(null, device);
}
}
return device;
}
Aggregations