Search in sources :

Example 1 with RPVPlexMigration

use of com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration in project coprhd-controller by CoprHD.

the class RPBlockServiceApiImpl method changeVolumeVirtualPool.

@Override
public TaskList changeVolumeVirtualPool(List<Volume> volumes, VirtualPool vpool, VirtualPoolChangeParam vpoolChangeParam, String taskId) throws InternalException {
    TaskList taskList = new TaskList();
    StringBuffer notSuppReasonBuff = new StringBuffer();
    notSuppReasonBuff.setLength(0);
    // Get the first volume for the change vpool operation
    Volume firstVolume = volumes.get(0);
    // Get the current vpool from the first volume
    VirtualPool currentVpool = _dbClient.queryObject(VirtualPool.class, firstVolume.getVirtualPool());
    // Container for RP+VPLEX migrations (if there are any)
    List<RPVPlexMigration> validMigrations = new ArrayList<RPVPlexMigration>();
    if (firstVolume.checkForRp() && firstVolume.checkPersonality(Volume.PersonalityTypes.METADATA)) {
        boolean vplex = RPHelper.isVPlexVolume(firstVolume, _dbClient);
        if (vplex) {
            if (VirtualPoolChangeAnalyzer.vpoolChangeRequiresMigration(currentVpool, vpool)) {
                // Allow the VPLEX Data Migration operation for the RP+VPLEX Journal
                // to proceed via the VPLEX Block Service.
                taskList.getTaskList().addAll(vplexBlockServiceApiImpl.changeVolumeVirtualPool(volumes, vpool, vpoolChangeParam, taskId).getTaskList());
            }
        }
    } else if (firstVolume.checkForRp() && !VirtualPool.vPoolSpecifiesProtection(vpool)) {
        taskList = createTasksForVolumes(vpool, volumes, taskId);
        removeProtection(volumes, vpool, taskId);
    } else if (VirtualPoolChangeAnalyzer.isSupportedRPVPlexMigrationVirtualPoolChange(firstVolume, currentVpool, vpool, _dbClient, notSuppReasonBuff, validMigrations)) {
        taskList.getTaskList().addAll(rpVPlexDataMigration(volumes, vpool, taskId, validMigrations, vpoolChangeParam).getTaskList());
    } else {
        // until CTRL-1347 and CTRL-5609 are fixed.
        if (volumes.size() == 1) {
            taskList = createTasksForVolumes(vpool, volumes, taskId);
            changeVolumeVirtualPool(firstVolume.getStorageController(), firstVolume, vpool, vpoolChangeParam, taskId);
        } else {
            throw APIException.methodNotAllowed.notSupportedWithReason("Multiple volume change virtual pool is currently not supported for RecoverPoint. " + "Please select one volume at a time.");
        }
    }
    return taskList;
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) TaskList(com.emc.storageos.model.TaskList) RPVPlexMigration(com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration) ArrayList(java.util.ArrayList) VirtualPool(com.emc.storageos.db.client.model.VirtualPool)

Example 2 with RPVPlexMigration

use of com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration in project coprhd-controller by CoprHD.

the class RPBlockServiceApiImpl method rpVPlexJournalMigrations.

/**
 * Special Journal migration step needed as Journals belong to a CG and need to be
 * gathered from the CG. These migrations are always single migrations.
 *
 * @param journalMigrationsExist Boolean to determine if journal migrations exist
 * @param journalVpoolMigrations List of RPVPlexMigrations for Journals
 * @param singleMigrations Container to store all single migrations
 * @param cgURIs Set of URIs of all the CGs from the request
 * @param logMigrations String buffer for logging
 */
private void rpVPlexJournalMigrations(boolean journalMigrationsExist, List<RPVPlexMigration> journalVpoolMigrations, Map<Volume, VirtualPool> singleMigrations, Set<URI> cgURIs, StringBuffer logMigrations) {
    if (journalMigrationsExist) {
        for (URI cgURI : cgURIs) {
            BlockConsistencyGroup cg = _dbClient.queryObject(BlockConsistencyGroup.class, cgURI);
            // Get all Journal volumes from the CG.
            List<Volume> journalVolumes = RPHelper.getCgVolumes(_dbClient, cg.getId(), Volume.PersonalityTypes.METADATA.name());
            for (Volume journalVolume : journalVolumes) {
                // Check to see if this Journal volume qualifies for migration
                RPVPlexMigration journalMigration = null;
                for (RPVPlexMigration migration : journalVpoolMigrations) {
                    if (journalVolume.getVirtualArray().equals(migration.getVarray())) {
                        // Need to make sure we're migrating the right Journal, so check to make sure the copy names match
                        boolean isSourceJournal = migration.getSubType().equals(Volume.PersonalityTypes.SOURCE) ? true : false;
                        String copyName = RPHelper.getCgCopyName(_dbClient, cg, migration.getVarray(), isSourceJournal);
                        if (journalVolume.getRpCopyName().equals(copyName)) {
                            journalMigration = migration;
                            break;
                        }
                    }
                }
                // a new task for the operation.
                if (journalMigration != null) {
                    // Make sure the journal volume is not involved in another task. If it is, an exception will
                    // be thrown.
                    BlockServiceUtils.checkForPendingTasks(journalVolume.getTenant().getURI(), Arrays.asList(journalVolume), _dbClient);
                    VirtualPool migrateToVpool = journalMigration.getMigrateToVpool();
                    logMigrations.append(String.format("\tRP+VPLEX migrate JOURNAL [%s](%s) to vpool [%s](%s)\n", journalVolume.getLabel(), journalVolume.getId(), migrateToVpool.getLabel(), migrateToVpool.getId()));
                    singleMigrations.put(journalVolume, migrateToVpool);
                } else {
                    _log.info(String.format("No migration info was found for Journal volume [%s](%s). Skipping...", journalVolume.getLabel(), journalVolume.getId()));
                }
            }
        }
    }
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) RPVPlexMigration(com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration) VirtualPool(com.emc.storageos.db.client.model.VirtualPool) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) BlockConsistencyGroup(com.emc.storageos.db.client.model.BlockConsistencyGroup)

Example 3 with RPVPlexMigration

use of com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration in project coprhd-controller by CoprHD.

the class RPBlockServiceApiImpl method findSourceAndTargetMigrations.

/**
 * Determines if there are any Source or Target migrations and if so adds them to the
 * containers passed in.
 *
 * @param volumes List of volumes to migrate
 * @param newVpool The newVpool for Source migrations
 * @param sourceMigrationsExist Determines if there are any source migrations
 * @param allSourceVolumesToMigrate Container for all Source volumes to migrate
 * @param targetMigrationsExist Determines if there are any Target migrations
 * @param allTargetVolumesToMigrate Container for all Target volumes to migrate
 * @param targetVpoolMigrations List of RPVPlexMigration for Target
 */
private void findSourceAndTargetMigrations(List<Volume> volumes, VirtualPool newVpool, boolean sourceMigrationsExist, HashMap<VirtualPool, List<Volume>> allSourceVolumesToMigrate, boolean targetMigrationsExist, HashMap<VirtualPool, List<Volume>> allTargetVolumesToMigrate, List<RPVPlexMigration> targetVpoolMigrations) {
    for (Volume volume : volumes) {
        if (sourceMigrationsExist) {
            // Group Source migrations by new vpool to Source volumes
            List<Volume> sourceVolumesToMigrate = allSourceVolumesToMigrate.get(newVpool);
            if (sourceVolumesToMigrate == null) {
                sourceVolumesToMigrate = new ArrayList<Volume>();
                allSourceVolumesToMigrate.put(newVpool, sourceVolumesToMigrate);
            }
            sourceVolumesToMigrate.add(volume);
        }
        if (targetMigrationsExist) {
            // Find the Targets for the volume
            StringSet rpTargets = volume.getRpTargets();
            for (String rpTargetId : rpTargets) {
                Volume rpTargetVolume = _dbClient.queryObject(Volume.class, URI.create(rpTargetId));
                // Check to see if this Target volume qualifies for migration
                RPVPlexMigration targetMigration = null;
                for (RPVPlexMigration migration : targetVpoolMigrations) {
                    if (rpTargetVolume.getVirtualArray().equals(migration.getVarray()) && rpTargetVolume.getVirtualPool().equals(migration.getMigrateFromVpool().getId())) {
                        targetMigration = migration;
                        break;
                    }
                }
                // a new task for the operation.
                if (targetMigration != null) {
                    // Make sure the target volume is not involved in another task. If it is, an exception will
                    // be thrown.
                    BlockServiceUtils.checkForPendingTasks(rpTargetVolume.getTenant().getURI(), Arrays.asList(rpTargetVolume), _dbClient);
                    // Make sure the target volume does not have any other restrictions and is
                    // valid for migrations (ex: may have snapshots)
                    VirtualPool migrateFromVpool = targetMigration.getMigrateFromVpool();
                    VirtualPool migrateToVpool = targetMigration.getMigrateToVpool();
                    BlockService.verifyVPlexVolumeForDataMigration(rpTargetVolume, migrateFromVpool, migrateToVpool, _dbClient);
                    // Group Target migrations by new vpool to Target volumes
                    List<Volume> targetVolumesToMigrate = allTargetVolumesToMigrate.get(migrateToVpool);
                    if (targetVolumesToMigrate == null) {
                        targetVolumesToMigrate = new ArrayList<Volume>();
                        allTargetVolumesToMigrate.put(migrateToVpool, targetVolumesToMigrate);
                    }
                    targetVolumesToMigrate.add(rpTargetVolume);
                } else {
                    _log.info(String.format("No migration info was found for Target volume [%s](%s). Skipping...", rpTargetVolume.getLabel(), rpTargetVolume.getId()));
                }
            }
        }
    }
}
Also used : Volume(com.emc.storageos.db.client.model.Volume) StringSet(com.emc.storageos.db.client.model.StringSet) RPVPlexMigration(com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration) VirtualPool(com.emc.storageos.db.client.model.VirtualPool)

Example 4 with RPVPlexMigration

use of com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration in project coprhd-controller by CoprHD.

the class RPBlockServiceApiImpl method rpVPlexDataMigration.

/**
 * Create the RP+VPLEX/MetroPoint Data Migration volume descriptors to be passed to the block orchestration
 * change vpool workflow.
 *
 * @param volumes The RP+VPLEX/MetroPoint volumes to migrate
 * @param newVpool The vpool to migrate to
 * @param taskId The task
 * @param validMigrations All valid migrations
 * @param vpoolChangeParam VirtualPool change parameters used to determine if need to suspend on migration
 * @return List of tasks
 * @throws InternalException
 */
private TaskList rpVPlexDataMigration(List<Volume> volumes, VirtualPool newVpool, String taskId, List<RPVPlexMigration> validMigrations, VirtualPoolChangeParam vpoolChangeParam) throws InternalException {
    // TaskList to return
    TaskList taskList = new TaskList();
    if (validMigrations == null || validMigrations.isEmpty()) {
        _log.warn(String.format("No RP+VPLEX migrations found"));
        return taskList;
    }
    _log.info(String.format("%s RP+VPLEX migrations found", validMigrations.size()));
    List<RPVPlexMigration> sourceVpoolMigrations = new ArrayList<RPVPlexMigration>();
    List<RPVPlexMigration> targetVpoolMigrations = new ArrayList<RPVPlexMigration>();
    List<RPVPlexMigration> journalVpoolMigrations = new ArrayList<RPVPlexMigration>();
    try {
        // Group the migrations by personality
        for (RPVPlexMigration migration : validMigrations) {
            switch(migration.getType()) {
                case SOURCE:
                    sourceVpoolMigrations.add(migration);
                    break;
                case TARGET:
                    targetVpoolMigrations.add(migration);
                    break;
                case METADATA:
                    journalVpoolMigrations.add(migration);
                    break;
                default:
                    break;
            }
        }
        // Convenience booleans to quickly check which migrations are required
        boolean sourceMigrationsExist = (!sourceVpoolMigrations.isEmpty());
        boolean targetMigrationsExist = (!targetVpoolMigrations.isEmpty());
        boolean journalMigrationsExist = (!journalVpoolMigrations.isEmpty());
        if (!sourceMigrationsExist && (targetMigrationsExist || journalMigrationsExist)) {
            // When there are no Source migrations and the Source volumes are in RGs we need
            // to make sure all those Source volumes are in the request.
            // 
            // Otherwise we could have the case where some Source volumes have been moved to a
            // new vpool and some have not.
            validateSourceVolumesInRGForMigrationRequest(volumes);
        }
        _log.info(String.format("%s SOURCE migrations, %s TARGET migrations, %s METADATA migrations", sourceVpoolMigrations.size(), targetVpoolMigrations.size(), journalVpoolMigrations.size()));
        // Buffer to log all the migrations
        StringBuffer logMigrations = new StringBuffer();
        logMigrations.append("\n\nRP+VPLEX Migrations:\n");
        // Step 2
        // 
        // Let's find out if there are any Source and Target volumes to migrate.
        // Source and Target migrations will be treated in two different ways depending
        // on if the VPLEX backend volumes are in an array Replication Group(RG) or not.
        // 
        // 1. In RG
        // Being in an RG means that the all volumes in the RG will need to be
        // grouped and migrated together.
        // NOTE:
        // a) All volumes in the RG will need to be selected for the operation to proceed.
        // b) There is restriction on the number of volumes in the RG that will be allowed for the migration.
        // Default value is 25 volumes. This is an existing limitation in the VPLEX code.
        // c) Journal volumes will never be in a backend RG.
        // 2. Not in RG
        // Treated as a normal single migration.
        HashMap<VirtualPool, List<Volume>> allSourceVolumesToMigrate = new HashMap<VirtualPool, List<Volume>>();
        HashMap<VirtualPool, List<Volume>> allTargetVolumesToMigrate = new HashMap<VirtualPool, List<Volume>>();
        findSourceAndTargetMigrations(volumes, newVpool, sourceMigrationsExist, allSourceVolumesToMigrate, targetMigrationsExist, allTargetVolumesToMigrate, targetVpoolMigrations);
        // Step 3
        // 
        // Handle all Source and Target migrations. The ones grouped by RG will
        // be migrated together. The others will be treated as single migrations.
        // Map to store single migrations (those not grouped by RG)
        Map<Volume, VirtualPool> singleMigrations = new HashMap<Volume, VirtualPool>();
        // Source
        // 
        // Source volumes could need to be grouped by RG or not (single migration).
        // 
        // Grouped migrations will have a migration WF initiated via the
        // call to migrateVolumesInReplicationGroup().
        // 
        // Single migrations will be collected afterwards to be migrated explicitly in Step 4 and 6
        // below.
        rpVPlexGroupedMigrations(allSourceVolumesToMigrate, singleMigrations, Volume.PersonalityTypes.SOURCE.name(), logMigrations, taskList, vpoolChangeParam);
        // Targets
        // 
        // Target volumes could need to be grouped by RG or not (single migration).
        // 
        // Grouped migrations will have a migration WF initiated via the
        // call to migrateVolumesInReplicationGroup().
        // 
        // Single migrations will be collected afterwards to be migrated explicitly in Step 4 and 6
        // below.
        rpVPlexGroupedMigrations(allTargetVolumesToMigrate, singleMigrations, Volume.PersonalityTypes.TARGET.name(), logMigrations, taskList, vpoolChangeParam);
        // Journals
        // 
        // Journals will never be in RGs so they will always be treated as single migrations.
        // Journal volumes must be checked against the CG. So we need to gather all affected
        // CGs in the request.
        // A new task will be generated to track each Journal migration.
        Set<URI> cgURIs = BlockConsistencyGroupUtils.getAllCGsFromVolumes(volumes);
        rpVPlexJournalMigrations(journalMigrationsExist, journalVpoolMigrations, singleMigrations, cgURIs, logMigrations);
        logMigrations.append("\n");
        _log.info(logMigrations.toString());
        // Step 4
        // 
        // Create the migration volume descriptors for all single migrations that are not in an RG.
        List<VolumeDescriptor> migrateVolumeDescriptors = new ArrayList<VolumeDescriptor>();
        for (Map.Entry<Volume, VirtualPool> entry : singleMigrations.entrySet()) {
            Volume migrateVolume = entry.getKey();
            VirtualPool migrateToVpool = entry.getValue();
            boolean allowHighAvailabilityMigrations = true;
            if (!migrateVolume.getAssociatedVolumes().isEmpty()) {
                // This is mainly an issue for RP+VPLEX journals.
                if (migrateVolume.getAssociatedVolumes().size() <= 1) {
                    allowHighAvailabilityMigrations = false;
                }
            } else {
                // Ex: Active Source journals that use the default Source vpool for provisioning.
                if (Volume.PersonalityTypes.METADATA.name().equals(migrateVolume.getPersonality())) {
                    allowHighAvailabilityMigrations = false;
                }
            }
            StorageSystem vplexStorageSystem = _dbClient.queryObject(StorageSystem.class, migrateVolume.getStorageController());
            migrateVolumeDescriptors.addAll(vplexBlockServiceApiImpl.createChangeVirtualPoolDescriptors(vplexStorageSystem, migrateVolume, migrateToVpool, taskId, null, null, null, allowHighAvailabilityMigrations));
        }
        // ensure the task is completed correctly and the vpools updated by the completer.
        if (!sourceMigrationsExist && (targetMigrationsExist || journalMigrationsExist)) {
            _log.info("No RP+VPLEX Source migrations detected, creating DUMMY_MIGRATE volume descriptors for the Source volumes.");
            for (Volume volume : volumes) {
                if (volume.checkPersonality(Volume.PersonalityTypes.SOURCE)) {
                    // Add the VPLEX Virtual Volume Descriptor for change vpool
                    VolumeDescriptor dummyMigrate = new VolumeDescriptor(VolumeDescriptor.Type.DUMMY_MIGRATE, volume.getStorageController(), volume.getId(), volume.getPool(), null);
                    Map<String, Object> volumeParams = new HashMap<String, Object>();
                    volumeParams.put(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID, volume.getId());
                    volumeParams.put(VolumeDescriptor.PARAM_VPOOL_CHANGE_NEW_VPOOL_ID, newVpool.getId());
                    volumeParams.put(VolumeDescriptor.PARAM_VPOOL_CHANGE_OLD_VPOOL_ID, volume.getVirtualPool());
                    dummyMigrate.setParameters(volumeParams);
                    migrateVolumeDescriptors.add(dummyMigrate);
                }
            }
        }
        // single migrations.
        if (!migrateVolumeDescriptors.isEmpty()) {
            // Generate the correct task information for single migrations
            List<Volume> migrationVolumes = new ArrayList<Volume>();
            migrationVolumes.addAll(singleMigrations.keySet());
            taskList.getTaskList().addAll(createTasksForVolumes(newVpool, migrationVolumes, taskId).getTaskList());
            // Invoke the block orchestrator for the change vpool operation
            BlockOrchestrationController controller = getController(BlockOrchestrationController.class, BlockOrchestrationController.BLOCK_ORCHESTRATION_DEVICE);
            controller.changeVirtualPool(migrateVolumeDescriptors, taskId);
        } else {
            _log.info(String.format("No extra migrations needed."));
        }
    } catch (Exception e) {
        String errorMsg = String.format("Volume VirtualPool change error: %s", e.getMessage());
        _log.error(errorMsg, e);
        for (TaskResourceRep volumeTask : taskList.getTaskList()) {
            volumeTask.setState(Operation.Status.error.name());
            volumeTask.setMessage(errorMsg);
            _dbClient.updateTaskOpStatus(Volume.class, volumeTask.getResource().getId(), taskId, new Operation(Operation.Status.error.name(), errorMsg));
        }
        throw e;
    }
    return taskList;
}
Also used : BlockOrchestrationController(com.emc.storageos.blockorchestrationcontroller.BlockOrchestrationController) HashMap(java.util.HashMap) TaskList(com.emc.storageos.model.TaskList) ArrayList(java.util.ArrayList) Operation(com.emc.storageos.db.client.model.Operation) NamedURI(com.emc.storageos.db.client.model.NamedURI) URI(java.net.URI) RPVPlexMigration(com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration) ApplicationAddVolumeList(com.emc.storageos.volumecontroller.ApplicationAddVolumeList) ArrayList(java.util.ArrayList) TaskList(com.emc.storageos.model.TaskList) VolumeGroupVolumeList(com.emc.storageos.model.application.VolumeGroupUpdateParam.VolumeGroupVolumeList) URIQueryResultList(com.emc.storageos.db.client.constraint.URIQueryResultList) StorageSystemConnectivityList(com.emc.storageos.model.systems.StorageSystemConnectivityList) List(java.util.List) StorageSystem(com.emc.storageos.db.client.model.StorageSystem) VolumeDescriptor(com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor) TaskResourceRep(com.emc.storageos.model.TaskResourceRep) VirtualPool(com.emc.storageos.db.client.model.VirtualPool) InternalException(com.emc.storageos.svcs.errorhandling.resources.InternalException) InternalServerErrorException(com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException) ControllerException(com.emc.storageos.volumecontroller.ControllerException) APIException(com.emc.storageos.svcs.errorhandling.resources.APIException) RecoverPointException(com.emc.storageos.recoverpoint.exceptions.RecoverPointException) Volume(com.emc.storageos.db.client.model.Volume) DiscoveredDataObject(com.emc.storageos.db.client.model.DiscoveredDataObject) DataObject(com.emc.storageos.db.client.model.DataObject) Map(java.util.Map) OpStatusMap(com.emc.storageos.db.client.model.OpStatusMap) HashMap(java.util.HashMap)

Aggregations

RPVPlexMigration (com.emc.storageos.api.service.impl.resource.utils.RPVPlexMigration)4 VirtualPool (com.emc.storageos.db.client.model.VirtualPool)4 Volume (com.emc.storageos.db.client.model.Volume)4 NamedURI (com.emc.storageos.db.client.model.NamedURI)2 TaskList (com.emc.storageos.model.TaskList)2 URI (java.net.URI)2 ArrayList (java.util.ArrayList)2 BlockOrchestrationController (com.emc.storageos.blockorchestrationcontroller.BlockOrchestrationController)1 VolumeDescriptor (com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor)1 URIQueryResultList (com.emc.storageos.db.client.constraint.URIQueryResultList)1 BlockConsistencyGroup (com.emc.storageos.db.client.model.BlockConsistencyGroup)1 DataObject (com.emc.storageos.db.client.model.DataObject)1 DiscoveredDataObject (com.emc.storageos.db.client.model.DiscoveredDataObject)1 OpStatusMap (com.emc.storageos.db.client.model.OpStatusMap)1 Operation (com.emc.storageos.db.client.model.Operation)1 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)1 StringSet (com.emc.storageos.db.client.model.StringSet)1 TaskResourceRep (com.emc.storageos.model.TaskResourceRep)1 VolumeGroupVolumeList (com.emc.storageos.model.application.VolumeGroupUpdateParam.VolumeGroupVolumeList)1 StorageSystemConnectivityList (com.emc.storageos.model.systems.StorageSystemConnectivityList)1