use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class VPlexDeviceController method storageViewAddStoragePorts.
/**
* Workflow Step to add storage port(s) to Storage View.
* Note arguments (except stepId) must match storageViewAddStoragePortsMethod above.
*
* @param vplexURI
* -- URI of VPlex StorageSystem
* @param exportURI
* -- ExportGroup URI
* @param maskURI
* -- ExportMask URI.
* @param targetURIs
* -- list of targets URIs (VPLEX FE ports) to be added.
* If not null, the targets (VPlex front end ports) indicated by the targetURIs will be added
* to the Storage View making sure they do belong to zoningMap storagePorts.
* If null, then ports are calculated from the zoningMap.
* @param completer the ExportMaskAddInitiatorCompleter
* @param stepId
* -- Workflow step id.
* @throws WorkflowException
*/
public void storageViewAddStoragePorts(URI vplexURI, URI exportURI, URI maskURI, List<URI> targetURIs, ExportMaskAddInitiatorCompleter completer, String stepId) throws DeviceControllerException {
try {
WorkflowStepCompleter.stepExecuting(stepId);
ExportOperationContext context = new VplexExportOperationContext();
// Prime the context object
completer.updateWorkflowStepContext(context);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplexURI);
for (ExportMask exportMask : exportMasks) {
// If a specific ExportMask is to be processed, ignore any others.
if (maskURI != null && !exportMask.getId().equals(maskURI)) {
continue;
}
ArrayList<URI> filteredTargetURIs = new ArrayList<URI>();
// Filter or get targets from the zoning map
if (exportMask.getZoningMap() != null) {
Set<String> zoningMapTargets = BlockStorageScheduler.getTargetIdsFromAssignments(exportMask.getZoningMap());
List<URI> zoningMapTargetURIs = StringSetUtil.stringSetToUriList(zoningMapTargets);
if (targetURIs == null || targetURIs.isEmpty()) {
// Add all storage ports from the zoning map
if (zoningMapTargetURIs != null && !zoningMapTargetURIs.isEmpty()) {
filteredTargetURIs.addAll(zoningMapTargetURIs);
}
} else {
// Log any ports not in the zoning map.
for (URI targetURI : targetURIs) {
filteredTargetURIs.add(targetURI);
if (zoningMapTargetURIs.contains(targetURI)) {
_log.info(String.format("Target %s not in zoning map", targetURI));
}
}
}
}
// Add new targets if specified
if (filteredTargetURIs != null && filteredTargetURIs.isEmpty() == false) {
List<PortInfo> targetPortInfos = new ArrayList<PortInfo>();
List<URI> targetsAddedToStorageView = new ArrayList<URI>();
for (URI target : filteredTargetURIs) {
// Do not try to add a port twice.
if (exportMask.getStoragePorts().contains(target.toString())) {
continue;
}
// Build the PortInfo structure for the port to be added
StoragePort port = getDataObject(StoragePort.class, target, _dbClient);
PortInfo pi = new PortInfo(port.getPortNetworkId().toUpperCase().replaceAll(":", ""), null, port.getPortName(), null);
targetPortInfos.add(pi);
targetsAddedToStorageView.add(target);
}
if (!targetPortInfos.isEmpty()) {
// Add the targets on the VPLEX
client.addTargetsToStorageView(exportMask.getMaskName(), targetPortInfos);
ExportOperationContext.insertContextOperation(completer, VplexExportOperationContext.OPERATION_ADD_TARGETS_TO_STORAGE_VIEW, targetsAddedToStorageView);
// Add the targets to the database.
for (URI target : targetsAddedToStorageView) {
exportMask.addTarget(target);
}
_dbClient.updateObject(exportMask);
}
}
}
InvokeTestFailure.internalOnlyInvokeTestFailure(InvokeTestFailure.ARTIFICIAL_FAILURE_083);
completer.ready(_dbClient);
} catch (VPlexApiException vae) {
_log.error("VPlexApiException adding storagePorts to Storage View: " + vae.getMessage(), vae);
failStep(completer, stepId, vae);
} catch (Exception ex) {
_log.error("Exception adding storagePorts to Storage View: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.ADD_STORAGE_VIEW_STORAGEPORTS.getName();
ServiceError serviceError = VPlexApiException.errors.storageViewAddStoragePortFailed(opName, ex);
failStep(completer, stepId, serviceError);
}
}
use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class VPlexDeviceController method createExportGroup.
/**
* Create a new ExportGroup based on the old ExportGroup, then add the volume to the new exportGroup
*
* @param oldExportGroup
* The old exportGroup that will be based on for the new exportGroup.
* @param volume
* The volume that will be added to the new exportGroup
* @param lun
* The lun number for the volume.
*/
private void createExportGroup(ExportGroup oldExportGroup, Volume volume, Integer lun) {
ExportGroup exportGroup = new ExportGroup();
exportGroup.setLabel(oldExportGroup.getLabel());
exportGroup.setType(oldExportGroup.getType());
exportGroup.setId(URIUtil.createId(ExportGroup.class));
exportGroup.setProject(oldExportGroup.getProject());
exportGroup.setVirtualArray(volume.getVirtualArray());
exportGroup.setTenant(oldExportGroup.getTenant());
exportGroup.setGeneratedName(oldExportGroup.getGeneratedName());
exportGroup.addVolume(volume.getId(), lun);
exportGroup.addInitiators(StringSetUtil.stringSetToUriList(oldExportGroup.getInitiators()));
exportGroup.addHosts(StringSetUtil.stringSetToUriList(oldExportGroup.getHosts()));
exportGroup.setClusters(oldExportGroup.getClusters());
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, oldExportGroup);
if (!exportMasks.isEmpty()) {
for (ExportMask exportMask : exportMasks) {
exportGroup.addExportMask(exportMask.getId());
}
}
exportGroup.setNumPaths(oldExportGroup.getNumPaths());
exportGroup.setZoneAllInitiators(oldExportGroup.getZoneAllInitiators());
_dbClient.createObject(exportGroup);
}
use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class VPlexDeviceController method getExportGroupsForVolume.
/**
* Return a list of ExportGroups for a BlockObject on an array.
* This is used by deleteVolumes to find the ExportGroup(s) on the underlying array.
*
* @param volume
* BlockObject - Volume
* @return List<ExportGroup>
* @throws Exception
*/
private List<ExportGroup> getExportGroupsForVolume(BlockObject volume) throws Exception {
URIQueryResultList exportGroupURIs = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory.getBlockObjectExportGroupConstraint(volume.getId()), exportGroupURIs);
List<ExportGroup> exportGroups = new ArrayList<ExportGroup>();
for (URI egURI : exportGroupURIs) {
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, egURI);
if (exportGroup == null || exportGroup.getInactive() == true) {
continue;
}
exportGroups.add(exportGroup);
}
return exportGroups;
}
use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class VPlexDeviceController method exportGroupCreate.
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportGroupCreate(java.net.URI, java.net.URI,
* java.util.Map,
* java.util.List, java.lang.String)
*/
@Override
public void exportGroupCreate(URI vplex, URI export, List<URI> initiators, Map<URI, Integer> volumeMap, String opId) throws ControllerException {
ExportCreateCompleter completer = null;
try {
WorkflowStepCompleter.stepExecuting(opId);
completer = new ExportCreateCompleter(export, volumeMap, opId);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, export);
StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, vplex);
_log.info(String.format("VPLEX exportGroupCreate %s vplex %s", exportGroup.getLabel(), vplexSystem.getNativeGuid()));
URI srcVarray = exportGroup.getVirtualArray();
boolean isRecoverPointExport = ExportUtils.checkIfInitiatorsForRP(_dbClient, exportGroup.getInitiators());
initiators = VPlexUtil.filterInitiatorsForVplex(_dbClient, initiators);
if (initiators == null || initiators.isEmpty()) {
_log.info("ExportGroup created with no initiators connected to VPLEX supplied, no need to orchestrate VPLEX further.");
completer.ready(_dbClient);
return;
}
// Determine whether this export will be done across both VPLEX clusters, or just one.
// If both, we will set up some data structures to handle both exports.
// Distributed volumes can be exported to both clusters.
// Local volumes may be from either the src or HA varray, and will be exported
// the the appropriate hosts.
// Hosts may have connectivity to one varray (local or HA), or both.
// Only one HA varray is allowed (technically one Varray not matching the ExportGroup).
// It is persisted in the exportGroup.altVirtualArray map with the Vplex System ID as key.
// Get a mapping of Virtual Array to the Volumes visible in each Virtual Array.
Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplex, exportGroup);
// Extract the src volumes into their own set.
Set<URI> srcVolumes = varrayToVolumes.get(srcVarray);
// Remove the srcVolumes from the varraysToVolumesMap
varrayToVolumes.remove(srcVarray);
URI haVarray = null;
// And we're not exporting to recover point Initiators
if (!varrayToVolumes.isEmpty() && !isRecoverPointExport) {
// Make sure there is only one "HA" varray and return the HA virtual array.
haVarray = VPlexUtil.pickHAVarray(varrayToVolumes);
}
// Partition the initiators by Varray.
// Some initiators may be connected to both virtual arrays, others connected to
// only one of the virtual arrays or the other.
List<URI> varrayURIs = new ArrayList<URI>();
varrayURIs.add(srcVarray);
if (haVarray != null) {
varrayURIs.add(haVarray);
}
Map<URI, List<URI>> varrayToInitiators = VPlexUtil.partitionInitiatorsByVarray(_dbClient, initiators, varrayURIs, vplexSystem);
if (varrayToInitiators.isEmpty()) {
throw VPlexApiException.exceptions.exportCreateNoinitiatorsHaveCorrectConnectivity(initiators.toString(), varrayURIs.toString());
}
// Validate that the export can be successful:
// If both src and ha volumes are present, all hosts must be connected.
// Otherwise, at least one host must be connected.
URI source = (srcVolumes == null || srcVolumes.isEmpty()) ? null : srcVarray;
VPlexUtil.validateVPlexClusterExport(_dbClient, source, haVarray, initiators, varrayToInitiators);
Workflow workflow = _workflowService.getNewWorkflow(this, "exportGroupCreate", true, opId);
// HA side initiators, and volumes accessible from the HA side.
if (haVarray != null && varrayToInitiators.get(haVarray) != null) {
exportGroup.putAltVirtualArray(vplex.toString(), haVarray.toString());
_dbClient.updateObject(exportGroup);
}
findAndUpdateFreeHLUsForClusterExport(vplexSystem, exportGroup, initiators, volumeMap);
// Do the source side export if there are src side volumes and initiators.
if (srcVolumes != null && varrayToInitiators.get(srcVarray) != null) {
assembleExportMasksWorkflow(vplex, export, srcVarray, varrayToInitiators.get(srcVarray), ExportMaskUtils.filterVolumeMap(volumeMap, srcVolumes), true, workflow, null, opId);
}
// HA side initiators, and volumes accessible from the HA side.
if (haVarray != null && varrayToInitiators.get(haVarray) != null) {
assembleExportMasksWorkflow(vplex, export, haVarray, varrayToInitiators.get(haVarray), ExportMaskUtils.filterVolumeMap(volumeMap, varrayToVolumes.get(haVarray)), true, workflow, null, opId);
}
// Initiate the workflow.
StringBuilder buf = new StringBuilder();
buf.append(String.format("VPLEX create ExportGroup %s for initiators %s completed successfully", export, initiators.toString()));
workflow.executePlan(completer, buf.toString());
_log.info("VPLEX exportGroupCreate workflow scheduled");
} catch (VPlexApiException vae) {
_log.error("Exception creating Export Group: " + vae.getMessage(), vae);
failStep(completer, opId, vae);
} catch (Exception ex) {
_log.error("Exception creating Export Group: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.CREATE_EXPORT_GROUP.getName();
ServiceError serviceError = VPlexApiException.errors.exportGroupCreateFailed(opName, ex);
failStep(completer, opId, serviceError);
}
}
use of com.emc.storageos.db.client.model.ExportGroup in project coprhd-controller by CoprHD.
the class VPlexDeviceController method exportGroupAddVolumes.
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportAddVolume(java.net.URI, java.net.URI,
* java.net.URI,
* java.lang.Integer, java.lang.String)
*/
@Override
public void exportGroupAddVolumes(URI vplexURI, URI exportURI, Map<URI, Integer> volumeMap, String opId) throws ControllerException {
String volListStr = "";
ExportAddVolumeCompleter completer = null;
try {
WorkflowStepCompleter.stepExecuting(opId);
completer = new ExportAddVolumeCompleter(exportURI, volumeMap, opId);
volListStr = Joiner.on(',').join(volumeMap.keySet());
Workflow workflow = _workflowService.getNewWorkflow(this, "exportGroupAddVolumes", true, opId);
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportURI);
StorageSystem vplexSystem = _dbClient.queryObject(StorageSystem.class, vplexURI);
URI srcVarray = exportGroup.getVirtualArray();
boolean isRecoverPointExport = ExportUtils.checkIfInitiatorsForRP(_dbClient, exportGroup.getInitiators());
if (!exportGroup.hasInitiators()) {
// VPLEX API restricts adding volumes before initiators
VPlexApiException.exceptions.cannotAddVolumesToExportGroupWithoutInitiators(exportGroup.forDisplay());
}
// Determine whether this export will be done across both VPLEX clusters,
// or just the src or ha varray.
// We get a map of varray to the volumes that can be exported in each varray.
Map<URI, Set<URI>> varrayToVolumes = VPlexUtil.mapBlockObjectsToVarrays(_dbClient, volumeMap.keySet(), vplexURI, exportGroup);
// Put the srcVolumes in their own set, and remove the src varray from the varrayToVolumes map.
Set<URI> srcVolumes = varrayToVolumes.get(srcVarray);
varrayToVolumes.remove(srcVarray);
URI haVarray = null;
// and we're not exporting to recover point initiators
if (!varrayToVolumes.isEmpty() && !isRecoverPointExport) {
if (exportGroup.hasAltVirtualArray(vplexURI.toString())) {
// If we've already chosen an haVarray, go with with the choice
haVarray = URI.create(exportGroup.getAltVirtualArrays().get(vplexURI.toString()));
} else {
// Otherwise we will make sure there is only one HA varray and persist it.
haVarray = VPlexUtil.pickHAVarray(varrayToVolumes);
}
}
// Partition the initiators by varray into varrayToInitiators map.
List<URI> varrayURIs = new ArrayList<URI>();
varrayURIs.add(exportGroup.getVirtualArray());
if (haVarray != null) {
varrayURIs.add(haVarray);
}
List<URI> exportGroupInitiatorList = StringSetUtil.stringSetToUriList(exportGroup.getInitiators());
Map<URI, List<URI>> varrayToInitiators = VPlexUtil.partitionInitiatorsByVarray(_dbClient, exportGroupInitiatorList, varrayURIs, vplexSystem);
if (varrayToInitiators.isEmpty()) {
throw VPlexApiException.exceptions.exportCreateNoinitiatorsHaveCorrectConnectivity(exportGroup.getInitiators().toString(), varrayURIs.toString());
}
findAndUpdateFreeHLUsForClusterExport(vplexSystem, exportGroup, exportGroupInitiatorList, volumeMap);
// Check if Zoning needs to be checked from system config
// call the doZoneExportMasksCreate to check/create/remove zones with the flag
String addZoneWhileAddingVolume = customConfigHandler.getComputedCustomConfigValue(CustomConfigConstants.ZONE_ADD_VOLUME, CustomConfigConstants.GLOBAL_KEY, null);
// Default behavior is we allow zoning checks against the Network System
Boolean addZoneOnDeviceOperation = true;
_log.info("zoneExportAddVolumes checking for custom config value {} to skip zoning checks : (Default) : {}", addZoneWhileAddingVolume, addZoneOnDeviceOperation);
if (addZoneWhileAddingVolume != null) {
addZoneOnDeviceOperation = Boolean.valueOf(addZoneWhileAddingVolume);
_log.info("Boolean convereted of : {} : returned by Config handler as : {} ", addZoneWhileAddingVolume, addZoneOnDeviceOperation);
} else {
_log.info("Config handler returned null for value so going by default value {}", addZoneOnDeviceOperation);
}
_log.info("zoneExportAddVolumes checking for custom config value {} to skip zoning checks : (Custom Config) : {}", addZoneWhileAddingVolume, addZoneOnDeviceOperation);
// Add all the volumes to the SRC varray if there are src side volumes and
// initiators that have connectivity to the source side.
String srcExportStepId = null;
if (varrayToInitiators.get(srcVarray) != null && srcVolumes != null) {
srcExportStepId = assembleExportMasksWorkflow(vplexURI, exportURI, srcVarray, varrayToInitiators.get(srcVarray), ExportMaskUtils.filterVolumeMap(volumeMap, srcVolumes), addZoneOnDeviceOperation, workflow, null, opId);
}
// and there are volumes to be added to the ha varray, do so.
if (haVarray != null && varrayToInitiators.get(haVarray) != null && varrayToVolumes.get(haVarray) != null) {
exportGroup.putAltVirtualArray(vplexURI.toString(), haVarray.toString());
_dbClient.updateObject(exportGroup);
assembleExportMasksWorkflow(vplexURI, exportURI, haVarray, varrayToInitiators.get(haVarray), ExportMaskUtils.filterVolumeMap(volumeMap, varrayToVolumes.get(haVarray)), addZoneOnDeviceOperation, workflow, srcExportStepId, opId);
}
// Initiate the workflow.
String message = String.format("VPLEX ExportGroup Add Volumes (%s) for export %s completed successfully", volListStr, exportURI);
workflow.executePlan(completer, message);
} catch (VPlexApiException vae) {
String message = String.format("Failed to add Volumes %s to ExportGroup %s", volListStr, exportURI);
_log.error(message, vae);
failStep(completer, opId, vae);
} catch (Exception ex) {
String message = String.format("Failed to add Volumes %s to ExportGroup %s", volListStr, exportURI);
_log.error(message, ex);
String opName = ResourceOperationTypeEnum.ADD_EXPORT_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.exportGroupAddVolumesFailed(volListStr, exportURI.toString(), opName, ex);
failStep(completer, opId, serviceError);
}
}
Aggregations