use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VplexCinderMaskingOrchestrator method updateZoningMapAndvalidateExportMask.
/**
* Re-validate the ExportMask
*
* This is required to be done as the ExportMask
* gets updated by reading the cinder export volume
* response.
*
* @param varrayURI
* @param initiatorPortMap
* @param mask
* @param invalidMasks
* @param directorToInitiatorIds
* @param idToInitiatorMap
* @param dbClient
* @param portWwnToClusterMap
*/
public void updateZoningMapAndvalidateExportMask(URI varrayURI, Map<URI, List<StoragePort>> initiatorPortMap, URI exportMaskURI, Map<String, Set<String>> directorToInitiatorIds, Map<String, Initiator> idToInitiatorMap, Map<String, String> portWwnToClusterMap, StorageSystem vplex, StorageSystem array, String clusterId, String stepId) {
try {
WorkflowStepCompleter.stepExecuting(stepId);
// Export Mask is updated, read it from DB
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
// First step would be to update the zoning map based on the connectivity
updateZoningMap(initiatorPortMap, directorToInitiatorIds, exportMask);
StringBuilder errorMessages = new StringBuilder();
boolean passed = VPlexBackEndOrchestratorUtil.validateExportMask(varrayURI, initiatorPortMap, exportMask, null, directorToInitiatorIds, idToInitiatorMap, _dbClient, _coordinator, portWwnToClusterMap, errorMessages);
if (!passed) {
// Mark this mask as inactive, so that we dont pick it in the next iteration
exportMask.setInactive(Boolean.TRUE);
_dbClient.updateObject(exportMask);
_log.error("Export Mask is not suitable for VPLEX to backend storage system");
WorkflowStepCompleter.stepFailed(stepId, VPlexApiException.exceptions.couldNotFindValidArrayExportMask(vplex.getNativeGuid(), array.getNativeGuid(), clusterId, errorMessages.toString()));
throw VPlexApiException.exceptions.couldNotFindValidArrayExportMask(vplex.getNativeGuid(), array.getNativeGuid(), clusterId, errorMessages.toString());
}
WorkflowStepCompleter.stepSucceded(stepId);
} catch (Exception ex) {
_log.error("Failed to validate export mask for cinder: ", ex);
VPlexApiException vplexex = DeviceControllerExceptions.vplex.failedToValidateExportMask(exportMaskURI.toString(), ex);
WorkflowStepCompleter.stepFailed(stepId, vplexex);
}
}
use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VplexCinderMaskingOrchestrator method deleteOrRemoveVolumesFromExportMask.
@Override
public void deleteOrRemoveVolumesFromExportMask(URI arrayURI, URI exportGroupURI, URI exportMaskURI, List<URI> volumes, List<URI> initiatorURIs, String stepId) {
ExportTaskCompleter completer = null;
try {
completer = new ExportMaskOnlyRemoveVolumeCompleter(exportGroupURI, exportMaskURI, volumes, stepId);
WorkflowStepCompleter.stepExecuting(stepId);
StorageSystem array = _dbClient.queryObject(StorageSystem.class, arrayURI);
BlockStorageDevice device = _blockController.getDevice(array.getSystemType());
ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI);
// If the exportMask isn't found, or has been deleted, nothing to do.
if (exportMask == null || exportMask.getInactive()) {
_log.info(String.format("ExportMask %s inactive, returning success", exportMaskURI));
completer.ready(_dbClient);
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
exportMask = refreshExportMask(array, device, exportMask);
// Determine if we're deleting the last volume in the mask.
StringMap maskVolumesMap = exportMask.getVolumes();
Set<String> remainingVolumes = new HashSet<String>();
List<URI> passedVolumesInMask = new ArrayList<>(volumes);
if (maskVolumesMap != null) {
remainingVolumes.addAll(maskVolumesMap.keySet());
}
for (URI volume : volumes) {
remainingVolumes.remove(volume.toString());
// are not in the mask to handle this condition.
if ((maskVolumesMap != null) && (!maskVolumesMap.keySet().contains(volume.toString()))) {
passedVolumesInMask.remove(volume);
}
}
// None of the volumes is in the export mask, so we are done.
if (passedVolumesInMask.isEmpty()) {
_log.info("None of these volumes {} are in export mask {}", volumes, exportMask.forDisplay());
completer.ready(_dbClient);
return;
}
// If it is last volume and there are no existing volumes, delete the ExportMask.
if (remainingVolumes.isEmpty() && !exportMask.hasAnyExistingVolumes()) {
_log.debug(String.format("Calling doExportDelete on the device %s", array.getId().toString()));
device.doExportDelete(array, exportMask, null, null, completer);
} else {
_log.debug(String.format("Calling doExportRemoveVolumes on the device %s", array.getId().toString()));
List<Initiator> initiators = null;
if (initiatorURIs != null && !initiatorURIs.isEmpty()) {
initiators = _dbClient.queryObject(Initiator.class, initiatorURIs);
}
device.doExportRemoveVolumes(array, exportMask, passedVolumesInMask, initiators, completer);
}
completer.ready(_dbClient);
} catch (Exception ex) {
_log.error("Failed to delete or remove volumes to export mask for cinder: ", ex);
VPlexApiException vplexex = DeviceControllerExceptions.vplex.addStepsForDeleteVolumesFailed(ex);
completer.error(_dbClient, vplexex);
}
}
use of com.emc.storageos.vplex.api.VPlexApiException 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.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class AbstractConsistencyGroupManager method removeVolumesFromCGInternal.
/**
* The method called by the workflow to remove VPLEX volumes from a VPLEX
* consistency group.
* @param vplexURI -- URI of VPlex device
* @param cgURI -- URI of Consistency Group
* @param vplexVolumeURIs -- URI list of volumes that will be removed
* @return ServiceCoded exception if an error occurred, otherwise null if no error occurred.
*/
protected ServiceCoded removeVolumesFromCGInternal(URI vplexURI, URI cgURI, List<URI> vplexVolumeURIs) {
try {
if (vplexVolumeURIs.isEmpty()) {
log.info("Empty volume list; no volumes to remove from CG %s", cgURI.toString());
return null;
}
// Get the API client.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, dbClient);
VPlexApiClient client = getVPlexAPIClient(vplexApiFactory, vplexSystem, dbClient);
log.info("Got VPLEX API client.");
Map<String, List<String>> cgToVolumesMap = new HashMap<String, List<String>>();
// Get the names of the volumes to be removed.
List<Volume> vplexVolumes = new ArrayList<Volume>();
for (URI vplexVolumeURI : vplexVolumeURIs) {
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, dbClient);
if (vplexVolume == null || vplexVolume.getInactive()) {
log.error(String.format("Skipping null or inactive vplex volume %s", vplexVolumeURI.toString()));
continue;
}
// Remove CG reference from volume, it won't be persisted until after the operation completes.
vplexVolume.setConsistencyGroup(NullColumnValueGetter.getNullURI());
vplexVolumes.add(vplexVolume);
// Get the CG name for this VPLEX volume, it could be a CG
// that is distributed, a CG on cluster-1, or a CG on cluster-2.
String cgName = getVplexCgName(vplexVolume, cgURI);
// Keep a map of CG name grouped by all VPLEX volumes in that same CG.
List<String> vplexVolumeNames = cgToVolumesMap.get(cgName);
if (vplexVolumeNames == null) {
vplexVolumeNames = new ArrayList<String>();
cgToVolumesMap.put(cgName, vplexVolumeNames);
}
vplexVolumeNames.add(vplexVolume.getDeviceLabel());
log.info(String.format("Adding VPLEX volume [%s](%s) with device label [%s] to be removed from VPLEX CG [%s]", vplexVolume.getLabel(), vplexVolume.getId(), vplexVolume.getDeviceLabel(), cgName));
}
for (Map.Entry<String, List<String>> entry : cgToVolumesMap.entrySet()) {
String cgName = entry.getKey();
List<String> vplexVolumeNames = entry.getValue();
log.info(String.format("Removing the following VPLEX volumes from VPLEX CG [%s]: %s", cgName, Joiner.on(", ").join(vplexVolumeNames)));
// Remove the volumes from the CG.
client.removeVolumesFromConsistencyGroup(vplexVolumeNames, cgName, false);
}
log.info("Removed volumes from consistency group.");
dbClient.updateObject(vplexVolumes);
return null;
} catch (VPlexApiException vae) {
log.error("Exception removing volumes from consistency group: " + vae.getMessage(), vae);
return vae;
} catch (Exception ex) {
log.error("Exception removing volumes from consistency group: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.DELETE_CG_VOLUME.getName();
ServiceError serviceError = VPlexApiException.errors.removeVolumesFromCGFailed(opName, ex);
return serviceError;
}
}
use of com.emc.storageos.vplex.api.VPlexApiException in project coprhd-controller by CoprHD.
the class VPlexConsistencyGroupManager method createCG.
/**
* Called by the workflow to create a new VPLEX consistency group.
*
* @param vplexURI The URI of the VPLEX storage system.
* @param cgURI The URI of the Bourne consistency group
* @param vplexVolumeURIs The URI of the VPLEX used to determine the VPlex
* cluster/distributed information.
* @param stepId The workflow step id.
*
* @throws WorkflowException When an error occurs updating the workflow step
* state.
*/
public void createCG(URI vplexURI, URI cgURI, List<URI> vplexVolumeURIs, String stepId) throws WorkflowException {
try {
// Update workflow step.
WorkflowStepCompleter.stepExecuting(stepId);
log.info("Updated step state for consistency group creation to execute.");
// Lock the CG for the step duration.
List<String> lockKeys = new ArrayList<String>();
lockKeys.add(ControllerLockingUtil.getConsistencyGroupStorageKey(dbClient, cgURI, vplexURI));
workflowService.acquireWorkflowStepLocks(stepId, lockKeys, LockTimeoutValue.get(LockType.RP_VPLEX_CG));
// Get the API client.
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, dbClient);
VPlexApiClient client = getVPlexAPIClient(vplexApiFactory, vplexSystem, dbClient);
log.info("Got VPLEX API client.");
// Get the consistency group
BlockConsistencyGroup cg = getDataObject(BlockConsistencyGroup.class, cgURI, dbClient);
// Check to see if it was created since we defined the workflow.
if (cg.created(vplexURI)) {
StringSet cgNames = cg.getSystemConsistencyGroups().get(vplexURI.toString());
log.info("Consistency group(s) already created: " + cgNames.toString());
if (!cg.getTypes().contains(Types.VPLEX.name())) {
// SRDF will reset the CG types. If the CG was existing on VPLEX need to make sure it is in types.
cg.addConsistencyGroupTypes(Types.VPLEX.name());
dbClient.updateObject(cg);
}
WorkflowStepCompleter.stepSucceded(stepId);
return;
}
// We need to know on what cluster to create the consistency group.
// The cluster would be determined by the virtual array specified in
// a volume creation request, which is the virtual array of the
// passed virtual volumes. Get the virtual array for one of the
// vplex volumes.
Volume firstVPlexVolume = getDataObject(Volume.class, vplexVolumeURIs.get(0), dbClient);
// Lets determine the VPlex consistency group that need to be created for this volume.
ClusterConsistencyGroupWrapper clusterConsistencyGroup = getClusterConsistencyGroup(firstVPlexVolume, cg);
String cgName = clusterConsistencyGroup.getCgName();
String clusterName = clusterConsistencyGroup.getClusterName();
boolean isDistributed = clusterConsistencyGroup.isDistributed();
URI vaURI = firstVPlexVolume.getVirtualArray();
log.info("Got virtual array for VPLEX volume.");
// Now we can create the consistency group.
client.createConsistencyGroup(cgName, clusterName, isDistributed);
log.info("Created VPLEX consistency group.");
// Create the rollback data in case this needs to be deleted.
VPlexCGRollbackData rbData = new VPlexCGRollbackData();
rbData.setVplexSystemURI(vplexURI);
rbData.setCgName(cgName);
rbData.setClusterName(clusterName);
rbData.setIsDistributed(new Boolean(getIsCGDistributed(client, cgName, clusterName)));
workflowService.storeStepData(stepId, rbData);
// Now update the CG in the DB.
cg.setVirtualArray(vaURI);
cg.setStorageController(vplexURI);
cg.addSystemConsistencyGroup(vplexSystem.getId().toString(), BlockConsistencyGroupUtils.buildClusterCgName(clusterName, cgName));
cg.addConsistencyGroupTypes(Types.VPLEX.name());
dbClient.persistObject(cg);
log.info("Updated consistency group in DB.");
// Update workflow step state to success.
WorkflowStepCompleter.stepSucceded(stepId);
log.info("Updated workflow step for consistency group creation to success.");
} catch (VPlexApiException vex) {
log.error("Exception creating consistency group: " + vex.getMessage(), vex);
WorkflowStepCompleter.stepFailed(stepId, vex);
} catch (Exception ex) {
log.error("Exception creating consistency group: " + ex.getMessage(), ex);
String opName = ResourceOperationTypeEnum.CREATE_CONSISTENCY_GROUP.getName();
ServiceError serviceError = VPlexApiException.errors.createConsistencyGroupFailed(opName, ex);
WorkflowStepCompleter.stepFailed(stepId, serviceError);
}
}
Aggregations