use of com.emc.storageos.vplex.api.VPlexApiClient 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);
}
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method validateStorageProviderConnection.
/**
* Validate a VPLEX Storage Provider connection.
*
* @param ipAddress
* the Storage Provider's IP address
* @param portNumber
* the Storage Provider's IP port
*
* @return true if the Storage Provider connection is valid
*/
@Override
public boolean validateStorageProviderConnection(String ipAddress, Integer portNumber) {
boolean connectionValid;
try {
// look up the provider by ip address and port
StringBuffer providerId = new StringBuffer(ipAddress).append(HYPHEN_OPERATOR).append(portNumber);
URIQueryResultList providerUriList = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory.getStorageProviderByProviderIDConstraint(providerId.toString()), providerUriList);
if (providerUriList.iterator().hasNext()) {
StorageProvider provider = _dbClient.queryObject(StorageProvider.class, providerUriList.iterator().next());
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, provider, _dbClient);
if (client != null) {
client.verifyConnectivity();
// if we got this far without blowing up, then the connection is valid
_log.info("VPLEX Storage Provider connection at {} is valid.", providerId);
connectionValid = true;
} else {
_log.error("a VplexApiClient could not be created for provider {}.", provider.getLabel());
connectionValid = false;
}
} else {
_log.error("Could not find a VPLEX Storage Provider " + "with address-port {} in ViPR.", providerId);
connectionValid = false;
}
} catch (Exception ex) {
_log.error("Connection to VPLEX Storage Provider {} is invalid.", ipAddress, ex);
connectionValid = false;
}
return connectionValid;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method getVPlexAPIClient.
private static VPlexApiClient getVPlexAPIClient(VPlexApiFactory vplexApiFactory, StorageProvider vplexMnmgtSvr, DbClient dbClient) throws URISyntaxException {
VPlexApiClient client = VPlexControllerUtils.getVPlexAPIClient(vplexApiFactory, vplexMnmgtSvr, dbClient);
updateTimeoutValues();
return client;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method assembleExportMasksWorkflow.
/**
* Method to assemble the find or create VPLEX storage views (export masks) workflow for the given
* ExportGroup, Initiators, and the block object Map.
*
* @param vplexURI
* the URI of the VPLEX StorageSystem object
* @param export
* the ExportGroup in question
* @param varrayUri
* -- NOTE! The varrayURI may NOT be the same as the exportGroup varray!.
* @param initiators
* if initiators is null, the method will use all initiators from the ExportGroup
* @param blockObjectMap
* the key (URI) of this map can reference either the volume itself or a snapshot.
* @param zoningStepNeeded - Determines whether zone step is needed
* @param workflow
* the controller workflow
* @param waitFor
* -- If non-null, will wait on previous workflow step
* @param opId
* the workflow step id
* @return the last Workflow Step id
* @throws Exception
*/
private String assembleExportMasksWorkflow(URI vplexURI, URI export, URI varrayUri, List<URI> initiators, Map<URI, Integer> blockObjectMap, boolean zoningStepNeeded, Workflow workflow, String waitFor, String opId) throws Exception {
long startAssembly = new Date().getTime();
VPlexControllerUtils.cleanStaleExportMasks(_dbClient, vplexURI);
_log.info("TIMER: clean stale export masks took {} ms", new Date().getTime() - startAssembly);
StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
ExportGroup exportGroup = getDataObject(ExportGroup.class, export, _dbClient);
// filter volume map just for this VPLEX's virtual volumes
_log.info("object map before filtering for this VPLEX: " + blockObjectMap);
Map<URI, Integer> filteredBlockObjectMap = new HashMap<URI, Integer>();
for (URI boURI : blockObjectMap.keySet()) {
BlockObject bo = Volume.fetchExportMaskBlockObject(_dbClient, boURI);
if (bo.getStorageController().equals(vplexURI)) {
filteredBlockObjectMap.put(bo.getId(), blockObjectMap.get(boURI));
}
}
blockObjectMap = filteredBlockObjectMap;
_log.info("object map after filtering for this VPLEX: " + blockObjectMap);
// validate volume to lun map to make sure there aren't any duplicate LUN entries
ExportUtils.validateExportGroupVolumeMap(exportGroup.getLabel(), blockObjectMap);
VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
// we will need lists of new export masks to create and existing export masks to simply update
List<ExportMask> exportMasksToCreateOnDevice = new ArrayList<ExportMask>();
List<ExportMask> exportMasksToUpdateOnDevice = new ArrayList<ExportMask>();
// In case we are just updating the existing export masks we will need this map
// to add initiators which are not already there.
Map<URI, List<Initiator>> exportMasksToUpdateOnDeviceWithInitiators = new HashMap<URI, List<Initiator>>();
// In case we are just updating the existing export masks we will need this map
// to add storage ports which are not already there.
Map<URI, List<URI>> exportMasksToUpdateOnDeviceWithStoragePorts = new HashMap<URI, List<URI>>();
// try to collect initiators, if none supplied by caller
if (initiators == null) {
initiators = new ArrayList<URI>();
if (exportGroup.hasInitiators()) {
for (String initiator : exportGroup.getInitiators()) {
initiators.add(URI.create(initiator));
}
}
}
// sort initiators in a host to initiator map
Map<URI, List<Initiator>> hostInitiatorMap = VPlexUtil.makeHostInitiatorsMap(initiators, _dbClient);
// This Set will be used to track shared export mask in database.
Set<ExportMask> sharedExportMasks = new HashSet<ExportMask>();
// look at each host
String lockName = null;
boolean lockAcquired = false;
String vplexClusterId = ConnectivityUtil.getVplexClusterForVarray(varrayUri, vplexURI, _dbClient);
String vplexClusterName = VPlexUtil.getVplexClusterName(varrayUri, vplexURI, client, _dbClient);
try {
lockName = _vplexApiLockManager.getLockName(vplexURI, vplexClusterId);
lockAcquired = _vplexApiLockManager.acquireLock(lockName, LockTimeoutValue.get(LockType.VPLEX_API_LIB));
if (!lockAcquired) {
throw VPlexApiException.exceptions.couldNotObtainConcurrencyLock(vplexSystem.getLabel());
}
Map<String, String> targetPortToPwwnMap = VPlexControllerUtils.getTargetPortToPwwnMap(client, vplexClusterName);
Boolean[] doInitiatorRefresh = new Boolean[] { new Boolean(true) };
/**
* COP-28674: During Vblock boot volume export, if existing storage views are found then check for existing volumes
* If found throw exception. This condition is valid only for boot volume vblock export.
*/
if (exportGroup.forHost() && ExportMaskUtils.isVblockHost(initiators, _dbClient) && ExportMaskUtils.isBootVolume(_dbClient, blockObjectMap)) {
_log.info("VBlock boot volume Export: Validating the Vplex Cluster {} to find existing storage views", vplexClusterName);
List<Initiator> initiatorList = _dbClient.queryObject(Initiator.class, initiators);
List<String> initiatorNames = getInitiatorNames(vplexSystem.getSerialNumber(), vplexClusterName, client, initiatorList.iterator(), doInitiatorRefresh);
List<VPlexStorageViewInfo> storageViewInfos = client.getStorageViewsContainingInitiators(vplexClusterName, initiatorNames);
List<String> maskNames = new ArrayList<String>();
if (!CollectionUtils.isEmpty(storageViewInfos)) {
for (VPlexStorageViewInfo storageView : storageViewInfos) {
if (!CollectionUtils.isEmpty(storageView.getVirtualVolumes())) {
maskNames.add(storageView.getName());
} else {
_log.info("Found Storage View {} for cluster {} with empty volumes", storageView.getName(), vplexClusterName);
}
}
} else {
_log.info("No Storage views found for cluster {}", vplexClusterName);
}
if (!CollectionUtils.isEmpty(maskNames)) {
Set<URI> computeResourceSet = hostInitiatorMap.keySet();
throw VPlexApiException.exceptions.existingMaskFoundDuringBootVolumeExport(Joiner.on(", ").join(maskNames), Joiner.on(", ").join(computeResourceSet), vplexClusterName);
} else {
_log.info("VBlock Boot volume Export : Validation passed");
}
}
for (URI hostUri : hostInitiatorMap.keySet()) {
_log.info("assembling export masks workflow, now looking at host URI: " + hostUri);
List<Initiator> inits = hostInitiatorMap.get(hostUri);
_log.info("this host contains these initiators: " + inits);
boolean foundMatchingStorageView = false;
boolean allPortsFromMaskMatchForVarray = true;
_log.info("attempting to locate an existing ExportMask for this host's initiators on VPLEX Cluster " + vplexClusterId);
Map<URI, ExportMask> vplexExportMasks = new HashMap<URI, ExportMask>();
allPortsFromMaskMatchForVarray = filterExportMasks(vplexExportMasks, inits, varrayUri, vplexSystem, vplexClusterId);
ExportMask sharedVplexExportMask = null;
switch(vplexExportMasks.size()) {
case FOUND_NO_VIPR_EXPORT_MASKS:
// Didn't find any single existing ExportMask for this Host/Initiators.
// Check if there is a shared ExportMask in CoprHD with by checking the existing initiators list.
sharedVplexExportMask = VPlexUtil.getExportMasksWithExistingInitiators(vplexURI, _dbClient, inits, varrayUri, vplexClusterId);
// on the VPLEX and set it up as a new ExportMask.
if (null != sharedVplexExportMask) {
sharedExportMasks.add(sharedVplexExportMask);
// If sharedVplexExportMask is found then that export mask will be used to add any missing
// initiators or storage ports as needed, and volumes requested, if not already present.
setupExistingExportMaskWithNewHost(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, inits, sharedVplexExportMask, opId);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, sharedVplexExportMask.getMaskName());
_log.info("Refreshing ExportMask {}", sharedVplexExportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, sharedVplexExportMask, targetPortToPwwnMap, _networkDeviceController);
foundMatchingStorageView = true;
break;
} else {
_log.info("could not find an existing matching ExportMask in ViPR, " + "so ViPR will see if there is one already on the VPLEX system");
// ViPR will attempt to find a suitable existing storage view
// on the VPLEX and set it up as a new ExportMask.
long start = new Date().getTime();
foundMatchingStorageView = checkForExistingStorageViews(client, targetPortToPwwnMap, vplexSystem, vplexClusterName, inits, exportGroup, varrayUri, blockObjectMap, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, doInitiatorRefresh, opId);
long elapsed = new Date().getTime() - start;
_log.info("TIMER: finding an existing storage view took {} ms and returned {}", elapsed, foundMatchingStorageView);
break;
}
case FOUND_ONE_VIPR_EXPORT_MASK:
// get the single value in the map
ExportMask viprExportMask = vplexExportMasks.values().iterator().next();
_log.info("a valid ExportMask matching these initiators exists already in ViPR " + "for this VPLEX device, so ViPR will re-use it: " + viprExportMask.getMaskName());
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, viprExportMask.getMaskName());
_log.info("Refreshing ExportMask {}", viprExportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, viprExportMask, targetPortToPwwnMap, _networkDeviceController);
reuseExistingExportMask(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithStoragePorts, inits, allPortsFromMaskMatchForVarray, viprExportMask, opId);
foundMatchingStorageView = true;
break;
default:
String message = "Invalid Configuration: more than one VPLEX ExportMask " + "in this cluster exists in ViPR for these initiators " + inits;
_log.error(message);
throw new Exception(message);
}
// or set up a brand new ExportMask (to create a storage view on the VPLEX) for the Host.
if (!foundMatchingStorageView) {
if (null == sharedVplexExportMask) {
// If we reached here, it means there isn't an existing storage view on the VPLEX with the host,
// and no other shared ExportMask was found in the database by looking at existingInitiators.
// So, ViPR will try to find if there is shared export mask already for the ExportGroup in the database.
sharedVplexExportMask = VPlexUtil.getSharedExportMaskInDb(exportGroup, vplexURI, _dbClient, varrayUri, vplexClusterId, hostInitiatorMap);
}
if (null != sharedVplexExportMask) {
// If a sharedExportMask was found, then the new host will be added to that ExportMask
_log.info(String.format("Shared export mask %s %s found for the export group %s %s which will be reused for initiators %s .", sharedVplexExportMask.getMaskName(), sharedVplexExportMask.getId(), exportGroup.getLabel(), exportGroup.getId(), inits.toString()));
sharedExportMasks.add(sharedVplexExportMask);
VPlexStorageViewInfo storageView = client.getStorageView(vplexClusterName, sharedVplexExportMask.getMaskName());
_log.info("Refreshing ExportMask {}", sharedVplexExportMask.getMaskName());
VPlexControllerUtils.refreshExportMask(_dbClient, storageView, sharedVplexExportMask, targetPortToPwwnMap, _networkDeviceController);
setupExistingExportMaskWithNewHost(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToUpdateOnDevice, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, inits, sharedVplexExportMask, opId);
} else {
// Otherwise, create a brand new ExportMask, which will enable the storage view to
// be created on the VPLEX device as part of this workflow
_log.info("did not find a matching existing storage view anywhere, so ViPR " + "will initialize a new one and push it to the VPLEX device");
setupNewExportMask(blockObjectMap, vplexSystem, exportGroup, varrayUri, exportMasksToCreateOnDevice, inits, vplexClusterId, opId);
}
}
}
} finally {
if (lockAcquired) {
_vplexApiLockManager.releaseLock(lockName);
}
}
_log.info("updating zoning if necessary for both new and updated export masks");
String zoningStepId = waitFor;
if (zoningStepNeeded) {
_log.info("Adding step to update zones if required.");
zoningStepId = addStepsForZoningUpdate(export, initiators, blockObjectMap, workflow, waitFor, exportMasksToCreateOnDevice, exportMasksToUpdateOnDevice);
}
_log.info("set up initiator pre-registration step");
String storageViewStepId = addStepsForInitiatorRegistration(initiators, vplexSystem, vplexClusterName, workflow, zoningStepId);
_log.info("processing the export masks to be created");
for (ExportMask exportMask : exportMasksToCreateOnDevice) {
storageViewStepId = addStepsForExportMaskCreate(blockObjectMap, workflow, vplexSystem, exportGroup, storageViewStepId, exportMask);
}
_log.info("processing the export masks to be updated");
for (ExportMask exportMask : exportMasksToUpdateOnDevice) {
boolean shared = false;
if (sharedExportMasks.contains(exportMask)) {
shared = true;
}
storageViewStepId = addStepsForExportMaskUpdate(export, blockObjectMap, workflow, vplexSystem, exportMasksToUpdateOnDeviceWithInitiators, exportMasksToUpdateOnDeviceWithStoragePorts, storageViewStepId, exportMask, shared);
}
long elapsed = new Date().getTime() - startAssembly;
_log.info("TIMER: export mask assembly took {} ms", elapsed);
return storageViewStepId;
}
use of com.emc.storageos.vplex.api.VPlexApiClient in project coprhd-controller by CoprHD.
the class VPlexDeviceController method rollbackRestoreResync.
/**
* Called if the restore/resync volume operation fails
*
* @param vplexURI
* The URI of the VPLEX system.
* @param vplexVolumeURI
* The URI of the distributed VPLEX volume.
* @param cgURI
* The URI of the volume's CG or null.
* @param detachStepId
* The Id of the detach mirror step.
* @param stepId
* The workflow step identifier.
*/
public void rollbackRestoreResync(URI vplexURI, URI vplexVolumeURI, URI cgURI, String detachStepId, String stepId) {
_log.info("Executing rollback of restore/resync volume {} on VPLEX {}", new Object[] { vplexVolumeURI, vplexURI });
String mirrorDeviceName = "";
try {
// Update workflow step.
WorkflowStepCompleter.stepExecuting(stepId);
// Get the rollback data so we know what to do.
@SuppressWarnings("unchecked") Map<String, String> rollbackData = (Map<String, String>) _workflowService.loadStepData(detachStepId);
String successWarningMessage = null;
if (rollbackData != null) {
boolean reattachMirror = Boolean.parseBoolean(rollbackData.get(REATTACH_MIRROR));
boolean addVolumeBackToCG = Boolean.parseBoolean(rollbackData.get(ADD_BACK_TO_CG));
String restoreDeviceName = rollbackData.get(RESTORE_DEVICE_NAME);
if ((restoreDeviceName != null) || reattachMirror || addVolumeBackToCG) {
// 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 VPLEX volume.
Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
String vplexVolumeName = vplexVolume.getDeviceLabel();
_log.info("Got VPLEX volume");
// the remote mirror, do this first.
if (reattachMirror) {
// Attach the mirror.
mirrorDeviceName = rollbackData.get(DETACHED_DEVICE);
client.reattachMirrorToDistributedVolume(vplexVolumeName, mirrorDeviceName);
_log.info("Reattached the mirror");
}
// and needs to be restored, do so after reattaching the device.
if (restoreDeviceName != null) {
String modifiedName = null;
try {
modifiedName = restoreDeviceName.substring(0, VPlexApiConstants.MAX_DEVICE_NAME_LENGTH_FOR_ATTACH_MIRROR);
client.renameDistributedDevice(modifiedName, restoreDeviceName);
} catch (Exception e) {
// We don't fail the rollback workflow step in this case, but instead just log a message
// indicating this error. The distribute device for the volume will just have
// the modified name.
successWarningMessage = String.format("Failed renaming the distributed device %s back " + " to its orginal name %s after reattaching remote mirror", modifiedName, restoreDeviceName);
_log.warn(successWarningMessage);
}
}
// reattached.
if (addVolumeBackToCG) {
ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(vplexVolume);
consistencyGroupManager.addVolumeToCg(cgURI, vplexVolume, client, false);
_log.info("Added volume back to consistency group.");
}
}
}
// Update workflow step state to success.
if (successWarningMessage != null) {
WorkflowStepCompleter.stepSucceeded(stepId, successWarningMessage);
} else {
WorkflowStepCompleter.stepSucceded(stepId);
}
_log.info("Updated workflow step state to success");
} catch (VPlexApiException vae) {
_log.error("Exception in restore/resync volume rollback for VPLEX distributed volume" + vae.getMessage(), vae);
WorkflowStepCompleter.stepFailed(stepId, vae);
} catch (Exception e) {
_log.error("Exception in restore/resync volume rollback for VPLEX distributed volume " + e.getMessage(), e);
WorkflowStepCompleter.stepFailed(stepId, VPlexApiException.exceptions.failedAttachingVPlexVolumeMirror(mirrorDeviceName, vplexVolumeURI.toString(), e));
}
}
Aggregations