Search in sources :

Example 81 with TaskCompleter

use of com.emc.storageos.volumecontroller.TaskCompleter in project coprhd-controller by CoprHD.

the class SRDFOperations method rollbackSRDFMirror.

private void rollbackSRDFMirror(StorageSystem system, final Volume source, final Volume target, boolean isGrouprollback, boolean isVpoolChange, final SRDFMirrorRollbackCompleter completer) {
    log.info("START Rolling back SRDF mirror");
    try {
        /*
             * In order to help the user with any potential cleanup, use this anonymous task completer to update the
             * rollback completer on whether or not a detach was successful for this source/target pair.
             */
        TaskCompleter inspect = new TaskCompleter() {

            @Override
            protected void complete(DbClient dbClient, Operation.Status status, ServiceCoded coded) throws DeviceControllerException {
                completer.addRollbackStatus(source, target, status, coded);
            }
        };
        performDetach(system, target, isGrouprollback, inspect);
        if (target.hasConsistencyGroup()) {
            log.info("Removing Volume from device Group on roll back");
            removeDeviceGroups(system, source.getId(), target.getId(), isVpoolChange, null);
        }
    } catch (Exception e) {
        String msg = format(FAILURE_MSG_FMT, "rollback", source.getId(), target.getId());
        log.warn(msg, e);
        // Re-throw in order to cleanup any CG and RDFG.
        throw e;
    }
}
Also used : LinkStatus(com.emc.storageos.db.client.model.Volume.LinkStatus) DbClient(com.emc.storageos.db.client.DbClient) ServiceCoded(com.emc.storageos.svcs.errorhandling.model.ServiceCoded) SRDFChangeCopyModeTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.SRDFChangeCopyModeTaskCompleter) TaskCompleter(com.emc.storageos.volumecontroller.TaskCompleter) SRDFTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.SRDFTaskCompleter) RemoteGroupAssociationNotFoundException(com.emc.storageos.volumecontroller.impl.smis.srdf.exceptions.RemoteGroupAssociationNotFoundException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) WBEMException(javax.wbem.WBEMException) NoSynchronizationsFoundException(com.emc.storageos.volumecontroller.impl.smis.srdf.exceptions.NoSynchronizationsFoundException)

Example 82 with TaskCompleter

use of com.emc.storageos.volumecontroller.TaskCompleter in project coprhd-controller by CoprHD.

the class SmisCommandHelper method waitForAsyncSmisJob.

private void waitForAsyncSmisJob(StorageSystem storageDevice, CIMObjectPath cimJobPath, SmisJob job) throws SmisException {
    if (job == null) {
        TaskCompleter taskCompleter = new TaskCompleter() {

            @Override
            public void ready(DbClient dbClient) throws DeviceControllerException {
            }

            @Override
            public void error(DbClient dbClient, ServiceCoded serviceCoded) throws DeviceControllerException {
            }

            @Override
            protected void complete(DbClient dbClient, Operation.Status status, ServiceCoded coded) throws DeviceControllerException {
            }
        };
        job = new SmisJob(cimJobPath, storageDevice.getId(), taskCompleter, "");
    } else {
        job.setCimJob(cimJobPath);
    }
    JobContext jobContext = new JobContext(_dbClient, _cimConnection, null, null, null, null, this);
    long startTime = System.currentTimeMillis();
    int sync_wrapper_time_out = InvokeTestFailure.internalOnlyOverrideSyncWrapperTimeOut(SYNC_WRAPPER_TIME_OUT);
    while (true) {
        JobPollResult result = job.poll(jobContext, SYNC_WRAPPER_WAIT);
        if (!result.isJobInTerminalState()) {
            if (System.currentTimeMillis() - startTime > sync_wrapper_time_out) {
                throw new SmisException("Timed out waiting on smis job to complete after " + (System.currentTimeMillis() - startTime) + " milliseconds");
            } else {
                try {
                    Thread.sleep(SYNC_WRAPPER_WAIT);
                } catch (InterruptedException e) {
                    _log.error("Thread waiting for smis job to complete was interrupted and " + "will be resumed");
                }
            }
        } else {
            if (result.isJobInTerminalFailedState()) {
                throw new SmisException("Smis job failed: " + result.getErrorDescription());
            }
            break;
        }
    }
}
Also used : LinkStatus(com.emc.storageos.db.client.model.Volume.LinkStatus) DbClient(com.emc.storageos.db.client.DbClient) ServiceCoded(com.emc.storageos.svcs.errorhandling.model.ServiceCoded) TaskCompleter(com.emc.storageos.volumecontroller.TaskCompleter) SmisJob(com.emc.storageos.volumecontroller.impl.smis.job.SmisJob) JobContext(com.emc.storageos.volumecontroller.JobContext) JobPollResult(com.emc.storageos.volumecontroller.impl.JobPollResult) AlternateIdConstraint(com.emc.storageos.db.client.constraint.AlternateIdConstraint)

Example 83 with TaskCompleter

use of com.emc.storageos.volumecontroller.TaskCompleter in project coprhd-controller by CoprHD.

the class VPlexDeviceController method addStepsForRemoveInitiators.

/**
 * Add steps necessary for Export removeInitiators.
 * This routine may be called multiple times for an Export Group on each
 * exportMask that needs to be adjusted.
 *
 * @param vplex
 *            -- StorageSystem VPLEX
 * @param workflow
 *            -- Workflow steps being added to
 * @param exportGroup
 *            -- ExportGroup
 * @param exportMask
 *            -- ExportMask being processed
 * @param initiators
 *            -- List<Initiator> initiators being removed
 * @param hostURI
 *            -- Host URI
 * @param hostInitiatorURIs
 *            -- list of Host Initiators
 * @param errorMessages
 *            -- collector for any validation-related error messages
 * @param previousStep
 *            -- previous step to wait on
 * @return String last step added to workflow; null if no steps added
 * @throws Exception
 */
private String addStepsForRemoveInitiators(StorageSystem vplex, Workflow workflow, ExportRemoveInitiatorCompleter completer, ExportGroup exportGroup, ExportMask exportMask, List<Initiator> initiators, URI hostURI, List<URI> initiatorsAlreadyRemovedFromExportGroup, StringBuffer errorMessages, String previousStep) throws Exception {
    String lastStep = previousStep;
    // assemble a list of other ExportGroups that reference this ExportMask
    List<ExportGroup> otherExportGroups = ExportUtils.getOtherExportGroups(exportGroup, exportMask, _dbClient);
    _log.info(String.format("will be removing initiators %s for host %s mask %s (%s)", getInitiatorsWwnsString(initiators), hostURI.toString(), exportMask.getMaskName(), exportMask.getId()));
    List<URI> hostInitiatorURIs = new ArrayList<URI>();
    List<URI> removeInitiatorListURIs = new ArrayList<URI>();
    for (Initiator initiator : initiators) {
        // contained within this ExportMask (CTRL-12300)
        if (exportMask.hasInitiator(initiator.getId().toString())) {
            hostInitiatorURIs.add(initiator.getId());
        }
        // removeInitiatorListURIs is created to pass it to next method name addStepsForInitiatorRemoval
        // we have filtering logic placed inside addStepsForInitiatorRemoval to take care of it.
        removeInitiatorListURIs.add(initiator.getId());
    }
    // Determine the targets we should remove for the initiators being removed.
    // Normally one or more targets will be removed for each initiator that
    // is removed according to the zoning map.
    List<URI> targetURIs = getTargetURIs(exportMask, hostInitiatorURIs);
    _log.info(String.format("will be removing targets %s for host %s", targetURIs.toString(), hostURI.toString()));
    // What is about to happen...
    // 
    // 1. if all the initiators in the storage view are getting removed
    // and there are no existing (external) initiators in the Export Mask
    // then delete the storage view
    // 
    // 2. if there are other ExportGroups referencing this ExportMask
    // AND
    // if there are no more of this ExportMask's initiators present
    // in this ExportGroup's initiators
    // THEN
    // remove this ExportGroup's volumes
    // that aren't also present in other ExportGroups
    // from this ExportMask
    // AND FINALLY
    // remove the initiator(s) from the ExportGroup
    // but NOT from the ExportMask
    // (because other ExportGroups are referencing it still)
    // 
    // 3. otherwise,
    // just remove initiators from the storage view, and if removing
    // all initiators, also remove any volumes present in the ExportGroup
    boolean removeAllInits = (hostInitiatorURIs.size() >= exportMask.getInitiators().size());
    boolean canDeleteMask = removeAllInits && !exportMask.hasAnyExistingInitiators();
    if (canDeleteMask) {
        if (!ExportUtils.exportMaskHasBothExclusiveAndSharedVolumes(exportGroup, otherExportGroups, exportMask)) {
            _log.info("all initiators are being removed and no " + "other ExportGroups reference ExportMask {}", exportMask.getMaskName());
            _log.info("creating a deleteStorageView workflow step for " + exportMask.getMaskName());
            String exportMaskDeleteStep = workflow.createStepId();
            Workflow.Method storageViewExecuteMethod = deleteStorageViewMethod(vplex.getId(), exportGroup.getId(), exportMask.getId(), false);
            lastStep = workflow.createStep(DELETE_STORAGE_VIEW, String.format("Delete VPLEX Storage View %s for ExportGroup %s", exportMask.getMaskName(), exportGroup.getId()), lastStep, vplex.getId(), vplex.getSystemType(), this.getClass(), storageViewExecuteMethod, null, exportMaskDeleteStep);
            // Add zoning step for deleting ExportMask
            List<NetworkZoningParam> zoningParam = NetworkZoningParam.convertExportMasksToNetworkZoningParam(exportGroup.getId(), Collections.singletonList(exportMask.getId()), _dbClient);
            Workflow.Method zoneMaskDeleteMethod = _networkDeviceController.zoneExportMasksDeleteMethod(zoningParam, StringSetUtil.stringSetToUriList(exportMask.getVolumes().keySet()));
            Workflow.Method zoneNullRollbackMethod = _networkDeviceController.zoneNullRollbackMethod();
            lastStep = workflow.createStep(null, "Zone delete mask: " + exportMask.getMaskName(), lastStep, nullURI, "network-system", _networkDeviceController.getClass(), zoneMaskDeleteMethod, zoneNullRollbackMethod, null);
        } else {
            // export Mask has shared and exclusive volumes, removing the volumes.
            // The volumes can be taken from the export Group
            List<URI> volumeURIList = URIUtil.toURIList(exportGroup.getVolumes().keySet());
            if (!volumeURIList.isEmpty()) {
                List<Volume> volumes = _dbClient.queryObject(Volume.class, volumeURIList);
                String volumesForDisplay = Joiner.on(", ").join(Collections2.transform(volumes, CommonTransformerFunctions.fctnDataObjectToForDisplay()));
                _log.info("there are some volumes that need to be removed: " + volumesForDisplay);
                _log.info("creating a remove volumes workflow step with " + exportMask.getMaskName() + " for volumes " + CommonTransformerFunctions.collectionToString(volumeURIList));
                completer.addExportMaskToRemovedVolumeMapping(exportMask.getId(), volumeURIList);
                TaskCompleter taskCompleter = new ExportMaskRemoveVolumeCompleter(exportGroup.getId(), exportMask.getId(), volumeURIList, lastStep);
                Workflow.Method storageViewRemoveVolume = storageViewRemoveVolumesMethod(vplex.getId(), exportGroup.getId(), exportMask.getId(), volumeURIList, lastStep, taskCompleter, null);
                lastStep = 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()), lastStep, 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);
                lastStep = workflow.createStep(null, "Zone remove volumes mask: " + exportMask.getMaskName(), lastStep, nullURI, "network-system", _networkDeviceController.getClass(), zoneRemoveVolumesMethod, _networkDeviceController.zoneNullRollbackMethod(), null);
            }
        }
    } else {
        // this is just a simple initiator removal, so just do it...
        lastStep = addStepsForInitiatorRemoval(vplex, workflow, completer, exportGroup, exportMask, removeInitiatorListURIs, targetURIs, lastStep, removeAllInits, hostURI, errorMessages);
    }
    return lastStep;
}
Also used : ArrayList(java.util.ArrayList) Workflow(com.emc.storageos.workflow.Workflow) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) NetworkZoningParam(com.emc.storageos.networkcontroller.impl.NetworkZoningParam) ExportGroup(com.emc.storageos.db.client.model.ExportGroup) Initiator(com.emc.storageos.db.client.model.Initiator) Volume(com.emc.storageos.db.client.model.Volume) ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) MigrationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationTaskCompleter) CloneTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.CloneTaskCompleter) MigrationOperationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationOperationTaskCompleter) CacheStatusTaskCompleter(com.emc.storageos.vplexcontroller.completers.CacheStatusTaskCompleter) VplexMirrorTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VplexMirrorTaskCompleter) VolumeTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeTaskCompleter) VolumeGroupUpdateTaskCompleter(com.emc.storageos.vplexcontroller.completers.VolumeGroupUpdateTaskCompleter) TaskCompleter(com.emc.storageos.volumecontroller.TaskCompleter) WorkflowTaskCompleter(com.emc.storageos.workflow.WorkflowTaskCompleter) ExportMaskRemoveVolumeCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportMaskRemoveVolumeCompleter)

Example 84 with TaskCompleter

use of com.emc.storageos.volumecontroller.TaskCompleter in project coprhd-controller by CoprHD.

the class VPlexDeviceController method restoreVolume.

/**
 * {@inheritDoc}
 */
@Override
public void restoreVolume(URI vplexURI, URI snapshotURI, String opId) throws InternalException {
    BlockSnapshot snapshot = getDataObject(BlockSnapshot.class, snapshotURI, _dbClient);
    try {
        // Generate the Workflow.
        Workflow workflow = _workflowService.getNewWorkflow(this, RESTORE_VOLUME_WF_NAME, false, opId);
        _log.info("Created restore volume workflow with operation id {}", opId);
        // Get some info from the snapshot we need to do the native
        // restore of the backend volume. Note that if the snapshot
        // is associated with a CG, then all backend volumes in the
        // CG will be restored using their corresponding snapshots,
        // meaning the VPLEX volumes using those backend volumes
        // will be restored.
        URI parentSystemURI = snapshot.getStorageController();
        StorageSystem parentSystem = getDataObject(StorageSystem.class, parentSystemURI, _dbClient);
        URI parentVolumeURI = snapshot.getParent().getURI();
        Volume parentVolume = getDataObject(Volume.class, parentVolumeURI, _dbClient);
        URI parentPoolURI = parentVolume.getPool();
        // Get the VPLEX system.
        StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        // Get the VPLEX volume(s) to be restored.
        List<URI> vplexVolumeURIs = new ArrayList<URI>();
        URI cgURI = snapshot.getConsistencyGroup();
        if (NullColumnValueGetter.isNullURI(cgURI)) {
            // If the snapshot is not in a CG, the only VPLEX
            // volume to restore is the VPLEX volume using the
            // snapshot parent.
            URIQueryResultList queryResults = new URIQueryResultList();
            _dbClient.queryByConstraint(AlternateIdConstraint.Factory.getVolumeByAssociatedVolumesConstraint(parentVolumeURI.toString()), queryResults);
            URI vplexVolumeURI = queryResults.iterator().next();
            vplexVolumeURIs.add(vplexVolumeURI);
        } else {
            // Otherwise, get all snapshots in the snapset, get the
            // parent volume for each snapshot, and get the VLPEX
            // volume using the snapshot parent.
            List<BlockSnapshot> cgSnaps = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshot, _dbClient);
            for (BlockSnapshot cgSnapshot : cgSnaps) {
                URIQueryResultList queryResults = new URIQueryResultList();
                _dbClient.queryByConstraint(AlternateIdConstraint.Factory.getVolumeByAssociatedVolumesConstraint(cgSnapshot.getParent().getURI().toString()), queryResults);
                URI vplexVolumeURI = queryResults.iterator().next();
                vplexVolumeURIs.add(vplexVolumeURI);
            }
        }
        // The workflow depends on if the VPLEX volumes are local
        // or distributed.
        String waitFor = null;
        Volume firstVplexVolume = getDataObject(Volume.class, vplexVolumeURIs.get(0), _dbClient);
        if (null == firstVplexVolume.getAssociatedVolumes() || firstVplexVolume.getAssociatedVolumes().isEmpty()) {
            _log.error("VPLEX volume {} has no backend volumes.", firstVplexVolume.forDisplay());
            throw InternalServerErrorException.internalServerErrors.noAssociatedVolumesForVPLEXVolume(firstVplexVolume.forDisplay());
        }
        boolean isLocal = firstVplexVolume.getAssociatedVolumes().size() == 1;
        if (isLocal) {
            // VPLEX volume.
            for (URI vplexVolumeURI : vplexVolumeURIs) {
                waitFor = createWorkflowStepForInvalidateCache(workflow, vplexSystem, vplexVolumeURI, null, null);
            }
            // Now create a workflow step to natively restore the backend
            // volume from the passed snapshot. Note that if the snapshot
            // is associated with a CG, then block controller will restore
            // all backend volumes in the CG using their corresponding
            // snapshots. We execute this after the invalidate cache. We
            // could execute these in parallel for a little better efficiency,
            // but what if the invalidate cache fails, but the restore succeeds,
            // the cache now has invalid data and a cache read hit could return
            // invalid data.
            createWorkflowStepForRestoreNativeSnapshot(workflow, parentSystem, parentVolumeURI, snapshotURI, parentPoolURI, waitFor, null);
        } else {
            for (URI vplexVolumeURI : vplexVolumeURIs) {
                // For distributed volumes we take snapshots of and restore the
                // source backend volume. Before we can do the restore, we need
                // to detach the mirror of the distributed volume. So, create a
                // workflow step to detach it from the source.
                Volume vplexVolume = getDataObject(Volume.class, vplexVolumeURI, _dbClient);
                String detachStepId = workflow.createStepId();
                Workflow.Method restoreVolumeRollbackMethod = createRestoreResyncRollbackMethod(vplexURI, vplexVolumeURI, vplexVolume.getConsistencyGroup(), detachStepId);
                waitFor = createWorkflowStepForDetachMirror(workflow, vplexSystem, vplexVolume, detachStepId, null, restoreVolumeRollbackMethod);
                // We now create a step to invalidate the cache for the
                // VPLEX volume. Note that if this step fails we need to
                // rollback and reattach the mirror.
                createWorkflowStepForInvalidateCache(workflow, vplexSystem, vplexVolumeURI, waitFor, rollbackMethodNullMethod());
                // Now create a workflow step to reattach the mirror to initiate
                // a rebuild of the mirror for the distributed volume. Note that
                // these steps will not run until after the native restore, which
                // only gets executed once, not for every VPLEX volume.
                createWorkflowStepForAttachMirror(workflow, vplexSystem, vplexVolume, detachStepId, RESTORE_VOLUME_STEP, rollbackMethodNullMethod());
            }
            // Create a workflow step to native restore the backend volume
            // from the passed snapshot. This step is executed after the
            // cache has been invalidated for each VPLEX volume. Note that
            // if the snapshot is associated with a CG, then block controller
            // will restore all backend volumes in the CG using their
            // corresponding snapshots. We could execute this in parallel
            // with the restore for a little better efficiency, but what if
            // the invalidate cache fails, but the restore succeeds, the
            // cache now has invalid data and a cache read hit could return
            // invalid data. If this step fails, then again, we need to
            // be sure and rollback and reattach the mirror. There is
            // nothing to rollback for the cache invalidate step. It just
            // means there will be no read cache hits on the volume for a
            // while until the cache is repopulated.
            createWorkflowStepForRestoreNativeSnapshot(workflow, parentSystem, parentVolumeURI, snapshotURI, parentPoolURI, INVALIDATE_CACHE_STEP, rollbackMethodNullMethod());
        }
        // Execute the workflow.
        _log.info("Executing workflow plan");
        TaskCompleter completer = new BlockSnapshotRestoreCompleter(snapshot, opId);
        String successMsg = String.format("Restore VPLEX volume from snapshot %s of backend volume %s " + "completed successfully", snapshotURI, parentVolumeURI);
        workflow.executePlan(completer, successMsg);
        _log.info("Workflow plan executing");
    } catch (Exception e) {
        String failMsg = String.format("Restore VPLEX volume from snapshot %s failed", snapshotURI);
        _log.error(failMsg, e);
        TaskCompleter completer = new BlockSnapshotRestoreCompleter(snapshot, opId);
        ServiceError serviceError = VPlexApiException.errors.restoreVolumeFailed(snapshotURI.toString(), e);
        failStep(completer, opId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) BlockSnapshot(com.emc.storageos.db.client.model.BlockSnapshot) ArrayList(java.util.ArrayList) Workflow(com.emc.storageos.workflow.Workflow) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) BlockSnapshotRestoreCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.BlockSnapshotRestoreCompleter) Volume(com.emc.storageos.db.client.model.Volume) ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) MigrationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationTaskCompleter) CloneTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.CloneTaskCompleter) MigrationOperationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationOperationTaskCompleter) CacheStatusTaskCompleter(com.emc.storageos.vplexcontroller.completers.CacheStatusTaskCompleter) VplexMirrorTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VplexMirrorTaskCompleter) VolumeTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeTaskCompleter) VolumeGroupUpdateTaskCompleter(com.emc.storageos.vplexcontroller.completers.VolumeGroupUpdateTaskCompleter) TaskCompleter(com.emc.storageos.volumecontroller.TaskCompleter) WorkflowTaskCompleter(com.emc.storageos.workflow.WorkflowTaskCompleter) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 85 with TaskCompleter

use of com.emc.storageos.volumecontroller.TaskCompleter in project coprhd-controller by CoprHD.

the class VPlexDeviceController method createFullCopy.

/**
 * {@inheritDoc}
 */
@Override
public void createFullCopy(URI vplexURI, List<VolumeDescriptor> volumeDescriptors, String opId) throws ControllerException {
    _log.info("Copy volumes on VPLEX", vplexURI);
    // When we copy a VPLEX virtual volume we natively copy the primary backend
    // volume of the virtual volume. This primary copy is then imported to the
    // VPLEX as a local or distributed virtual volume depending upon the type of
    // the VPLEX volume being copied. Note that we could be creating multiple
    // copies of a single source volume that is not in a consistency group or
    // creating a single copy of multiple source volumes which are in a consistency
    // group.
    URI vplexSrcVolumeURI = null;
    List<URI> vplexCopyVolumesURIs = new ArrayList<URI>();
    TaskCompleter completer = null;
    try {
        // Set up the task completer
        List<VolumeDescriptor> vplexVolumeDescrs = VolumeDescriptor.filterByType(volumeDescriptors, new VolumeDescriptor.Type[] { Type.VPLEX_VIRT_VOLUME }, new VolumeDescriptor.Type[] {});
        List<VolumeDescriptor> vplexSrcVolumeDescs = getDescriptorsForFullCopySrcVolumes(vplexVolumeDescrs);
        // VPLEX copy volumes
        vplexVolumeDescrs.removeAll(vplexSrcVolumeDescs);
        vplexCopyVolumesURIs = VolumeDescriptor.getVolumeURIs(vplexVolumeDescrs);
        completer = new VPlexTaskCompleter(Volume.class, vplexCopyVolumesURIs, opId, null);
        Volume firstFullCopy = _dbClient.queryObject(Volume.class, vplexCopyVolumesURIs.get(0));
        URI sourceVolume = firstFullCopy.getAssociatedSourceVolume();
        Volume source = URIUtil.isType(sourceVolume, Volume.class) ? _dbClient.queryObject(Volume.class, sourceVolume) : null;
        VolumeGroup volumeGroup = (source != null) ? source.getApplication(_dbClient) : null;
        if (volumeGroup != null && !ControllerUtils.checkVolumeForVolumeGroupPartialRequest(_dbClient, source)) {
            _log.info("Creating full copy for Application {}", volumeGroup.getLabel());
            // add VolumeGroup to task completer
            completer.addVolumeGroupId(volumeGroup.getId());
        }
        // Generate the Workflow.
        Workflow workflow = _workflowService.getNewWorkflow(this, COPY_VOLUMES_WF_NAME, false, opId);
        _log.info("Created new full copy workflow with operation id {}", opId);
        /**
         * Volume descriptors contains
         * 1. VPLEX v-volume to be copied (source),
         * 2. VPLEX copy v-volume to be created,
         * 3. backend source volume to be created as clone for (1)'s backend volume
         * 4. Empty volume to be created as HA backend volume for (2) in case of Distributed
         *
         * Group the given volume descriptors by backend Array Replication Group (RG).
         * -For each RG entry, create workflow steps,
         * -These RG steps run in parallel
         */
        Map<String, List<VolumeDescriptor>> repGroupToVolumeDescriptors = groupDescriptorsByReplicationGroup(volumeDescriptors);
        for (String repGroupName : repGroupToVolumeDescriptors.keySet()) {
            _log.info("Processing Array Replication Group {}", repGroupName);
            List<URI> vplexCopyVolumeURIs = new ArrayList<URI>();
            List<VolumeDescriptor> volumeDescriptorsRG = repGroupToVolumeDescriptors.get(repGroupName);
            // We need to know which of the passed volume descriptors represents
            // the VPLEX virtual volumes that are being copied. We also remove it
            // from the list, so the only VPLEX volumes in the list are those
            // of the copies.
            List<VolumeDescriptor> vplexVolumeDescriptors = VolumeDescriptor.filterByType(volumeDescriptorsRG, new VolumeDescriptor.Type[] { Type.VPLEX_VIRT_VOLUME }, new VolumeDescriptor.Type[] {});
            List<VolumeDescriptor> vplexSrcVolumeDescrs = getDescriptorsForFullCopySrcVolumes(vplexVolumeDescriptors);
            vplexVolumeDescriptors.removeAll(vplexSrcVolumeDescrs);
            _log.info("Got volume descriptors for VPLEX volumes being copied.");
            // Get the URIs of the VPLEX copy volumes.
            vplexCopyVolumeURIs.addAll(VolumeDescriptor.getVolumeURIs(vplexVolumeDescriptors));
            vplexURI = getDataObject(Volume.class, vplexCopyVolumeURIs.get(0), _dbClient).getStorageController();
            // Add a rollback step to make sure all full copies are
            // marked inactive and that the full copy relationships
            // are updated. This will also mark any HA backend volumes
            // inactive in the case the copies are distributed. The
            // step only provides functionality on rollback. Normal
            // execution is a no-op.
            List<URI> volumesToMarkInactive = new ArrayList<URI>();
            volumesToMarkInactive.addAll(vplexCopyVolumeURIs);
            List<VolumeDescriptor> blockDescriptors = VolumeDescriptor.filterByType(volumeDescriptorsRG, new VolumeDescriptor.Type[] { Type.BLOCK_DATA }, new VolumeDescriptor.Type[] {});
            if (!blockDescriptors.isEmpty()) {
                volumesToMarkInactive.addAll(VolumeDescriptor.getVolumeURIs(blockDescriptors));
            }
            StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
            Workflow.Method executeMethod = rollbackMethodNullMethod();
            Workflow.Method rollbackMethod = markVolumesInactiveMethod(volumesToMarkInactive);
            String waitFor = workflow.createStep(null, "Mark volumes inactive on rollback", null, vplexURI, vplexSystem.getSystemType(), this.getClass(), executeMethod, rollbackMethod, null);
            if (!vplexSrcVolumeDescrs.isEmpty()) {
                // Find the backend volume that is the primary volume for one of
                // the VPLEX volumes being copied. The primary backend volume is the
                // associated volume in the same virtual array as the VPLEX volume.
                // It does not matter which one if there are multiple source VPLEX
                // volumes. These volumes will all be in a consistency group and
                // use the same backend storage system.
                VolumeDescriptor vplexSrcVolumeDescr = vplexSrcVolumeDescrs.get(0);
                vplexSrcVolumeURI = vplexSrcVolumeDescr.getVolumeURI();
                BlockObject primarySourceObject = getPrimaryForFullCopySrcVolume(vplexSrcVolumeURI);
                _log.info("Primary volume/snapshot is {}", primarySourceObject.getId());
                // add CG to taskCompleter
                if (!NullColumnValueGetter.isNullURI(primarySourceObject.getConsistencyGroup())) {
                    completer.addConsistencyGroupId(primarySourceObject.getConsistencyGroup());
                }
            }
            // Next, create a step to create and start an import volume
            // workflow for each copy.
            createStepsForFullCopyImport(workflow, vplexURI, vplexVolumeDescriptors, volumeDescriptorsRG, waitFor);
            _log.info("Created workflow steps to import the primary copies");
        }
        _log.info("Executing workflow plan");
        FullCopyOperationCompleteCallback wfCompleteCB = new FullCopyOperationCompleteCallback();
        workflow.executePlan(completer, String.format("Copy of VPLEX volume %s completed successfully", vplexSrcVolumeURI), wfCompleteCB, new Object[] { vplexCopyVolumesURIs }, null, null);
        _log.info("Workflow plan executing");
    } catch (Exception e) {
        String failMsg = String.format("Copy of VPLEX volume %s failed", vplexSrcVolumeURI);
        _log.error(failMsg, e);
        ServiceError serviceError = VPlexApiException.errors.fullCopyVolumesFailed((vplexSrcVolumeURI != null ? vplexSrcVolumeURI.toString() : ""), e);
        failStep(completer, opId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) VolumeDescriptor(com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor) ArrayList(java.util.ArrayList) Workflow(com.emc.storageos.workflow.Workflow) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) Volume(com.emc.storageos.db.client.model.Volume) VolumeGroup(com.emc.storageos.db.client.model.VolumeGroup) ApplicationAddVolumeList(com.emc.storageos.volumecontroller.ApplicationAddVolumeList) ArrayList(java.util.ArrayList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) List(java.util.List) ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) MigrationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationTaskCompleter) CloneTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.CloneTaskCompleter) MigrationOperationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationOperationTaskCompleter) CacheStatusTaskCompleter(com.emc.storageos.vplexcontroller.completers.CacheStatusTaskCompleter) VplexMirrorTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VplexMirrorTaskCompleter) VolumeTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeTaskCompleter) VolumeGroupUpdateTaskCompleter(com.emc.storageos.vplexcontroller.completers.VolumeGroupUpdateTaskCompleter) TaskCompleter(com.emc.storageos.volumecontroller.TaskCompleter) WorkflowTaskCompleter(com.emc.storageos.workflow.WorkflowTaskCompleter) BlockObject(com.emc.storageos.db.client.model.BlockObject) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

TaskCompleter (com.emc.storageos.volumecontroller.TaskCompleter)171 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)160 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)147 WorkflowException (com.emc.storageos.workflow.WorkflowException)141 ControllerException (com.emc.storageos.volumecontroller.ControllerException)127 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)113 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)106 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)103 VolumeTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.VolumeTaskCompleter)89 CloneTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.CloneTaskCompleter)88 Workflow (com.emc.storageos.workflow.Workflow)72 MultiVolumeTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.MultiVolumeTaskCompleter)70 SimpleTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.SimpleTaskCompleter)70 URI (java.net.URI)70 BaseCollectionException (com.emc.storageos.plugins.BaseCollectionException)69 ApplicationTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.ApplicationTaskCompleter)69 BlockMirrorTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.BlockMirrorTaskCompleter)69 BlockSnapshotEstablishGroupTaskCompleter (com.emc.storageos.volumecontroller.impl.block.taskcompleter.BlockSnapshotEstablishGroupTaskCompleter)69 DiscoverTaskCompleter (com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.DiscoverTaskCompleter)69 ScanTaskCompleter (com.emc.storageos.volumecontroller.impl.plugins.discovery.smis.ScanTaskCompleter)69