use of com.emc.storageos.workflow.Workflow 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.workflow.Workflow in project coprhd-controller by CoprHD.
the class RPDeviceController method addPreRestoreVolumeSteps.
/**
* Adds the necessary RecoverPoint controller steps that need to be executed prior
* to restoring a volume from snapshot. The pre-restore step is required if we
* are restoring a native array snapshot of the following parent volumes:
* <ul>
* <li>A BlockSnapshot parent volume that is a regular RP source/target residing on a VMAX.</li>
* <li>A BlockSnapshot parent volume that is a backing volume to a VPlex distributed volume.</li>
* </ul>
*
* @param workflow
* the Workflow being constructed
* @param storageSystemURI
* the URI of storage controller
* @param volumeURI
* the URI of volume to be restored
* @param snapshotURI
* the URI of snapshot used for restoration
* @param taskId
* the top level operation's taskId
* @return A waitFor key that can be used by subsequent controllers to wait on
*/
public String addPreRestoreVolumeSteps(Workflow workflow, URI storageSystemURI, URI volumeURI, URI snapshotURI, String taskId) {
String waitFor = null;
BlockSnapshot snapshot = _dbClient.queryObject(BlockSnapshot.class, snapshotURI);
// Only consider native snapshots
if (snapshot != null && NullColumnValueGetter.isNotNullValue(snapshot.getTechnologyType()) && snapshot.getTechnologyType().equals(TechnologyType.NATIVE.toString())) {
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, storageSystemURI);
if (volume != null && storageSystem != null) {
boolean vplexDistBackingVolume = false;
URI cgId = volume.getConsistencyGroup();
Volume associatedVPlexVolume = Volume.fetchVplexVolume(_dbClient, volume);
if (associatedVPlexVolume != null && associatedVPlexVolume.getAssociatedVolumes() != null && associatedVPlexVolume.getAssociatedVolumes().size() == 2) {
vplexDistBackingVolume = true;
}
if (vplexDistBackingVolume) {
volume = associatedVPlexVolume;
}
// before performing the native block restore.
if (!NullColumnValueGetter.isNullURI(volume.getProtectionController()) && (vplexDistBackingVolume || (storageSystem != null && NullColumnValueGetter.isNotNullValue(storageSystem.getSystemType()) && storageSystem.getSystemType().equals(SystemType.vmax.toString())))) {
ProtectionSystem rpSystem = null;
rpSystem = _dbClient.queryObject(ProtectionSystem.class, volume.getProtectionController());
if (rpSystem == null) {
// Verify non-null storage device returned from the database client.
throw DeviceControllerExceptions.recoverpoint.failedConnectingForMonitoring(volume.getProtectionController());
}
List<URI> volumeURIs = getVolumesForRestore(snapshot, volume);
// Validate the replication sets for all volumes to restore. Must ensure the source
// volume size is not greater than the target volume size
List<Volume> volumes = _dbClient.queryObject(Volume.class, volumeURIs);
RPHelper.validateRSetVolumeSizes(_dbClient, volumes);
Map<String, RecreateReplicationSetRequestParams> rsetParams = new HashMap<String, RecreateReplicationSetRequestParams>();
// Lock CG
List<String> locks = new ArrayList<String>();
String lockName = ControllerLockingUtil.getConsistencyGroupStorageKey(_dbClient, cgId, rpSystem.getId());
if (null != lockName) {
locks.add(lockName);
acquireWorkflowLockOrThrow(workflow, locks);
}
for (URI volumeId : volumeURIs) {
Volume vol = _dbClient.queryObject(Volume.class, volumeId);
RecreateReplicationSetRequestParams rsetParam = getReplicationSettings(rpSystem, vol.getId());
rsetParams.put(RPHelper.getRPWWn(vol.getId(), _dbClient), rsetParam);
}
String stepId = workflow.createStepId();
Workflow.Method deleteRsetExecuteMethod = new Workflow.Method(METHOD_DELETE_RSET_STEP, rpSystem.getId(), volumeURIs);
Workflow.Method recreateRSetExecuteMethod = new Workflow.Method(METHOD_RECREATE_RSET_STEP, rpSystem.getId(), volumeURIs, rsetParams);
waitFor = workflow.createStep(STEP_PRE_VOLUME_RESTORE, "Pre volume restore from snapshot, delete replication set step for RP: " + volumeURI.toString(), null, rpSystem.getId(), rpSystem.getSystemType(), this.getClass(), deleteRsetExecuteMethod, recreateRSetExecuteMethod, stepId);
_log.info(String.format("Created workflow step to delete replication set for volume %s.", volume.getId().toString()));
}
}
}
return waitFor;
}
use of com.emc.storageos.workflow.Workflow in project coprhd-controller by CoprHD.
the class RPDeviceController method addPostVolumeExpandSteps.
/**
* RP specific workflow steps after volume expansion are added here in this method
* RP CG replication sets that were removed during pre expand are reconstructed with the new expanded volumes.
*
* @param workflow
* @param waitFor
* @param volume
* descriptors
* @param taskId
* @return
* @throws WorkflowException
*/
public String addPostVolumeExpandSteps(Workflow workflow, String waitFor, List<VolumeDescriptor> volumeDescriptors, String taskId) throws WorkflowException {
// Get only the RP volumes from the descriptors.
List<VolumeDescriptor> volumeDescriptorsTypeFilter = VolumeDescriptor.filterByType(volumeDescriptors, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.RP_SOURCE, VolumeDescriptor.Type.RP_EXISTING_SOURCE, VolumeDescriptor.Type.RP_VPLEX_VIRT_SOURCE }, new VolumeDescriptor.Type[] {});
// If there are no RP volumes, just return
if (volumeDescriptorsTypeFilter.isEmpty()) {
return waitFor;
}
for (VolumeDescriptor descriptor : volumeDescriptorsTypeFilter) {
Volume volume = _dbClient.queryObject(Volume.class, descriptor.getVolumeURI());
ProtectionSystem rpSystem = _dbClient.queryObject(ProtectionSystem.class, volume.getProtectionController());
Map<String, RecreateReplicationSetRequestParams> rsetParams = new HashMap<String, RecreateReplicationSetRequestParams>();
RecreateReplicationSetRequestParams rsetParam = getReplicationSettings(rpSystem, volume.getId());
rsetParams.put(RPHelper.getRPWWn(volume.getId(), _dbClient), rsetParam);
String stepId = workflow.createStepId();
Workflow.Method recreateRSetExecuteMethod = new Workflow.Method(METHOD_RECREATE_RSET_STEP, rpSystem.getId(), Arrays.asList(volume.getId()), rsetParams);
workflow.createStep(STEP_POST_VOLUME_EXPAND, "Post volume Expand, Recreate replication set subtask for RP: " + volume.toString(), waitFor, rpSystem.getId(), rpSystem.getSystemType(), this.getClass(), recreateRSetExecuteMethod, null, stepId);
_log.info("Recreate Replication Set in workflow");
}
return STEP_POST_VOLUME_EXPAND;
}
use of com.emc.storageos.workflow.Workflow in project coprhd-controller by CoprHD.
the class RPDeviceController method addPostRestoreFromFullcopySteps.
/**
* Adds the necessary RecoverPoint controller steps that need to be executed after
* restoring a volume from full copy. The post-restore step is required if we
* are restoring a VPLEX full copy, whoes source volume is a distributed VPLEX volume
* or a VMAX volume
*
* @param workflow
* the Workflow being constructed
* @param waitFor
* the step that the newly created steps will wait for.
* @param storageSystemURI
* the URI of storage controller
* @param fullCopies
* the URI of full copies to restore
* @param taskId
* the top level operation's taskId
* @return A waitFor key that can be used by subsequent controllers to wait on
*/
public String addPostRestoreFromFullcopySteps(Workflow workflow, String waitFor, URI storageSystemURI, List<URI> fullCopies, String taskId) {
if (fullCopies != null && !fullCopies.isEmpty()) {
List<Volume> sourceVolumes = checkIfDistributedVplexOrVmaxFullCopies(fullCopies);
if (!sourceVolumes.isEmpty()) {
Map<String, RecreateReplicationSetRequestParams> rsetParams = new HashMap<String, RecreateReplicationSetRequestParams>();
List<URI> volumeURIs = new ArrayList<URI>();
URI rpSystemId = sourceVolumes.get(0).getProtectionController();
ProtectionSystem rpSystem = _dbClient.queryObject(ProtectionSystem.class, rpSystemId);
for (Volume vol : sourceVolumes) {
RecreateReplicationSetRequestParams rsetParam = getReplicationSettings(rpSystem, vol.getId());
rsetParams.put(RPHelper.getRPWWn(vol.getId(), _dbClient), rsetParam);
volumeURIs.add(vol.getId());
}
String stepId = workflow.createStepId();
Workflow.Method recreateRSetExecuteMethod = new Workflow.Method(METHOD_RECREATE_RSET_STEP, rpSystemId, volumeURIs, rsetParams);
waitFor = workflow.createStep(STEP_PRE_VOLUME_RESTORE, "Post volume restore from full copy, add replication set step for RP", waitFor, rpSystemId, rpSystem.getSystemType(), this.getClass(), recreateRSetExecuteMethod, rollbackMethodNullMethod(), stepId);
_log.info("Created workflow step to recreate replication set for volumes");
}
}
return waitFor;
}
use of com.emc.storageos.workflow.Workflow in project coprhd-controller by CoprHD.
the class RPDeviceController method addRemoveProtectionOnVolumeStep.
/**
* Step to remove protection on RP Source volumes
*
* @param workflow
* The current WF
* @param waitFor
* The previous waitFor step ID or Group
* @param volumeDescriptors
* RP Source volume descriptors
* @param taskId
* The Task ID
* @param blockDeviceController
* Reference to a BlockDeviceController, used for specific steps on
* the volumes not covered by RP but required for the operation to be complete.
* @return The next waitFor step ID or Group
*/
private String addRemoveProtectionOnVolumeStep(Workflow workflow, String waitFor, List<VolumeDescriptor> volumeDescriptors, String taskId, BlockDeviceController blockDeviceController) {
List<URI> volumeURIs = new ArrayList<URI>();
URI newVpoolURI = null;
// Filter to get only the RP Source volumes.
List<VolumeDescriptor> rpSourceDescriptors = VolumeDescriptor.filterByType(volumeDescriptors, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.RP_SOURCE, VolumeDescriptor.Type.RP_VPLEX_VIRT_SOURCE }, new VolumeDescriptor.Type[] {});
for (VolumeDescriptor descriptor : rpSourceDescriptors) {
if (descriptor.getParameters().get(VolumeDescriptor.PARAM_DO_NOT_DELETE_VOLUME) != null) {
// This is a rollback protection operation. We do not want to delete the volume but we do
// want to remove protection from it.
newVpoolURI = (URI) descriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_NEW_VPOOL_ID);
_log.info(String.format("Adding step to remove protection from Volume (%s) and move it to vpool (%s)", descriptor.getVolumeURI(), newVpoolURI));
volumeURIs.add(descriptor.getVolumeURI());
}
}
if (volumeURIs.isEmpty()) {
return waitFor;
}
// Filter to get only the Block Data volumes
List<VolumeDescriptor> blockDataDescriptors = VolumeDescriptor.filterByType(volumeDescriptors, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.BLOCK_DATA }, new VolumeDescriptor.Type[] {});
// Check to see if there are any BLOCK_DATA volumes flagged to not be fully deleted.
// These volumes could potentially need to have some untag operation performed
// on the underlying array even though they won't be deleted.
List<VolumeDescriptor> doNotDeleteDescriptors = VolumeDescriptor.getDoNotDeleteDescriptors(blockDataDescriptors);
// Breakup the descriptors further into RP and RP+VPLEX descriptors
List<VolumeDescriptor> rpDescriptors = new ArrayList<VolumeDescriptor>();
List<VolumeDescriptor> rpVPlexDescriptors = new ArrayList<VolumeDescriptor>();
for (VolumeDescriptor descr : doNotDeleteDescriptors) {
Volume volume = _dbClient.queryObject(Volume.class, descr.getVolumeURI());
// Check to see if this volume is associated to a RP+VPLEX Source volume.
if (RPHelper.isAssociatedToRpVplexType(volume, _dbClient, PersonalityTypes.SOURCE)) {
rpVPlexDescriptors.add(descr);
} else {
rpDescriptors.add(descr);
}
}
if (doNotDeleteDescriptors != null && !doNotDeleteDescriptors.isEmpty()) {
// Call the BlockDeviceController to perform untag operations on the volumes.
// NOTE: Only needed for RP volumes.
waitFor = blockDeviceController.addStepsForUntagVolumes(workflow, waitFor, rpDescriptors, taskId);
// Call the BlockDeviceController to remove the volumes from any backend array CGs.
// NOTE: Only needed for RP+VPLEX/MP volumes.
waitFor = blockDeviceController.addStepsForUpdateConsistencyGroup(workflow, waitFor, null, rpVPlexDescriptors);
}
// Grab any volume from the list so we can grab the protection system. This
// request could be over multiple protection systems but we don't really
// care at this point. We just need this reference to pass into the
// WorkFlow.
Volume volume = _dbClient.queryObject(Volume.class, volumeURIs.get(0));
ProtectionSystem rpSystem = _dbClient.queryObject(ProtectionSystem.class, volume.getProtectionController());
String stepId = workflow.createStepId();
Workflow.Method removeProtectionExecuteMethod = new Workflow.Method(METHOD_REMOVE_PROTECTION_STEP, volumeURIs, newVpoolURI);
workflow.createStep(STEP_REMOVE_PROTECTION, "Remove RP protection on volume(s)", waitFor, rpSystem.getId(), rpSystem.getSystemType(), this.getClass(), removeProtectionExecuteMethod, null, stepId);
return STEP_REMOVE_PROTECTION;
}
Aggregations