Search in sources :

Example 91 with InternalException

use of com.emc.storageos.svcs.errorhandling.resources.InternalException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method addStepsForChangeVirtualPool.

@Override
public String addStepsForChangeVirtualPool(Workflow workflow, String waitFor, List<VolumeDescriptor> volumes, String taskId) throws InternalException {
    try {
        // Get all the Virtual Volumes.
        List<VolumeDescriptor> vplexVirtualVolumes = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.VPLEX_VIRT_VOLUME }, new VolumeDescriptor.Type[] {});
        if (vplexVirtualVolumes == null || vplexVirtualVolumes.isEmpty()) {
            return waitFor;
        }
        // Find the original change vpool virtual volumes from the descriptors.
        URI newVpoolURI = null;
        List<URI> changeVpoolVirtualVolumeURIs = new ArrayList<URI>();
        for (VolumeDescriptor vplexVirtualVolume : vplexVirtualVolumes) {
            if (vplexVirtualVolume.getParameters() != null && !vplexVirtualVolume.getParameters().isEmpty()) {
                // Let's check to see if the PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID was populated
                // in the descriptor params map. This would indicate that the descriptor
                // has information about the existing volume for the change vpool operation.
                Object existingVolumeId = vplexVirtualVolume.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID);
                if (existingVolumeId != null) {
                    URI virtualVolumeURI = (URI) existingVolumeId;
                    _log.info(String.format("Adding steps for change vpool for vplex volume %s", virtualVolumeURI.toString()));
                    if (newVpoolURI == null) {
                        newVpoolURI = (URI) vplexVirtualVolume.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_NEW_VPOOL_ID);
                    }
                    changeVpoolVirtualVolumeURIs.add(virtualVolumeURI);
                }
            }
        }
        // Check to see if this is an RP+VPLEX change vpool request
        List<VolumeDescriptor> rpExistingSourceVolumes = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.RP_EXISTING_SOURCE }, new VolumeDescriptor.Type[] {});
        // Check to see if this is an RP+VPLEX change vpool request
        List<VolumeDescriptor> rpExistingProtectedSourceVolumes = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.RP_EXISTING_PROTECTED_SOURCE }, new VolumeDescriptor.Type[] {});
        boolean rpAddProtectionVPoolChange = (rpExistingSourceVolumes != null && !rpExistingSourceVolumes.isEmpty());
        boolean rpUpgradeProtectionVPoolChange = (rpExistingProtectedSourceVolumes != null && !rpExistingProtectedSourceVolumes.isEmpty());
        // RP+VPLEX change vpool request
        if (rpAddProtectionVPoolChange || rpUpgradeProtectionVPoolChange) {
            // First let's make a copy of the all the volume descriptors passed in
            List<VolumeDescriptor> copyOfVolumeDescriptors = new ArrayList<VolumeDescriptor>();
            copyOfVolumeDescriptors.addAll(volumes);
            if (rpAddProtectionVPoolChange) {
                _log.info("Adding VPLEX steps for RP+VPLEX/MetroPoint add protection vpool change...");
                Iterator<VolumeDescriptor> it = copyOfVolumeDescriptors.iterator();
                while (it.hasNext()) {
                    VolumeDescriptor currentVolumeDesc = it.next();
                    if (changeVpoolVirtualVolumeURIs.contains(currentVolumeDesc.getVolumeURI())) {
                        // Remove the RP+VPLEX Source Change Vpool Virtual Volume(s) from the copy of the
                        // descriptors as they do not need to be created (because they already exist!)
                        it.remove();
                        break;
                    }
                }
                // already)
                for (URI virtualVolumeURI : changeVpoolVirtualVolumeURIs) {
                    Volume changeVpoolVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
                    changeVpoolVolume.getConsistencyGroup();
                    // This is a good time to update the vpool on the existing Virtual Volume to the new vpool
                    changeVpoolVolume.setVirtualPool(newVpoolURI);
                    _dbClient.updateObject(changeVpoolVolume);
                    StorageSystem vplex = getDataObject(StorageSystem.class, changeVpoolVolume.getStorageController(), _dbClient);
                    // Get a handle on the RP consistency group manager
                    ConsistencyGroupManager consistencyGroupManager = getConsistencyGroupManager(DiscoveredDataObject.Type.rp.name());
                    // Add step for create CG
                    waitFor = consistencyGroupManager.addStepsForCreateConsistencyGroup(workflow, waitFor, vplex, Arrays.asList(virtualVolumeURI), false);
                    _log.info("Added steps for CG creation for vplex volume {}", virtualVolumeURI);
                }
            } else {
                _log.info("Adding VPLEX steps for RP+VPLEX/MetroPoint upgrade protection vpool change...");
            }
            // Let's now create the virtual volumes for the RP+VPLEX:
            // Source Journal, Target(s), and Target Journal.
            waitFor = addStepsForCreateVolumes(workflow, waitFor, copyOfVolumeDescriptors, taskId);
        }
        // Create steps to migrate the backend volumes.
        String lastStep = waitFor;
        URI cgURI = null;
        // With application support, one VPLEX CG could have multiple replication groups from the same local system.
        // The localSystemToRemoveCG map key is storagesystemUri, value is the list of replication group names to be removed.
        Map<URI, Set<String>> localSystemsToRemoveCG = new HashMap<URI, Set<String>>();
        List<VolumeDescriptor> vplexMigrateVolumes = VolumeDescriptor.filterByType(volumes, new VolumeDescriptor.Type[] { VolumeDescriptor.Type.VPLEX_MIGRATE_VOLUME }, new VolumeDescriptor.Type[] {});
        if (vplexMigrateVolumes != null && !vplexMigrateVolumes.isEmpty()) {
            for (URI virtualVolumeURI : changeVpoolVirtualVolumeURIs) {
                _log.info("Adding migration steps for vplex volume {}", virtualVolumeURI);
                // A list of the volumes satisfying the new VirtualPool to
                // which the data on the current backend volumes
                // will be migrated.
                List<URI> newVolumes = new ArrayList<URI>();
                // A Map containing a migration for each new backend
                // volume
                Map<URI, URI> migrationMap = new HashMap<URI, URI>();
                // A map that specifies the storage pool in which
                // each new volume should be created.
                Map<URI, URI> poolVolumeMap = new HashMap<URI, URI>();
                // The URI of the vplex system
                URI vplexURI = null;
                for (VolumeDescriptor desc : vplexMigrateVolumes) {
                    // Skip migration targets that are not for the VPLEX
                    // volume being processed.
                    Migration migration = getDataObject(Migration.class, desc.getMigrationId(), _dbClient);
                    if (!migration.getVolume().equals(virtualVolumeURI)) {
                        continue;
                    }
                    // migrated when multiple volumes are passed.
                    if (vplexURI == null) {
                        Volume virtualVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
                        vplexURI = virtualVolume.getStorageController();
                        cgURI = virtualVolume.getConsistencyGroup();
                    }
                    // Set data required to add the migration steps.
                    newVolumes.add(desc.getVolumeURI());
                    migrationMap.put(desc.getVolumeURI(), desc.getMigrationId());
                    poolVolumeMap.put(desc.getVolumeURI(), desc.getPoolURI());
                    // If the migration is to a different storage system
                    // we may need to remove the backend CG on the source
                    // system after the migration completes. Note that the
                    // migration source is null for an ingested volume
                    // being migrated to known storage.
                    Volume migSrc = null;
                    URI migSrcURI = migration.getSource();
                    if (!NullColumnValueGetter.isNullURI(migSrcURI)) {
                        migSrc = getDataObject(Volume.class, migSrcURI, _dbClient);
                    }
                    URI migTgtURI = migration.getTarget();
                    Volume migTgt = getDataObject(Volume.class, migTgtURI, _dbClient);
                    if ((migSrc != null) && (!migTgt.getStorageController().equals(migSrc.getStorageController()))) {
                        // If we have a volume to migrate and the RG field is NOT set on the volume,
                        // do not remove the RG on the local system.
                        // 
                        // Volumes that are in RGs that are being migrated are grouped together so otherwise
                        // we're good as the replication instance will be set on those volumes.
                        String rgName = migSrc.getReplicationGroupInstance();
                        if (NullColumnValueGetter.isNotNullValue(rgName)) {
                            URI storageUri = migSrc.getStorageController();
                            Set<String> rgNames = localSystemsToRemoveCG.get(storageUri);
                            if (rgNames == null) {
                                rgNames = new HashSet<String>();
                                localSystemsToRemoveCG.put(storageUri, rgNames);
                            }
                            rgNames.add(rgName);
                            _log.info("Will remove CG {} on local system {}", rgName, storageUri);
                        } else {
                            _log.info("Will not remove CG on local system {}", migSrc.getStorageController());
                        }
                    }
                }
                // Note that the last step here is a step group associated
                // with deleting the migration sources after the migrations
                // have completed and committed. This means that anything
                // that waits on this, will occur after the migrations have
                // completed, been committed, and the migration sources deleted.
                lastStep = addStepsForMigrateVolumes(workflow, vplexURI, virtualVolumeURI, newVolumes, migrationMap, poolVolumeMap, newVpoolURI, null, VolumeDescriptor.getMigrationSuspendBeforeCommit(volumes), VolumeDescriptor.getMigrationSuspendBeforeDeleteSource(volumes), taskId, waitFor);
                _log.info("Add migration steps for vplex volume {}", virtualVolumeURI);
            }
            // systemConsistencyGroup specified for the group.
            if (!NullColumnValueGetter.isNullURI(cgURI)) {
                _log.info("Vpool change volumes are in CG {}", cgURI);
                BlockConsistencyGroup cg = getDataObject(BlockConsistencyGroup.class, cgURI, _dbClient);
                if (cg.checkForType(Types.LOCAL)) {
                    _log.info("CG {} has local type", cgURI);
                    // If any of the VPLEX volumes involved in the vpool change
                    // is in a VPLEX CG with corresponding local CGs for the backend
                    // volumes, then it is required that all VPLEX volumes in the
                    // CG are part of the vpool change. If the backend volumes are being
                    // migrated to a new storage system, then we need to add a step
                    // to delete the local CG.
                    boolean localCGDeleted = false;
                    for (Map.Entry<URI, Set<String>> entry : localSystemsToRemoveCG.entrySet()) {
                        localCGDeleted = true;
                        URI localSystemURI = entry.getKey();
                        StorageSystem localSystem = getDataObject(StorageSystem.class, localSystemURI, _dbClient);
                        Set<String> rgNames = entry.getValue();
                        for (String rgName : rgNames) {
                            _log.info("Adding step to remove CG {} on local system {}", rgName, localSystemURI);
                            Workflow.Method deleteCGMethod = new Workflow.Method("deleteReplicationGroupInConsistencyGroup", localSystemURI, cgURI, rgName, false, false, true);
                            workflow.createStep("deleteLocalCG", String.format("Delete consistency group from storage system: %s", localSystemURI), lastStep, localSystemURI, localSystem.getSystemType(), BlockDeviceController.class, deleteCGMethod, null, null);
                        }
                    }
                    if (localCGDeleted) {
                        lastStep = "deleteLocalCG";
                    }
                }
            }
        }
        // Return the last step
        return lastStep;
    } catch (Exception ex) {
        throw VPlexApiException.exceptions.addStepsForChangeVirtualPoolFailed(ex);
    }
}
Also used : HashSet(java.util.HashSet) StringSet(com.emc.storageos.db.client.model.StringSet) Set(java.util.Set) HashMap(java.util.HashMap) Migration(com.emc.storageos.db.client.model.Migration) ArrayList(java.util.ArrayList) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) VolumeDescriptor(com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor) Workflow(com.emc.storageos.workflow.Workflow) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) BlockConsistencyGroup(com.emc.storageos.db.client.model.BlockConsistencyGroup) Volume(com.emc.storageos.db.client.model.Volume) DiscoveredDataObject(com.emc.storageos.db.client.model.DiscoveredDataObject) DataObject(com.emc.storageos.db.client.model.DataObject) VPlexControllerUtils.getDataObject(com.emc.storageos.vplexcontroller.VPlexControllerUtils.getDataObject) BlockObject(com.emc.storageos.db.client.model.BlockObject) Map(java.util.Map) StringSetMap(com.emc.storageos.db.client.model.StringSetMap) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap) StringMap(com.emc.storageos.db.client.model.StringMap)

Example 92 with InternalException

use of com.emc.storageos.svcs.errorhandling.resources.InternalException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method resyncSnapshot.

/**
 * {@inheritDoc}
 */
@Override
public void resyncSnapshot(URI vplexURI, URI snapshotURI, String opId) throws InternalException {
    // The snapshot target volume could be the source side backend volume for
    // a VPLEX volume if a VPLEX volume was created on the snapshot target volume
    // for the purpose of exporting the snapshot through the VPLEX rather directly
    // through the backend storage system. If this is the case, and that snapshot
    // is resynchronized, then we need do some additional steps because the data
    // on the VPLEX backend volume will have changed, and the VPLEX volume needs
    // to know about that.
    BlockSnapshot snapshot = getDataObject(BlockSnapshot.class, snapshotURI, _dbClient);
    try {
        // Create a new the Workflow.
        Workflow workflow = _workflowService.getNewWorkflow(this, RESYNC_SNAPSHOT_WF_NAME, false, opId);
        _log.info("Created resync snapshot workflow with operation id {}", opId);
        // Get all snapshots that will be resync'd.
        List<BlockSnapshot> snapshotsToResync = new ArrayList<BlockSnapshot>();
        URI cgURI = snapshot.getConsistencyGroup();
        if (!NullColumnValueGetter.isNullURI(cgURI)) {
            snapshotsToResync = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshot, _dbClient);
        } else {
            snapshotsToResync.add(snapshot);
        }
        // Get a list of the VPLEX volumes, if any, that are built
        // using the snapshot target volume.
        List<Volume> vplexVolumes = VPlexUtil.getVPlexVolumesBuiltOnSnapshots(snapshotsToResync, _dbClient);
        // Create the workflow steps.
        if (vplexVolumes.isEmpty()) {
            // If there are no VPLEX volumes built on the snapshots to be resynchronized,
            // then we just need a single step to invoke the block device controller to
            // resync the snapshots.
            createWorkflowStepForResyncNativeSnapshot(workflow, snapshot, null, null);
        } else {
            // Maps Vplex volume that needs to be flushed to underlying array volume
            Map<Volume, Volume> vplexToArrayVolumesToFlush = new HashMap<Volume, Volume>();
            for (Volume vplexVolume : vplexVolumes) {
                Volume arrayVolumeToBeResynced = VPlexUtil.getVPLEXBackendVolume(vplexVolume, true, _dbClient);
                vplexToArrayVolumesToFlush.put(vplexVolume, arrayVolumeToBeResynced);
            }
            Map<URI, String> vplexVolumeIdToDetachStep = new HashMap<URI, String>();
            String waitFor = null;
            // Generate pre restore steps
            waitFor = addPreRestoreResyncSteps(workflow, vplexToArrayVolumesToFlush, vplexVolumeIdToDetachStep, waitFor);
            // Now create a workflow step to natively resync the snapshot.
            // Note that if the snapshot is associated with a CG, then block
            // controller will resync all snapshots in the snapshot set. We
            // execute this after the invalidate cache.
            waitFor = createWorkflowStepForResyncNativeSnapshot(workflow, snapshot, waitFor, rollbackMethodNullMethod());
            // Generate post restore steps
            waitFor = addPostRestoreResyncSteps(workflow, vplexToArrayVolumesToFlush, vplexVolumeIdToDetachStep, waitFor);
        }
        // Execute the workflow.
        _log.info("Executing workflow plan");
        TaskCompleter completer = new BlockSnapshotResyncCompleter(snapshot, opId);
        String successMsg = String.format("Resynchronize VPLEX native snapshot %s from volume %s " + "completed successfully", snapshotURI, snapshot.getParent().getURI());
        workflow.executePlan(completer, successMsg);
        _log.info("Workflow plan executing");
    } catch (Exception e) {
        String failMsg = String.format("Resynchronize VPLEX native snapshot %s failed", snapshotURI);
        _log.error(failMsg, e);
        TaskCompleter completer = new BlockSnapshotResyncCompleter(snapshot, opId);
        ServiceError serviceError = VPlexApiException.errors.restoreVolumeFailed(snapshotURI.toString(), e);
        failStep(completer, opId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) HashMap(java.util.HashMap) BlockSnapshotResyncCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.BlockSnapshotResyncCompleter) 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) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) 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) MigrationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationTaskCompleter) VolumeGroupUpdateTaskCompleter(com.emc.storageos.vplexcontroller.completers.VolumeGroupUpdateTaskCompleter) ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) 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) TaskCompleter(com.emc.storageos.volumecontroller.TaskCompleter) WorkflowTaskCompleter(com.emc.storageos.workflow.WorkflowTaskCompleter)

Example 93 with InternalException

use of com.emc.storageos.svcs.errorhandling.resources.InternalException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method addStepsForMigrateVolumes.

/**
 * Adds steps in the passed workflow to migrate a volume.
 *
 * @param workflow
 * @param vplexURI
 * @param virtualVolumeURI
 * @param targetVolumeURIs
 * @param migrationsMap
 * @param poolVolumeMap
 * @param newVpoolURI
 * @param newVarrayURI
 * @param suspendBeforeCommit
 * @param suspendBeforeDeleteSource
 * @param opId
 * @param waitFor
 * @return
 * @throws InternalException
 */
public String addStepsForMigrateVolumes(Workflow workflow, URI vplexURI, URI virtualVolumeURI, List<URI> targetVolumeURIs, Map<URI, URI> migrationsMap, Map<URI, URI> poolVolumeMap, URI newVpoolURI, URI newVarrayURI, boolean suspendBeforeCommit, boolean suspendBeforeDeleteSource, String opId, String waitFor) throws InternalException {
    try {
        _log.info("VPlex controller migrate volume {} on VPlex {}", virtualVolumeURI, vplexURI);
        String volumeUserLabel = "Label Unknown";
        Volume virtualVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
        if (virtualVolume != null && virtualVolume.getDeviceLabel() != null && virtualVolume.getLabel() != null) {
            volumeUserLabel = virtualVolume.getLabel() + " (" + virtualVolume.getDeviceLabel() + ")";
        }
        // Get the VPlex storage system
        StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        _log.info("Got VPlex system");
        // Create a step to validate the volume and prevent migration if the
        // the ViPR DB does not properly reflect the actual backend volumes.
        // A successful migration will delete the backend source volumes. If
        // the ViPR DB does not correctly reflect the actual backend volume,
        // we could delete a backend volume used by some other VPLEX volume.
        waitFor = createWorkflowStepToValidateVPlexVolume(workflow, vplexSystem, virtualVolumeURI, waitFor);
        Map<URI, Volume> volumeMap = new HashMap<URI, Volume>();
        Map<URI, StorageSystem> storageSystemMap = new HashMap<URI, StorageSystem>();
        for (URI volumeURI : targetVolumeURIs) {
            Volume volume = getDataObject(Volume.class, volumeURI, _dbClient);
            volumeMap.put(volumeURI, volume);
            StorageSystem storageSystem = getDataObject(StorageSystem.class, volume.getStorageController(), _dbClient);
            storageSystemMap.put(volume.getStorageController(), storageSystem);
        }
        // Set the project and tenant.
        Volume firstVolume = volumeMap.values().iterator().next();
        Project vplexProject = VPlexUtil.lookupVplexProject(firstVolume, vplexSystem, _dbClient);
        URI tenantURI = vplexProject.getTenantOrg().getURI();
        _log.info("Project is {}, Tenant is {}", vplexProject.getId(), tenantURI);
        waitFor = createWorkflowStepsForBlockVolumeExport(workflow, vplexSystem, storageSystemMap, volumeMap, vplexProject.getId(), tenantURI, waitFor);
        _log.info("Created workflow steps for volume export.");
        // Now make a migration Step for each passed target to which data
        // for the passed virtual volume will be migrated. The migrations
        // will be done from this controller.
        Iterator<URI> targetVolumeIter = targetVolumeURIs.iterator();
        while (targetVolumeIter.hasNext()) {
            URI targetVolumeURI = targetVolumeIter.next();
            _log.info("Target volume is {}", targetVolumeURI);
            URI migrationURI = migrationsMap.get(targetVolumeURI);
            _log.info("Migration is {}", migrationURI);
            String stepId = workflow.createStepId();
            _log.info("Migration opId is {}", stepId);
            Workflow.Method vplexExecuteMethod = new Workflow.Method(MIGRATE_VIRTUAL_VOLUME_METHOD_NAME, vplexURI, virtualVolumeURI, targetVolumeURI, migrationURI, newVarrayURI);
            Workflow.Method vplexRollbackMethod = new Workflow.Method(RB_MIGRATE_VIRTUAL_VOLUME_METHOD_NAME, vplexURI, migrationURI, stepId);
            _log.info("Creating workflow migration step");
            workflow.createStep(MIGRATION_CREATE_STEP, String.format("VPlex %s migrating to target volume %s.", vplexSystem.getId().toString(), targetVolumeURI.toString()), waitFor, vplexSystem.getId(), vplexSystem.getSystemType(), getClass(), vplexExecuteMethod, vplexRollbackMethod, stepId);
            _log.info("Created workflow migration step");
        }
        // Once the migrations complete, we will commit the migrations.
        // So, now we create the steps to commit the migrations.
        String waitForStep = MIGRATION_CREATE_STEP;
        List<URI> migrationURIs = new ArrayList<URI>(migrationsMap.values());
        List<URI> migrationSources = new ArrayList<URI>();
        Iterator<URI> migrationsIter = migrationsMap.values().iterator();
        while (migrationsIter.hasNext()) {
            URI migrationURI = migrationsIter.next();
            _log.info("Migration is {}", migrationURI);
            Migration migration = getDataObject(Migration.class, migrationURI, _dbClient);
            // The migration source volume may be null for ingested volumes
            // for which we do not know anything about the backend volumes.
            // If we don't know the source, we know we are migrating an
            // ingested volume and we will not want to do any renaming
            // after the commit as we do when migration ViPR create volumes,
            // which adhere to a standard naming convention.
            Boolean rename = Boolean.TRUE;
            if (migration.getSource() != null) {
                migrationSources.add(migration.getSource());
            } else {
                rename = Boolean.FALSE;
            }
            _log.info("Added migration source {}", migration.getSource());
            String stepId = workflow.createStepId();
            _log.info("Commit operation id is {}", stepId);
            Workflow.Method vplexExecuteMethod = new Workflow.Method(COMMIT_MIGRATION_METHOD_NAME, vplexURI, virtualVolumeURI, migrationURI, rename, newVpoolURI, newVarrayURI);
            Workflow.Method vplexRollbackMethod = new Workflow.Method(RB_COMMIT_MIGRATION_METHOD_NAME, migrationURIs, newVpoolURI, newVarrayURI, stepId);
            _log.info("Creating workflow step to commit migration");
            String stepDescription = String.format("migration commit step on VPLEX %s of volume %s", vplexSystem.getSerialNumber(), volumeUserLabel);
            waitForStep = workflow.createStep(MIGRATION_COMMIT_STEP, stepDescription, waitForStep, vplexSystem.getId(), vplexSystem.getSystemType(), getClass(), vplexExecuteMethod, vplexRollbackMethod, suspendBeforeCommit, stepId);
            workflow.setSuspendedStepMessage(stepId, COMMIT_MIGRATION_SUSPEND_MESSAGE);
            _log.info("Created workflow step to commit migration");
        }
        // Create a step that creates a sub workflow to delete the old
        // migration source volumes, which are no longer used by the
        // virtual volume. We also update the virtual volume CoS. If
        // we make it to this step, then all migrations were committed.
        // We do this in a sub workflow because we don't won't to
        // initiate rollback regardless of success or failure.
        String stepId = workflow.createStepId();
        Workflow.Method vplexExecuteMethod = new Workflow.Method(DELETE_MIGRATION_SOURCES_METHOD, vplexURI, virtualVolumeURI, newVpoolURI, newVarrayURI, migrationSources);
        List<String> migrationSourceLabels = new ArrayList<>();
        Iterator<Volume> volumeIter = _dbClient.queryIterativeObjects(Volume.class, migrationSources);
        while (volumeIter.hasNext()) {
            migrationSourceLabels.add(volumeIter.next().getNativeGuid());
        }
        String stepDescription = String.format("post-migration delete of original source backing volumes [%s] associated with virtual volume %s", Joiner.on(',').join(migrationSourceLabels), volumeUserLabel);
        workflow.createStep(DELETE_MIGRATION_SOURCES_STEP, stepDescription, waitForStep, vplexSystem.getId(), vplexSystem.getSystemType(), getClass(), vplexExecuteMethod, null, suspendBeforeDeleteSource, stepId);
        workflow.setSuspendedStepMessage(stepId, DELETE_MIGRATION_SOURCES_SUSPEND_MESSAGE);
        _log.info("Created workflow step to create sub workflow for source deletion");
        return DELETE_MIGRATION_SOURCES_STEP;
    } catch (Exception e) {
        throw VPlexApiException.exceptions.addStepsForChangeVirtualPoolFailed(e);
    }
}
Also used : HashMap(java.util.HashMap) Migration(com.emc.storageos.db.client.model.Migration) 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) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException) Project(com.emc.storageos.db.client.model.Project) Volume(com.emc.storageos.db.client.model.Volume) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 94 with InternalException

use of com.emc.storageos.svcs.errorhandling.resources.InternalException in project coprhd-controller by CoprHD.

the class VPlexDeviceController method deactivateMirror.

@Override
public void deactivateMirror(URI vplexURI, URI mirrorURI, List<VolumeDescriptor> volumeDescriptors, String taskId) throws InternalException {
    VplexMirrorDeactivateCompleter completer = new VplexMirrorDeactivateCompleter(mirrorURI, taskId);
    try {
        // Generate the Workflow.
        Workflow workflow = _workflowService.getNewWorkflow(this, DEACTIVATE_MIRROR_WF_NAME, true, taskId);
        // the wait for key returned by previous call
        String waitFor = null;
        // Add steps for detaching and deleting mirror
        waitFor = addStepsForDetachAndDeleteMirror(workflow, waitFor, vplexURI, mirrorURI, taskId);
        // Next, call the BlockDeviceController to add its methods.
        waitFor = _blockDeviceController.addStepsForDeleteVolumes(workflow, waitFor, volumeDescriptors, taskId);
        String successMessage = "Deactivate mirror successful for: " + mirrorURI;
        workflow.executePlan(completer, successMessage);
    } catch (Exception ex) {
        _log.error("Deactivate mirror failed for mirror " + mirrorURI, ex);
        ServiceError serviceError = VPlexApiException.errors.deactivateMirrorFailed(ex);
        failStep(completer, taskId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Workflow(com.emc.storageos.workflow.Workflow) VplexMirrorDeactivateCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.VplexMirrorDeactivateCompleter) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) WorkflowException(com.emc.storageos.workflow.WorkflowException) DatabaseException(com.emc.storageos.db.exceptions.DatabaseException) DeviceControllerException(com.emc.storageos.exceptions.DeviceControllerException)

Example 95 with InternalException

use of com.emc.storageos.svcs.errorhandling.resources.InternalException 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) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) 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) MigrationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationTaskCompleter) VolumeGroupUpdateTaskCompleter(com.emc.storageos.vplexcontroller.completers.VolumeGroupUpdateTaskCompleter) ExportTaskCompleter(com.emc.storageos.volumecontroller.impl.block.taskcompleter.ExportTaskCompleter) 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) TaskCompleter(com.emc.storageos.volumecontroller.TaskCompleter) WorkflowTaskCompleter(com.emc.storageos.workflow.WorkflowTaskCompleter) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)209 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)112 URI (java.net.URI)106 ControllerException (com.emc.storageos.volumecontroller.ControllerException)100 Volume (com.emc.storageos.db.client.model.Volume)91 ArrayList (java.util.ArrayList)86 WorkflowException (com.emc.storageos.workflow.WorkflowException)84 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)83 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)77 NamedURI (com.emc.storageos.db.client.model.NamedURI)63 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)60 URISyntaxException (java.net.URISyntaxException)58 APIException (com.emc.storageos.svcs.errorhandling.resources.APIException)55 Operation (com.emc.storageos.db.client.model.Operation)51 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)45 Workflow (com.emc.storageos.workflow.Workflow)41 TaskResourceRep (com.emc.storageos.model.TaskResourceRep)40 Path (javax.ws.rs.Path)39 Produces (javax.ws.rs.Produces)39 CheckPermission (com.emc.storageos.security.authorization.CheckPermission)37