use of com.emc.storageos.networkcontroller.impl.NetworkZoningParam in project coprhd-controller by CoprHD.
the class AbstractDefaultMaskingOrchestrator method generateZoningDeleteWorkflow.
protected String generateZoningDeleteWorkflow(Workflow workflow, String previousStep, ExportGroup exportGroup, List<ExportMask> exportMasks) throws WorkflowException {
URI exportGroupURI = exportGroup.getId();
List<URI> exportMaskURIs = new ArrayList<URI>();
Set<URI> volumeURIs = new HashSet<>();
for (ExportMask mask : exportMasks) {
exportMaskURIs.add(mask.getId());
volumeURIs.addAll(ExportMaskUtils.getVolumeURIs(mask));
}
List<NetworkZoningParam> zoningParams = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportGroupURI, exportMaskURIs, _dbClient);
String zoningStep = workflow.createStepId();
Workflow.Method zoningExecuteMethod = _networkDeviceController.zoneExportMasksDeleteMethod(zoningParams, volumeURIs);
zoningStep = workflow.createStep((previousStep == null ? EXPORT_GROUP_ZONING_TASK : null), "Zoning subtask for export-group: " + exportGroupURI, previousStep, NullColumnValueGetter.getNullURI(), "network-system", _networkDeviceController.getClass(), zoningExecuteMethod, null, zoningStep);
return zoningStep;
}
use of com.emc.storageos.networkcontroller.impl.NetworkZoningParam in project coprhd-controller by CoprHD.
the class ExportWorkflowUtils method generateZoningRemovePathsWorkflow.
/**
* Generate workflow step for remove paths zoning
*
* @param workflow - workflow
* @param wfGroupId - workflow group id
* @param storageURI - system URI
* @param exportGroupURI - export group URI
* @param maskAjustedPathMap - adjusted paths per mask
* @param maskRemovePaths - remove paths per mask
* @param waitFor - wait for step
* @return - generated step id
* @throws ControllerException
*/
public String generateZoningRemovePathsWorkflow(Workflow workflow, String wfGroupId, URI storageURI, URI exportGroupURI, Map<URI, Map<URI, List<URI>>> maskAdjustedPathMap, Map<URI, Map<URI, List<URI>>> maskRemovePaths, String waitFor) throws ControllerException {
String zoningStep = workflow.createStepId();
ZoningRemovePathsCompleter taskCompleter = new ZoningRemovePathsCompleter(exportGroupURI, zoningStep, maskAdjustedPathMap);
List<NetworkZoningParam> zoningParams = NetworkZoningParam.convertPathsToNetworkZoningParam(exportGroupURI, maskRemovePaths, _dbClient);
Workflow.Method zoningExecuteMethod = networkDeviceController.zoneExportRemovePathsMethod(zoningParams, taskCompleter);
zoningStep = workflow.createStep(wfGroupId, "Zoning subtask for remvoe paths: " + exportGroupURI, waitFor, NullColumnValueGetter.getNullURI(), "network-system", networkDeviceController.getClass(), zoningExecuteMethod, null, zoningStep);
return zoningStep;
}
use of com.emc.storageos.networkcontroller.impl.NetworkZoningParam in project coprhd-controller by CoprHD.
the class VPlexBackendManager method addWorkflowStepsToRemoveBackendVolumes.
/**
* Remove a list of volumes from the ExportGroup specified.
*
* @param workflow
* = Workflow steps are to be added to
* @param waitFor
* - Wait for completion of this workflow step
* @param storage
* - Storage SclusterUnknownystem
* @param exportGroupURI-
* Export Group to be processed
* @param blockObjectList
* - list of volumes or snapshot (URIs)
* @return true if any steps added to Workflow
* @throws DeviceControllerException
*/
public boolean addWorkflowStepsToRemoveBackendVolumes(Workflow workflow, String waitFor, StorageSystem storage, URI exportGroupURI, List<URI> blockObjectList) throws DeviceControllerException {
ExportGroup exportGroup = _dbClient.queryObject(ExportGroup.class, exportGroupURI);
boolean stepsAdded = false;
// Read all the ExportMasks
Map<String, ExportMask> exportMasks = new HashMap<String, ExportMask>();
Map<String, List<URI>> maskToVolumes = new HashMap<String, List<URI>>();
List<ExportMask> egExportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup);
for (ExportMask mask : egExportMasks) {
if (mask == null || mask.getInactive()) {
continue;
}
exportMasks.put(mask.getId().toString(), mask);
maskToVolumes.put(mask.getId().toString(), new ArrayList<URI>());
}
// Put this information in the maskToVolumes map.
for (URI blockObjectURI : blockObjectList) {
for (ExportMask mask : exportMasks.values()) {
if (mask.hasVolume(blockObjectURI)) {
maskToVolumes.get(mask.getId().toString()).add(blockObjectURI);
} else {
_log.info(String.format("ExportMask %s (%s) does not contain volume %s", mask.getMaskName(), mask.getId(), blockObjectURI));
}
}
}
// Now process each Export Mask.
// refresh export masks per XIO storage array
boolean needRefresh = storage.deviceIsType(Type.xtremio);
String previousStepId = waitFor;
for (ExportMask mask : exportMasks.values()) {
List<URI> volumes = maskToVolumes.get(mask.getId().toString());
if (volumes.isEmpty()) {
_log.info("No volumes to remove for Export Mask: " + mask.getId());
continue;
}
previousStepId = waitFor;
// Verify the ExportMask is present on the system, or check if it was renamed
verifyExportMaskOnSystem(mask, storage);
if (mask.getCreatedBySystem()) {
_log.info(String.format("Generating unzoning step for ExportMask %s", mask.getMaskName()));
// Since this mask was created by the system, we want to unzone it.
List<URI> maskURIs = Collections.singletonList(mask.getId());
List<NetworkZoningParam> zoningParams = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportGroup.getId(), maskURIs, _dbClient);
Workflow.Method zoneRemoveMethod = _networkDeviceController.zoneExportRemoveVolumesMethod(zoningParams, volumes);
previousStepId = workflow.createStep(ZONING_STEP, String.format("Removing zones for ExportMask %s", mask.getMaskName()), previousStepId, nullURI, "network-system", _networkDeviceController.getClass(), zoneRemoveMethod, zoneRemoveMethod, null);
} else {
_log.info(String.format("ExportMask %s not created by ViPR; no unzoning step", mask.getMaskName()));
}
VplexBackEndMaskingOrchestrator orca = getOrch(storage);
List<URI> initiatorURIs = new ArrayList<>();
if (mask.getInitiators() != null) {
initiatorURIs = new ArrayList<URI>(Collections2.transform(mask.getInitiators(), CommonTransformerFunctions.FCTN_STRING_TO_URI));
}
if (needRefresh) {
BlockStorageDevice device = _blockDeviceController.getDevice(storage.getSystemType());
device.refreshExportMask(storage, mask);
needRefresh = false;
}
Workflow.Method removeVolumesMethod = orca.deleteOrRemoveVolumesFromExportMaskMethod(storage.getId(), exportGroup.getId(), mask.getId(), volumes, initiatorURIs);
String stepId = workflow.createStepId();
workflow.createStep(EXPORT_STEP, String.format("Removing volume from ExportMask %s", mask.getMaskName()), previousStepId, storage.getId(), storage.getSystemType(), orca.getClass(), removeVolumesMethod, removeVolumesMethod, stepId);
_log.info(String.format("Generated remove volume from ExportMask %s for volumes %s", mask.getMaskName(), volumes));
stepsAdded = true;
}
return stepsAdded;
}
use of com.emc.storageos.networkcontroller.impl.NetworkZoningParam in project coprhd-controller by CoprHD.
the class VPlexBackendManager method addWorkflowStepsToAddBackendVolumes.
/**
* Add steps to generate the Workflow to add a volume to the VPLEX backend.
* The VNX is special, we do zoning after masking.
* For all the other arrays, we do zoning, then masking.
*
* @param workflow
* @param dependantStepId
* @param exportGroup
* @param exportMask
* @param volumeMap
* @param varrayURI
* @param vplex
* @param array
* @param forgetRollbackStepId
* @return String stepId of last added step
*/
public String addWorkflowStepsToAddBackendVolumes(Workflow workflow, String dependantStepId, ExportGroup exportGroup, ExportMask exportMask, Map<URI, Volume> volumeMap, URI varrayURI, StorageSystem vplex, StorageSystem array, String forgetRollbackStepId) {
// Determine if VNX or OpenStack so can order VNX zoning after masking
boolean isMaskingFirst = isMaskingFirst(array);
boolean isOpenStack = isOpenStack(array);
Map<URI, Integer> volumeLunIdMap = createVolumeMap(array.getId(), volumeMap);
String zoningStep = null;
String maskStepId = workflow.createStepId();
String reValidateExportMaskStep = workflow.createStepId();
ExportMaskAddVolumeCompleter createCompleter = new ExportMaskAddVolumeCompleter(exportGroup.getId(), exportMask.getId(), volumeLunIdMap, maskStepId, forgetRollbackStepId);
List<URI> volumeList = new ArrayList<>();
volumeList.addAll(volumeLunIdMap.keySet());
String previousStepId = dependantStepId;
String zoningDependentStep = ((isMaskingFirst && isOpenStack) ? reValidateExportMaskStep : ((isMaskingFirst && !isOpenStack) ? maskStepId : previousStepId));
if (exportMask.getCreatedBySystem()) {
_log.info(String.format("Creating zone references for Backend ExportMask %s", exportMask.getMaskName()));
List<URI> maskURIs = Collections.singletonList(exportMask.getId());
List<NetworkZoningParam> zoningParams = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportGroup.getId(), maskURIs, _dbClient);
HashSet<URI> volumes = new HashSet<URI>(volumeLunIdMap.keySet());
Workflow.Method zoneCreateMethod = _networkDeviceController.zoneExportAddVolumesMethod(exportGroup.getId(), maskURIs, volumes);
Workflow.Method zoneDeleteMethod = _networkDeviceController.zoneExportRemoveVolumesMethod(zoningParams, volumes);
zoningStep = workflow.createStep(ZONING_STEP, String.format("Adding zones for ExportMask %s", exportMask.getMaskName()), zoningDependentStep, nullURI, "network-system", _networkDeviceController.getClass(), zoneCreateMethod, zoneDeleteMethod, null);
if (!isMaskingFirst) {
previousStepId = zoningStep;
}
}
// Initiators that are sent down for export validation are the known initiators.
// For back-end VPLEX masks, I find that userAddedInitiators are not getting filled-in,
// so we're playing it safe by using known initiators.
List<URI> initiatorURIs = new ArrayList<>();
if (exportMask.getInitiators() != null) {
initiatorURIs = new ArrayList<URI>(Collections2.transform(exportMask.getInitiators(), CommonTransformerFunctions.FCTN_STRING_TO_URI));
}
VplexBackEndMaskingOrchestrator orca = getOrch(array);
Workflow.Method updateMaskMethod = orca.createOrAddVolumesToExportMaskMethod(array.getId(), exportGroup.getId(), exportMask.getId(), volumeLunIdMap, initiatorURIs, createCompleter);
Workflow.Method rollbackMaskMethod = orca.deleteOrRemoveVolumesFromExportMaskMethod(array.getId(), exportGroup.getId(), exportMask.getId(), volumeList, initiatorURIs);
workflow.createStep(EXPORT_STEP, "createOrAddVolumesToExportMask: " + exportMask.getMaskName(), previousStepId, array.getId(), array.getSystemType(), orca.getClass(), updateMaskMethod, rollbackMaskMethod, maskStepId);
// This is required as the export mask gets updated by reading the cinder response.
if (isOpenStack) {
// START - updateZoningMapAndValidateExportMask Step
Workflow.Method updatezoningAndvalidateMaskMethod = ((VplexCinderMaskingOrchestrator) orca).updateZoningMapAndValidateExportMaskMethod(varrayURI, _initiatorPortMap, exportMask.getId(), _directorToInitiatorIds, _idToInitiatorMap, _portWwnToClusterMap, vplex, array, _cluster);
workflow.createStep(REVALIDATE_MASK, "updatezoningAndrevalidateExportMask: " + exportMask.getMaskName(), maskStepId, array.getId(), array.getSystemType(), orca.getClass(), updatezoningAndvalidateMaskMethod, rollbackMaskMethod, reValidateExportMaskStep);
// END - updateZoningMapAndValidateExportMask Step
}
_log.info(String.format("VPLEX ExportGroup %s (%s) vplex %s varray %s", exportGroup.getLabel(), exportGroup.getId(), vplex.getId(), exportGroup.getVirtualArray()));
return (isMaskingFirst && zoningStep != null) ? zoningStep : maskStepId;
}
use of com.emc.storageos.networkcontroller.impl.NetworkZoningParam in project coprhd-controller by CoprHD.
the class VPlexDeviceController method exportGroupRemoveVolumes.
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.impl.vplex.VplexController#exportRemoveVolume(java.net.URI, java.net.URI,
* java.net.URI,
* java.lang.String)
*/
@Override
public void exportGroupRemoveVolumes(URI vplexURI, URI exportURI, List<URI> volumeURIs, String opId) throws ControllerException {
String volListStr = "";
ExportRemoveVolumeCompleter completer = null;
boolean hasSteps = false;
try {
_log.info("entering export group remove volumes");
WorkflowStepCompleter.stepExecuting(opId);
completer = new ExportRemoveVolumeCompleter(exportURI, volumeURIs, opId);
volListStr = Joiner.on(',').join(volumeURIs);
validator.volumeURIs(volumeURIs, false, false, ValCk.ID);
Workflow workflow = _workflowService.getNewWorkflow(this, EXPORT_GROUP_REMOVE_VOLUMES, false, opId);
StorageSystem vplex = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, exportURI, _dbClient);
List<ExportMask> exportMasks = ExportMaskUtils.getExportMasks(_dbClient, exportGroup, vplex.getId());
StringBuffer errorMessages = new StringBuffer();
boolean isValidationNeeded = validatorConfig.isValidationEnabled();
_log.info("Orchestration level validation needed : {}", isValidationNeeded);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplex, _dbClient);
// For safety, run remove volumes serially
String previousStep = null;
for (ExportMask exportMask : exportMasks) {
if (exportMask.getInactive()) {
_log.info(String.format("ExportMask %s (%s) is inactive, skipping", exportMask.getMaskName(), exportMask.getId()));
continue;
}
String vplexClusterName = VPlexUtil.getVplexClusterName(exportMask, vplexURI, client, _dbClient);
Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, exportMask.getMaskName());
_log.info("Refreshing ExportMask {}", exportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, exportMask, targetPortToPwwnMap, _networkDeviceController);
List<URI> volumeURIList = new ArrayList<URI>();
List<URI> remainingVolumesInMask = new ArrayList<URI>();
if (exportMask.getVolumes() != null && !exportMask.getVolumes().isEmpty()) {
// note that this is the assumed behavior even for the
// situation in which this export mask is in use by other
// export groups... see CTRL-3941
// assemble a list of other ExportGroups that reference this ExportMask
List<ExportGroup> otherExportGroups = ExportUtils.getOtherExportGroups(exportGroup, exportMask, _dbClient);
if (otherExportGroups != null && !otherExportGroups.isEmpty()) {
// Gets the list of volume URIs that are not other Export Groups
volumeURIList = getVolumeListDiff(exportGroup, exportMask, otherExportGroups, volumeURIs);
} else {
volumeURIList = volumeURIs;
}
Map<URI, BlockObject> blockObjectMap = VPlexUtil.translateRPSnapshots(_dbClient, volumeURIList);
volumeURIList.clear();
volumeURIList.addAll(blockObjectMap.keySet());
volumeURIList = ExportMaskUtils.filterVolumesByExportMask(volumeURIList, exportMask);
for (String volumeURI : exportMask.getVolumes().keySet()) {
remainingVolumesInMask.add(URI.create(volumeURI));
}
remainingVolumesInMask.removeAll(volumeURIList);
}
_log.info(String.format("exportGroupRemove: mask %s volumes to process: %s", exportMask.getMaskName(), volumeURIList.toString()));
// Fetch exportMask again as exportMask zoning Map might have changed in zoneExportRemoveVolumes
exportMask = _dbClient.queryObject(ExportMask.class, exportMask.getId());
boolean existingVolumes = exportMask.hasAnyExistingVolumes();
// The useradded - existing initiators enhancement made in refreshExportMask
// guarantees that all the discovered initiators are added to userAdded,
// irrespective of whether it's already registered on the array manually.
boolean existingInitiators = exportMask.hasAnyExistingInitiators();
boolean canMaskBeDeleted = remainingVolumesInMask.isEmpty() && !existingInitiators && !existingVolumes;
if (!canMaskBeDeleted) {
_log.info("this mask is not empty, so just updating: " + exportMask.getMaskName());
completer.addExportMaskToRemovedVolumeMapping(exportMask.getId(), volumeURIList);
Workflow.Method storageViewRemoveVolume = storageViewRemoveVolumesMethod(vplex.getId(), exportGroup.getId(), exportMask.getId(), volumeURIList, opId, completer, null);
previousStep = workflow.createStep("removeVolumes", String.format("Removing volumes from export on storage array %s (%s) for export mask %s (%s)", vplex.getNativeGuid(), vplex.getId().toString(), exportMask.getMaskName(), exportMask.getId()), previousStep, vplex.getId(), vplex.getSystemType(), this.getClass(), storageViewRemoveVolume, rollbackMethodNullMethod(), null);
// Add zoning step for removing volumes
List<NetworkZoningParam> zoningParam = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportGroup.getId(), Collections.singletonList(exportMask.getId()), _dbClient);
Workflow.Method zoneRemoveVolumesMethod = _networkDeviceController.zoneExportRemoveVolumesMethod(zoningParam, volumeURIList);
previousStep = workflow.createStep(null, "Zone remove volumes mask: " + exportMask.getMaskName(), previousStep, nullURI, "network-system", _networkDeviceController.getClass(), zoneRemoveVolumesMethod, _networkDeviceController.zoneNullRollbackMethod(), null);
hasSteps = true;
/**
* TODO
* ExportremoveVolumeCompleter should be enhanced to remove export mask from export group if last volume removed.
* We already take care of this.
*/
} else {
_log.info("this mask is empty of ViPR-managed volumes, and there are no existing volumes or initiators, so deleting: " + exportMask.getMaskName());
List<NetworkZoningParam> zoningParams = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportURI, Collections.singletonList(exportMask.getId()), _dbClient);
hasSteps = true;
String exportMaskDeleteStep = workflow.createStepId();
Workflow.Method deleteStorageView = deleteStorageViewMethod(vplexURI, exportURI, exportMask.getId(), false);
previousStep = workflow.createStep(DELETE_STORAGE_VIEW, String.format("Deleting storage view: %s (%s)", exportMask.getMaskName(), exportMask.getId()), previousStep, vplexURI, vplex.getSystemType(), this.getClass(), deleteStorageView, null, exportMaskDeleteStep);
// Unzone step (likely just a FCZoneReference removal since this is remove volume only)
previousStep = workflow.createStep(ZONING_STEP, "Zoning subtask for export-group: " + exportURI, previousStep, NullColumnValueGetter.getNullURI(), "network-system", _networkDeviceController.getClass(), _networkDeviceController.zoneExportRemoveVolumesMethod(zoningParams, volumeURIs), null, workflow.createStepId());
}
}
if (hasSteps) {
String message = errorMessages.toString();
if (isValidationNeeded && !message.isEmpty()) {
_log.error("Error Message {}", errorMessages);
List<Volume> volumes = _dbClient.queryObject(Volume.class, volumeURIs);
String volumesForDisplay = Joiner.on(", ").join(Collections2.transform(volumes, CommonTransformerFunctions.fctnDataObjectToForDisplay()));
throw DeviceControllerException.exceptions.removeVolumesValidationError(volumesForDisplay, vplex.forDisplay(), message);
}
workflow.executePlan(completer, String.format("Sucessfully removed volumes or deleted Storage View: %s (%s)", exportGroup.getLabel(), exportGroup.getId()));
} else {
completer.ready(_dbClient);
}
} catch (VPlexApiException vae) {
String message = String.format("Failed to remove Volume %s from ExportGroup %s", volListStr, exportURI);
_log.error(message, vae);
failStep(completer, opId, vae);
} catch (Exception ex) {
String message = String.format("Failed to remove Volume %s from ExportGroup %s", volListStr, exportURI);
_log.error(message, ex);
String opName = ResourceOperationTypeEnum.DELETE_EXPORT_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.exportGroupRemoveVolumesFailed(volListStr, exportURI.toString(), opName, ex);
failStep(completer, opId, serviceError);
}
}
Aggregations