use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeVpoolChangeTaskCompleter in project coprhd-controller by CoprHD.
the class RPDeviceController method updateConsistencyGroupPolicy.
@Override
public void updateConsistencyGroupPolicy(URI protectionDevice, URI consistencyGroup, List<URI> volumeURIs, URI newVpoolURI, String task) throws InternalException {
_log.info(String.format("Request to update consistency group policy for volumes %s through virtual pool change to %s", volumeURIs, newVpoolURI));
VolumeVpoolChangeTaskCompleter taskCompleter = null;
URI oldVpoolURI = null;
List<Volume> volumes = new ArrayList<Volume>();
List<Volume> vplexBackendVolumes = new ArrayList<Volume>();
try {
// Get all CG source volumes. The entire CG policy is being updated so we
// need to capture the existing vpools for all the source volumes before
// changing them.
List<Volume> cgVolumes = RPHelper.getCgSourceVolumes(consistencyGroup, _dbClient);
VirtualPool newVpool = _dbClient.queryObject(VirtualPool.class, newVpoolURI);
Map<URI, URI> oldVpools = new HashMap<URI, URI>();
for (Volume volume : cgVolumes) {
// Save the old virtual pool
oldVpoolURI = volume.getVirtualPool();
oldVpools.put(volume.getId(), oldVpoolURI);
// Update to the new virtual pool
volume.setVirtualPool(newVpoolURI);
volumes.add(volume);
// If this is a VPlex volume, there will be
StringSet associatedVolumeIds = volume.getAssociatedVolumes();
// Perform additional tasks if this volume is a VPlex volume
if (associatedVolumeIds != null && !associatedVolumeIds.isEmpty()) {
Volume backendSrc = null;
Volume backendHa = null;
for (String associatedVolumeId : associatedVolumeIds) {
Volume associatedVolume = _dbClient.queryObject(Volume.class, URI.create(associatedVolumeId));
// Assign the associated volumes to either be the source or HA
if (associatedVolume != null) {
if (associatedVolume.getVirtualArray().equals(volume.getVirtualArray())) {
backendSrc = associatedVolume;
} else {
backendHa = associatedVolume;
}
}
}
if (backendSrc != null) {
// Change the back end volume's vPool too
backendSrc.setVirtualPool(newVpoolURI);
vplexBackendVolumes.add(backendSrc);
_log.info(String.format("Changing VirtualPool for VPLEX backend source volume %s (%s) from %s to %s", backendSrc.getLabel(), backendSrc.getId(), oldVpoolURI, newVpoolURI));
if (backendHa != null) {
VirtualPool newHAVpool = VirtualPool.getHAVPool(newVpool, _dbClient);
if (newHAVpool == null) {
// it may not be set
newHAVpool = newVpool;
}
backendHa.setVirtualPool(newHAVpool.getId());
vplexBackendVolumes.add(backendHa);
}
}
}
}
_dbClient.updateObject(volumes);
_dbClient.updateObject(vplexBackendVolumes);
// The VolumeVpoolChangeTaskCompleter will restore the old Virtual Pool
taskCompleter = new VolumeVpoolChangeTaskCompleter(volumeURIs, oldVpools, task);
} catch (Exception ex) {
_log.error("Unexpected exception reading volume or generating taskCompleter: ", ex);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(ex);
VolumeWorkflowCompleter completer = new VolumeWorkflowCompleter(volumeURIs, task);
completer.error(_dbClient, serviceError);
}
try {
Workflow workflow = _workflowService.getNewWorkflow(this, "updateReplicationMode", false, task);
ProtectionSystem protectionSystem = _dbClient.queryObject(ProtectionSystem.class, protectionDevice);
if (!volumes.isEmpty()) {
VirtualPool newVirtualPool = _dbClient.queryObject(VirtualPool.class, newVpoolURI);
// Add workflow step
addUpdateConsistencyGroupPolicyStep(workflow, protectionSystem, consistencyGroup, newVirtualPool.getRpCopyMode());
}
if (!workflow.getAllStepStatus().isEmpty()) {
_log.info("The updateAutoTieringPolicy workflow has {} step(s). Starting the workflow.", workflow.getAllStepStatus().size());
workflow.executePlan(taskCompleter, "Updated the consistency group policy successfully.");
} else {
taskCompleter.ready(_dbClient);
}
} catch (Exception ex) {
_log.error("Unexpected exception: ", ex);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(ex);
taskCompleter.error(_dbClient, serviceError);
}
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeVpoolChangeTaskCompleter in project coprhd-controller by CoprHD.
the class BlockDeviceExportController method updateVolumePathParams.
@Override
public void updateVolumePathParams(URI volumeURI, URI newVpoolURI, String opId) throws ControllerException {
_log.info("Received request to update Volume path parameters. Creating master workflow.");
VolumeVpoolChangeTaskCompleter taskCompleter = null;
Volume volume = null;
try {
// Read volume from database, update the Vpool to the new completer, and create task completer.
volume = _dbClient.queryObject(Volume.class, volumeURI);
URI oldVpoolURI = volume.getVirtualPool();
List<URI> rollbackList = new ArrayList<URI>();
List<Volume> updatedVolumes = new ArrayList<Volume>();
rollbackList.add(volumeURI);
// Check if it is a VPlex volume, and get backend volumes
Volume backendSrc = VPlexUtil.getVPLEXBackendVolume(volume, true, _dbClient, false);
if (backendSrc != null) {
// Change the back end volume's vpool too
backendSrc.setVirtualPool(newVpoolURI);
rollbackList.add(backendSrc.getId());
updatedVolumes.add(backendSrc);
// VPlex volume, check if it is distributed
Volume backendHa = VPlexUtil.getVPLEXBackendVolume(volume, false, _dbClient, false);
if (backendHa != null && backendHa.getVirtualPool() != null && backendHa.getVirtualPool().toString().equals(oldVpoolURI.toString())) {
backendHa.setVirtualPool(newVpoolURI);
rollbackList.add(backendHa.getId());
updatedVolumes.add(backendHa);
}
}
// The VolumeVpoolChangeTaskCompleter will restore the old Virtual Pool in event of error.
taskCompleter = new VolumeVpoolChangeTaskCompleter(rollbackList, oldVpoolURI, opId);
volume.setVirtualPool(newVpoolURI);
updatedVolumes.add(volume);
_log.info(String.format("Changing VirtualPool PathParams for volume %s (%s) from %s to %s", volume.getLabel(), volume.getId(), oldVpoolURI, newVpoolURI));
_dbClient.updateObject(updatedVolumes);
} catch (Exception ex) {
_log.error("Unexpected exception reading volume or generating taskCompleter: ", ex);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(ex);
VolumeWorkflowCompleter completer = new VolumeWorkflowCompleter(volumeURI, opId);
completer.error(_dbClient, serviceError);
}
try {
Workflow workflow = _wfUtils.newWorkflow("updateVolumePathParams", false, opId);
// Locate all the ExportMasks containing the given volume, and their Export Group.
Map<ExportMask, ExportGroup> maskToGroupMap = ExportUtils.getExportMasks(volume, _dbClient);
Map<URI, StringSetMap> maskToZoningMap = new HashMap<URI, StringSetMap>();
// Store the original zoning maps of the export masks to be used to restore in case of a failure
for (ExportMask mask : maskToGroupMap.keySet()) {
maskToZoningMap.put(mask.getId(), mask.getZoningMap());
}
taskCompleter.setMaskToZoningMap(maskToZoningMap);
// Acquire all necessary locks for the workflow:
// For each export group lock initiator's hosts and storage array keys.
List<URI> initiatorURIs = new ArrayList<URI>();
for (ExportGroup exportGroup : maskToGroupMap.values()) {
initiatorURIs.addAll(StringSetUtil.stringSetToUriList(exportGroup.getInitiators()));
List<String> lockKeys = ControllerLockingUtil.getHostStorageLockKeys(_dbClient, ExportGroup.ExportGroupType.valueOf(exportGroup.getType()), initiatorURIs, volume.getStorageController());
initiatorURIs.clear();
boolean acquiredLocks = _wfUtils.getWorkflowService().acquireWorkflowLocks(workflow, lockKeys, LockTimeoutValue.get(LockType.EXPORT_GROUP_OPS));
if (!acquiredLocks) {
throw DeviceControllerException.exceptions.failedToAcquireLock(lockKeys.toString(), "UpdateVolumePathParams: " + volume.getLabel());
}
}
// These steps are serialized, which is required in case an ExportMask appears
// in multiple Export Groups.
String stepId = null;
for (ExportGroup exportGroup : maskToGroupMap.values()) {
stepId = _wfUtils.generateExportChangePathParams(workflow, "changePathParams", stepId, volume.getStorageController(), exportGroup.getId(), volumeURI);
}
if (!workflow.getAllStepStatus().isEmpty()) {
_log.info("The updateVolumePathParams workflow has {} steps. Starting the workflow.", workflow.getAllStepStatus().size());
workflow.executePlan(taskCompleter, "Update the export group on all storage systems successfully.");
} else {
taskCompleter.ready(_dbClient);
}
} catch (Exception ex) {
_log.error("Unexpected exception: ", ex);
ServiceError serviceError = DeviceControllerException.errors.jobFailed(ex);
taskCompleter.error(_dbClient, serviceError);
}
}
use of com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeVpoolChangeTaskCompleter in project coprhd-controller by CoprHD.
the class BlockOrchestrationDeviceController method changeVirtualPool.
/*
* (non-Javadoc)
*
* @see
* com.emc.storageos.blockorchestrationcontroller.BlockOrchestrationController#changeVirtualPool(java.util.List,
* java.lang.String)
*/
@Override
public void changeVirtualPool(List<VolumeDescriptor> volumes, String taskId) throws ControllerException {
Map<URI, URI> volumeToOldVpoolsMap = VolumeDescriptor.createVolumeToOldVpoolMap(volumes);
Map<URI, URI> volumeToNewVpoolsMap = VolumeDescriptor.createVolumeToNewVpoolMap(volumes);
List<URI> volURIs = VolumeDescriptor.getVolumeURIs(volumes);
List<URI> cgIds = null;
List<URI> migrationURIs = new ArrayList<URI>();
for (VolumeDescriptor desc : volumes) {
URI migrationURI = desc.getMigrationId();
if (!NullColumnValueGetter.isNullURI(migrationURI)) {
migrationURIs.add(migrationURI);
}
cgIds = Volume.fetchCgIds(s_dbClient, volURIs);
}
VolumeVpoolChangeTaskCompleter completer = new VolumeVpoolChangeTaskCompleter(volURIs, migrationURIs, volumeToOldVpoolsMap, volumeToNewVpoolsMap, taskId);
try {
// Validate the volume identities before proceeding
validator.volumeURIs(volURIs, true, true, ValCk.ID, ValCk.VPLEX);
// Generate the Workflow.
Workflow workflow = _workflowService.getNewWorkflow(this, CHANGE_VPOOL_WF_NAME, true, taskId, completer);
// the wait for key returned by previous call
String waitFor = null;
// Mainly for RP+VPLEX as a change vpool would require new volumes (source-journal, target(s),
// target-journal) to be created.
waitFor = _blockDeviceController.addStepsForCreateVolumes(workflow, waitFor, volumes, taskId);
// Call the VPlexDeviceController to add change virtual pool steps.
waitFor = _vplexDeviceController.addStepsForChangeVirtualPool(workflow, waitFor, volumes, taskId);
// Last, call the RPDeviceController to add change virtual pool steps.
waitFor = _rpDeviceController.addStepsForChangeVirtualPool(workflow, waitFor, volumes, taskId);
// This step is currently used to ensure that any existing resources get added to native
// CGs. Mainly used for VPLEX->RP+VPLEX change vpool. The existing VPLEX volume would not be
// in any CG and we now need its backing volume(s) to be added to their local array CG.
waitFor = postRPChangeVpoolSteps(workflow, waitFor, volumes, taskId);
// Finish up and execute the plan.
// The Workflow will handle the TaskCompleter
String successMessage = "Change Virtual Pool suceeded for volumes: " + volURIs.toString();
Object[] callbackArgs = new Object[] { volURIs };
workflow.executePlan(completer, successMessage, new WorkflowCallback(), callbackArgs, null, null);
} catch (Exception ex) {
s_logger.error("Could not change Virtual Pool for volumes: " + volURIs, ex);
String opName = ResourceOperationTypeEnum.CHANGE_BLOCK_VOLUME_VPOOL.getName();
ServiceError serviceError = DeviceControllerException.errors.changeVirtualPoolFailed(volURIs.toString(), opName, ex);
completer.error(s_dbClient, _locker, serviceError);
}
}
Aggregations