Search in sources :

Example 1 with VPlexMigrationInfo

use of com.emc.storageos.vplex.api.VPlexMigrationInfo in project coprhd-controller by CoprHD.

the class VPlexDeviceController method commitMigration.

/**
 * Invoked by the migration workflow to commit the migration after it has
 * been completed.
 *
 * @param vplexURI
 *            The URI of the VPlex storage system.
 * @param virtualVolumeURI
 *            The URI of the virtual volume.
 * @param migrationURI
 *            The URI of the data migration.
 * @param rename
 *            Indicates if the volume should be renamed after commit to
 *            conform to ViPR standard naming conventions.
 * @param newVpoolURI - the new virtual pool for the virtual volume (or null if not changing)
 * @param newVarrayURI - the new varray for the virtual volume (or null if not changing)
 * @param stepId
 *            The workflow step identifier.
 *
 * @throws WorkflowException
 */
public void commitMigration(URI vplexURI, URI virtualVolumeURI, URI migrationURI, Boolean rename, URI newVpoolURI, URI newVarrayURI, String stepId) throws WorkflowException {
    _log.info("Committing migration {}", migrationURI);
    Migration migration = null;
    VPlexApiClient client = null;
    try {
        // Update step state to executing.
        WorkflowStepCompleter.stepExecuting(stepId);
        // Get the migration.
        migration = getDataObject(Migration.class, migrationURI, _dbClient);
        // workflow, so check the status.
        if (!VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue().equals(migration.getMigrationStatus())) {
            // Get the VPlex API client.
            StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
            client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
            _log.info("Got VPlex API client for system {}", vplexURI);
            // Make a call to the VPlex API client to commit the migration.
            // Note that for ingested VPLEX volumes created outside ViPR, we
            // don't want to update the name.
            List<VPlexMigrationInfo> migrationInfoList = new ArrayList<VPlexMigrationInfo>();
            Volume virtualVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
            try {
                migrationInfoList = client.commitMigrations(virtualVolume.getDeviceLabel(), Arrays.asList(migration.getLabel()), true, true, rename.booleanValue());
                _log.info("Committed migration {}", migration.getLabel());
            } catch (VPlexApiException vae) {
                _log.error("Exception committing VPlex migration: " + vae.getMessage(), vae);
                boolean committed = false;
                // Check the migration status. Maybe it committed even though we had an error.
                VPlexMigrationInfo migrationInfo = client.getMigrationInfo(migration.getLabel());
                if (migrationInfo.getStatus().equalsIgnoreCase(VPlexMigrationInfo.MigrationStatus.COMMITTED.name())) {
                    _log.info("Migration {} has committed despite exception", migration.getLabel());
                    migrationInfoList.clear();
                    migrationInfoList.add(migrationInfo);
                    committed = true;
                } else {
                    _log.info("Migration {} status {}", migration.getLabel(), migrationInfo.getStatus());
                }
                if (!committed) {
                    // This was observed at customer site COP-21257
                    if (vae.getServiceCode() == ServiceCode.VPLEX_API_RESPONSE_TIMEOUT_ERROR) {
                        // We are going to throw an error, but we don't want to rollback completely
                        _workflowService.setWorkflowRollbackContOnError(stepId, false);
                    }
                    WorkflowStepCompleter.stepFailed(stepId, vae);
                    return;
                }
            }
            // Below this point migration is committed, no turning back.
            // Initialize the migration info in the database.
            migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue());
            _dbClient.updateObject(migration);
            _log.info("Update migration status to committed");
            // Update the virtual volume native id and associated
            // volumes. Note that we don't update CoS until all
            // commits are successful.
            VPlexVirtualVolumeInfo updatedVirtualVolumeInfo = migrationInfoList.get(0).getVirtualVolumeInfo();
            // update any properties that were changed after migration including deviceLabel, nativeGuid, and nativeId.
            // also, if the updated volume isn't thin-enabled, it is thin-capable, and the target vpool supports thin
            // provisioning, then a call should be made to the VPLEX to flip the thin-enabled flag on for this volume.
            URI targetVolumeUri = migration.getTarget();
            Volume targetVolume = getDataObject(Volume.class, targetVolumeUri, _dbClient);
            if (updatedVirtualVolumeInfo != null) {
                _log.info(String.format("New virtual volume is %s", updatedVirtualVolumeInfo.toString()));
                // if the new virtual volume is thin-capable, but thin-enabled is not true,
                // that means we need to ask the VPLEX to convert it to a thin-enabled volume.
                // this doesn't happen automatically for thick-to-thin data migrations.
                boolean isThinEnabled = updatedVirtualVolumeInfo.isThinEnabled();
                if (!isThinEnabled && VPlexApiConstants.TRUE.equalsIgnoreCase(updatedVirtualVolumeInfo.getThinCapable())) {
                    if (verifyVplexSupportsThinProvisioning(vplexSystem)) {
                        if (null != targetVolume) {
                            _log.info(String.format("migration target Volume is %s", targetVolume.forDisplay()));
                            VirtualPool targetVirtualPool = getDataObject(VirtualPool.class, targetVolume.getVirtualPool(), _dbClient);
                            if (null != targetVirtualPool) {
                                _log.info(String.format("migration target VirtualPool is %s", targetVirtualPool.forDisplay()));
                                boolean doEnableThin = VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(targetVirtualPool.getSupportedProvisioningType());
                                if (doEnableThin) {
                                    _log.info(String.format("the new VirtualPool is thin, requesting VPLEX to enable thin provisioning on %s", updatedVirtualVolumeInfo.getName()));
                                    isThinEnabled = client.setVirtualVolumeThinEnabled(updatedVirtualVolumeInfo);
                                }
                            }
                        }
                    }
                }
                virtualVolume.setDeviceLabel(updatedVirtualVolumeInfo.getName());
                virtualVolume.setNativeId(updatedVirtualVolumeInfo.getPath());
                virtualVolume.setNativeGuid(updatedVirtualVolumeInfo.getPath());
                virtualVolume.setThinlyProvisioned(isThinEnabled);
            }
            // Note that for ingested volumes, there will be no associated volumes
            // at first.
            StringSet assocVolumes = virtualVolume.getAssociatedVolumes();
            if ((assocVolumes != null) && (!assocVolumes.isEmpty())) {
                // For a distributed volume, there could be multiple
                // migrations. When the first completes, there will
                // be no associated volumes. However, when the second
                // completes, there will be associated volumes. However,
                // the migration source could be null.
                URI sourceVolumeUri = migration.getSource();
                if (sourceVolumeUri != null) {
                    assocVolumes.remove(sourceVolumeUri.toString());
                    // Retain any previous RP fields on the new target volume.
                    Volume sourceVolume = getDataObject(Volume.class, sourceVolumeUri, _dbClient);
                    if (sourceVolume != null) {
                        boolean targetUpdated = false;
                        if (NullColumnValueGetter.isNotNullValue(sourceVolume.getRpCopyName())) {
                            targetVolume.setRpCopyName(sourceVolume.getRpCopyName());
                            targetUpdated = true;
                        }
                        if (NullColumnValueGetter.isNotNullValue(sourceVolume.getInternalSiteName())) {
                            targetVolume.setInternalSiteName(sourceVolume.getInternalSiteName());
                            targetUpdated = true;
                        }
                        if (targetUpdated) {
                            _dbClient.updateObject(targetVolume);
                        }
                    }
                }
                assocVolumes.add(migration.getTarget().toString());
            } else {
                // NOTE: Now an ingested volume will have associated volumes.
                // It will no longer be considered an ingested volume.
                assocVolumes = new StringSet();
                assocVolumes.add(migration.getTarget().toString());
                virtualVolume.setAssociatedVolumes(assocVolumes);
            }
            updateMigratedVirtualVolumeVpoolAndVarray(virtualVolume, newVpoolURI, newVarrayURI);
            _dbClient.updateObject(virtualVolume);
            _log.info("Updated virtual volume.");
        } else {
            _log.info("The migration is already committed.");
            // Note that we don't set the device label and native id. If the
            // migration was committed outside of Bourne, the virtual volume
            // will still have the old name. If it was committed through
            // Bourne, these values would already have been update.
            // Regardless, we have to update the vpool, and we update the
            // associated volumes in case it was committed outside of
            // Bourne.
            associateVplexVolumeWithMigratedTarget(migration, virtualVolumeURI);
            _log.info("Updated virtual volume.");
        }
        // Update the workflow step status.
        StringBuilder successMsgBuilder = new StringBuilder();
        successMsgBuilder.append("VPlex System: ");
        successMsgBuilder.append(vplexURI);
        successMsgBuilder.append(" migration: ");
        successMsgBuilder.append(migrationURI);
        successMsgBuilder.append(" was committed");
        _log.info(successMsgBuilder.toString());
        WorkflowStepCompleter.stepSucceded(stepId);
        _log.info("Updated workflow step state to success");
    } catch (VPlexApiException vae) {
        _log.error("Exception committing VPlex migration: " + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception committing VPlex migration: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.COMMIT_VOLUME_MIGRATION.getName();
        ServiceError serviceError = VPlexApiException.errors.commitMigrationFailed(opName, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Migration(com.emc.storageos.db.client.model.Migration) ArrayList(java.util.ArrayList) VirtualPool(com.emc.storageos.db.client.model.VirtualPool) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) 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) VPlexMigrationInfo(com.emc.storageos.vplex.api.VPlexMigrationInfo) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) StringSet(com.emc.storageos.db.client.model.StringSet) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 2 with VPlexMigrationInfo

use of com.emc.storageos.vplex.api.VPlexMigrationInfo in project coprhd-controller by CoprHD.

the class VPlexDeviceController method rollbackCommitMigration.

/**
 * Rollback when a migration commit fails.
 *
 * @param migrationURIs
 *            The URIs for all migrations.
 * @param newVpoolURI
 *            The URI of the new Vpool after migration commit
 * @param newVarrayURI
 *            The URI of the new Varray after migration commit
 * @param commitStepId
 *            The commit step id.
 * @param stepId
 *            The rollback step id.
 *
 * @throws WorkflowException
 */
public void rollbackCommitMigration(List<URI> migrationURIs, URI newVpoolURI, URI newVarrayURI, String commitStepId, String stepId) throws WorkflowException {
    // Update step state to executing.
    WorkflowStepCompleter.stepExecuting(stepId);
    try {
        // Determine if any migration was successfully committed.
        boolean migrationCommitted = false;
        Iterator<URI> migrationIter = migrationURIs.iterator();
        while (migrationIter.hasNext()) {
            URI migrationURI = migrationIter.next();
            Migration migration = _dbClient.queryObject(Migration.class, migrationURI);
            Volume volume = _dbClient.queryObject(Volume.class, migration.getVolume());
            // Check migration database record for committed state
            if (VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue().equals(migration.getMigrationStatus())) {
                migrationCommitted = true;
                updateMigratedVirtualVolumeVpoolAndVarray(volume, newVpoolURI, newVarrayURI);
                _dbClient.updateObject(volume);
                inventoryDeleteMigrationSource(migration.getSource(), volume);
                continue;
            }
            // Check vplex hardware migration records for committed state
            VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, volume.getStorageController(), _dbClient);
            VPlexMigrationInfo migrationInfo = client.getMigrationInfo(migration.getLabel());
            if (migrationInfo.getStatus().equalsIgnoreCase(VPlexMigrationInfo.MigrationStatus.COMMITTED.name())) {
                migrationCommitted = true;
                migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.COMMITTED.name());
                _dbClient.updateObject(migration);
                associateVplexVolumeWithMigratedTarget(migration, migration.getVolume());
                updateMigratedVirtualVolumeVpoolAndVarray(volume, newVpoolURI, newVarrayURI);
                _dbClient.updateObject(volume);
                inventoryDeleteMigrationSource(migration.getSource(), volume);
                continue;
            }
        }
        // creation step will cancel the migration.
        if (migrationCommitted) {
            _log.info("The migration has already been committed or the migration state can not be determined, failing rollback");
            // Don't allow rollback to go further than the first error.
            _workflowService.setWorkflowRollbackContOnError(stepId, false);
            ServiceError serviceError = VPlexApiException.errors.cantRollbackCommittedMigration();
            WorkflowStepCompleter.stepFailed(stepId, serviceError);
        } else {
            _log.info("No Migrations are not committed");
            WorkflowStepCompleter.stepSucceded(stepId);
        }
    } catch (Exception e) {
        _log.info("Exception determining commit rollback state", e);
        // Don't allow rollback to go further than the first error.
        _workflowService.setWorkflowRollbackContOnError(stepId, false);
        ServiceError serviceError = VPlexApiException.errors.cantRollbackExceptionDeterminingCommitState(e);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : VPlexMigrationInfo(com.emc.storageos.vplex.api.VPlexMigrationInfo) ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) Volume(com.emc.storageos.db.client.model.Volume) Migration(com.emc.storageos.db.client.model.Migration) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) 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)

Example 3 with VPlexMigrationInfo

use of com.emc.storageos.vplex.api.VPlexMigrationInfo in project coprhd-controller by CoprHD.

the class VPlexDeviceController method migrateVirtualVolume.

/**
 * Creates and starts a VPlex data migration for the passed virtual volume
 * on the passed VPlex storage system. The passed target is a newly created
 * backend volume to which the data will be migrated. The source for the
 * data migration is the current backend volume for the virtual volume that
 * is in the same varray as the passed target. The method also creates
 * a migration job to monitor the progress of the migration. The workflow
 * step will complete when the migration completes, at which point the
 * migration is automatically committed.
 *
 * @param vplexURI
 *            The URI of the VPlex storage system.
 * @param virtualVolumeURI
 *            The URI of the virtual volume.
 * @param targetVolumeURI
 *            The URI of the migration target.
 * @param migrationURI
 *            The URI of the migration.
 * @param newNhURI
 *            The URI of the new varray for the virtual volume
 *            when a local virtual volume is being migrated to the other
 *            cluster, or null.
 * @param stepId
 *            The workflow step identifier.
 * @throws WorkflowException
 */
public void migrateVirtualVolume(URI vplexURI, URI virtualVolumeURI, URI targetVolumeURI, URI migrationURI, URI newNhURI, String stepId) throws WorkflowException {
    _log.info("Migration {} using target {}", migrationURI, targetVolumeURI);
    try {
        // Update step state to executing.
        WorkflowStepCompleter.stepExecuting(stepId);
        // Initialize the step data. The step data indicates if we
        // successfully started the migration and is used in
        // rollback.
        _workflowService.storeStepData(stepId, Boolean.FALSE);
        // Get the virtual volume.
        Volume virtualVolume = getDataObject(Volume.class, virtualVolumeURI, _dbClient);
        String virtualVolumeName = virtualVolume.getDeviceLabel();
        _log.info("Virtual volume name is {}", virtualVolumeName);
        // Setup the native volume info for the migration target.
        Volume migrationTarget = getDataObject(Volume.class, targetVolumeURI, _dbClient);
        StorageSystem targetStorageSystem = getDataObject(StorageSystem.class, migrationTarget.getStorageController(), _dbClient);
        _log.info("Storage system for migration target is {}", migrationTarget.getStorageController());
        List<String> itls = VPlexControllerUtils.getVolumeITLs(migrationTarget);
        VolumeInfo nativeVolumeInfo = new VolumeInfo(targetStorageSystem.getNativeGuid(), targetStorageSystem.getSystemType(), migrationTarget.getWWN().toUpperCase().replaceAll(":", ""), migrationTarget.getNativeId(), migrationTarget.getThinlyProvisioned().booleanValue(), itls);
        // Get the migration associated with the target.
        Migration migration = getDataObject(Migration.class, migrationURI, _dbClient);
        // Determine the unique name for the migration. We identifying
        // the migration source and target, using array serial number
        // and volume native id, in the migration name. This was fine
        // for VPlex extent migration, which has a max length of 63
        // for the migration name. However, for remote migrations,
        // which require VPlex device migration, the max length is much
        // more restrictive, like 20 characters. So, we switched over
        // timestamps.
        StringBuilder migrationNameBuilder = new StringBuilder(MIGRATION_NAME_PREFIX);
        DateFormat dateFormatter = new SimpleDateFormat(MIGRATION_NAME_DATE_FORMAT);
        migrationNameBuilder.append(dateFormatter.format(new Date()));
        String migrationName = migrationNameBuilder.toString();
        migration.setLabel(migrationName);
        _dbClient.updateObject(migration);
        _log.info("Migration name is {}", migrationName);
        // Get the VPlex API client.
        StorageSystem vplexSystem = getDataObject(StorageSystem.class, vplexURI, _dbClient);
        VPlexApiClient client = getVPlexAPIClient(_vplexApiFactory, vplexSystem, _dbClient);
        _log.info("Got VPlex API client for VPlex {}", vplexURI);
        // Get the configured migration speed
        String speed = customConfigHandler.getComputedCustomConfigValue(CustomConfigConstants.MIGRATION_SPEED, vplexSystem.getSystemType(), null);
        _log.info("Migration speed is {}", speed);
        String transferSize = migrationSpeedToTransferSizeMap.get(speed);
        // Make a call to the VPlex API client to migrate the virtual
        // volume. Note that we need to do a remote migration when a
        // local virtual volume is being migrated to the other VPlex
        // cluster. If the passed new varray is not null, then
        // this is the case.
        Boolean isRemoteMigration = newNhURI != null;
        // We support both device and extent migrations, however,
        // when we don't know anything about the backend volumes
        // we must use device migration.
        Boolean useDeviceMigration = migration.getSource() == null;
        List<VPlexMigrationInfo> migrationInfoList = client.migrateVirtualVolume(migrationName, virtualVolumeName, Arrays.asList(nativeVolumeInfo), isRemoteMigration, useDeviceMigration, true, true, transferSize);
        _log.info("Started VPlex migration");
        // We store step data indicating that the migration was successfully
        // create and started. We will use this to determine the behavior
        // on rollback. If we never got to the point that the migration
        // was created and started, then there is no rollback to attempt
        // on the VLPEX as the migrate API already tried to clean everything
        // up on the VLPEX.
        _workflowService.storeStepData(stepId, Boolean.TRUE);
        // Initialize the migration info in the database.
        VPlexMigrationInfo migrationInfo = migrationInfoList.get(0);
        migration.setMigrationStatus(VPlexMigrationInfo.MigrationStatus.READY.getStatusValue());
        migration.setPercentDone("0");
        migration.setStartTime(migrationInfo.getStartTime());
        _dbClient.updateObject(migration);
        _log.info("Update migration info");
        // Create a migration task completer and queue a job to monitor
        // the migration progress. The completer will be invoked by the
        // job when the migration completes.
        MigrationTaskCompleter migrationCompleter = new MigrationTaskCompleter(migrationURI, stepId);
        VPlexMigrationJob migrationJob = new VPlexMigrationJob(migrationCompleter);
        migrationJob.setTimeoutTimeMsec(MINUTE_TO_MILLISECONDS * Long.valueOf(ControllerUtils.getPropertyValueFromCoordinator(coordinator, CONTROLLER_VPLEX_MIGRATION_TIMEOUT_MINUTES)));
        ControllerServiceImpl.enqueueJob(new QueueJob(migrationJob));
        _log.info("Queued job to monitor migration progress.");
    } catch (VPlexApiException vae) {
        _log.error("Exception migrating VPlex virtual volume: " + vae.getMessage(), vae);
        WorkflowStepCompleter.stepFailed(stepId, vae);
    } catch (Exception ex) {
        _log.error("Exception migrating VPlex virtual volume: " + ex.getMessage(), ex);
        String opName = ResourceOperationTypeEnum.MIGRATE_VIRTUAL_VOLUME.getName();
        ServiceError serviceError = VPlexApiException.errors.migrateVirtualVolume(opName, ex);
        WorkflowStepCompleter.stepFailed(stepId, serviceError);
    }
}
Also used : ServiceError(com.emc.storageos.svcs.errorhandling.model.ServiceError) MigrationTaskCompleter(com.emc.storageos.vplexcontroller.completers.MigrationTaskCompleter) Migration(com.emc.storageos.db.client.model.Migration) VolumeInfo(com.emc.storageos.vplex.api.clientdata.VolumeInfo) VPlexVirtualVolumeInfo(com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo) Date(java.util.Date) 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) VPlexMigrationInfo(com.emc.storageos.vplex.api.VPlexMigrationInfo) VPlexMigrationJob(com.emc.storageos.vplexcontroller.job.VPlexMigrationJob) Volume(com.emc.storageos.db.client.model.Volume) VPlexApiException(com.emc.storageos.vplex.api.VPlexApiException) SimpleDateFormat(java.text.SimpleDateFormat) DateFormat(java.text.DateFormat) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) SimpleDateFormat(java.text.SimpleDateFormat) QueueJob(com.emc.storageos.volumecontroller.impl.job.QueueJob) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Example 4 with VPlexMigrationInfo

use of com.emc.storageos.vplex.api.VPlexMigrationInfo in project coprhd-controller by CoprHD.

the class VPlexMigrationJob method poll.

/**
 * {@inheritDoc}
 */
public JobPollResult poll(JobContext jobContext, long trackingPeriodInMillis) {
    s_logger.debug("Polled migration job");
    Migration migration = null;
    StorageSystem vplexSystem = null;
    try {
        // Therefore, the default max retries is 240.
        if (_maxRetries == null) {
            if (trackingPeriodInMillis < MAX_TIME_FOR_SUCCESSFUL_STATUS_CHECK_MS) {
                _maxRetries = new Integer(Math.round(MAX_TIME_FOR_SUCCESSFUL_STATUS_CHECK_MS / trackingPeriodInMillis));
            } else {
                _maxRetries = new Integer(1);
            }
        }
        // Get the DB client from the job context.
        DbClient dbClient = jobContext.getDbClient();
        // Get the migration associated with this job.
        migration = dbClient.queryObject(Migration.class, _taskCompleter.getId());
        String migrationName = migration.getLabel();
        s_logger.debug("Migration is {}", migration.getId());
        // Get the virtual volume associated with the migration
        // and then get the VPlex storage system for that virtual
        // volume.
        Volume virtualVolume = dbClient.queryObject(Volume.class, migration.getVolume());
        s_logger.debug("Virtual volume is {}", virtualVolume.getId());
        vplexSystem = dbClient.queryObject(StorageSystem.class, virtualVolume.getStorageController());
        s_logger.debug("VPlex system is {}", vplexSystem.getId());
        // Get the VPlex API client for this VPlex storage system
        // and get the latest info for the migration.
        VPlexApiClient vplexApiClient = VPlexControllerUtils.getVPlexAPIClient(jobContext.getVPlexApiFactory(), vplexSystem, dbClient);
        s_logger.debug("Got VPlex APi Client");
        VPlexMigrationInfo migrationInfo = vplexApiClient.getMigrationInfo(migrationName);
        s_logger.debug("Got migration info from VPlex");
        // Update the migration in the database to reflect the
        // current status and percent done.
        String migrationStatus = migrationInfo.getStatus();
        s_logger.debug("Migration status is {}", migrationStatus);
        migration.setMigrationStatus(migrationStatus);
        int percentDone = getMigrationPercentDone(migrationInfo.getPercentageDone());
        s_logger.debug("Migration percent done is {}", percentDone);
        migration.setPercentDone(String.valueOf(percentDone));
        dbClient.persistObject(migration);
        // Update the job info.
        _pollResult.setJobName(migrationName);
        _pollResult.setJobId(virtualVolume.getId().toString());
        _pollResult.setJobPercentComplete(percentDone);
        s_logger.debug("Updated poll result");
        // Examine the status.
        if (VPlexMigrationInfo.MigrationStatus.COMPLETE.getStatusValue().equals(migrationStatus)) {
            // Completed successfully
            s_logger.info("Migration: {} completed sucessfully", migration.getId());
            _status = JobStatus.SUCCESS;
        } else if (VPlexMigrationInfo.MigrationStatus.COMMITTED.getStatusValue().equals(migrationStatus)) {
            // The migration job completed and somehow it was committed
            // outside the scope of the workflow that created the
            // migration job. We return success here to ensure that there
            // is no rollback in the workflow that could end up deleting
            // the target volume of the migration.
            s_logger.info("Migration: {} completed and was committed", migration.getId());
            _status = JobStatus.SUCCESS;
        } else if (VPlexMigrationInfo.MigrationStatus.CANCELLED.getStatusValue().equals(migrationStatus)) {
            // The migration job was cancelled outside the scope of the
            // workflow that created the migration job.
            _errorDescription = "The migration was cancelled";
            s_logger.info("Migration: {} was cancelled prior to completion", migration.getId());
            _status = JobStatus.FAILED;
        } else if (VPlexMigrationInfo.MigrationStatus.ERROR.getStatusValue().equals(migrationStatus)) {
            // The migration failed.
            _errorDescription = "The migration failed";
            s_logger.error("Migration {} failed prior to completion", migration.getId());
            _status = JobStatus.FAILED;
        }
        // We had a successful check of the status. Reset the retry
        // count in case the job is still in progress and the next
        // attempt to check the status fails.
        _retryCount = 0;
    } catch (Exception e) {
        s_logger.error(String.format("Unexpected error getting status of migration %s on VPlex %s: %s", (migration != null ? migration.getId() : "null"), (vplexSystem != null ? vplexSystem.getId() : "null"), _errorDescription), e);
        if (++_retryCount > _maxRetries) {
            _errorDescription = e.getMessage();
            _status = JobStatus.FAILED;
        }
    } finally {
        s_logger.debug("Updating status {}", _status);
        updateStatus(jobContext);
    }
    _pollResult.setJobStatus(_status);
    _pollResult.setErrorDescription(_errorDescription);
    return _pollResult;
}
Also used : VPlexMigrationInfo(com.emc.storageos.vplex.api.VPlexMigrationInfo) DbClient(com.emc.storageos.db.client.DbClient) Volume(com.emc.storageos.db.client.model.Volume) Migration(com.emc.storageos.db.client.model.Migration) VPlexApiClient(com.emc.storageos.vplex.api.VPlexApiClient) URISyntaxException(java.net.URISyntaxException) StorageSystem(com.emc.storageos.db.client.model.StorageSystem)

Aggregations

Migration (com.emc.storageos.db.client.model.Migration)4 Volume (com.emc.storageos.db.client.model.Volume)4 VPlexApiClient (com.emc.storageos.vplex.api.VPlexApiClient)4 VPlexMigrationInfo (com.emc.storageos.vplex.api.VPlexMigrationInfo)4 URISyntaxException (java.net.URISyntaxException)4 StorageSystem (com.emc.storageos.db.client.model.StorageSystem)3 DatabaseException (com.emc.storageos.db.exceptions.DatabaseException)3 DeviceControllerException (com.emc.storageos.exceptions.DeviceControllerException)3 ServiceError (com.emc.storageos.svcs.errorhandling.model.ServiceError)3 InternalException (com.emc.storageos.svcs.errorhandling.resources.InternalException)3 InternalServerErrorException (com.emc.storageos.svcs.errorhandling.resources.InternalServerErrorException)3 ControllerException (com.emc.storageos.volumecontroller.ControllerException)3 VPlexApiException (com.emc.storageos.vplex.api.VPlexApiException)3 WorkflowException (com.emc.storageos.workflow.WorkflowException)3 IOException (java.io.IOException)3 NamedURI (com.emc.storageos.db.client.model.NamedURI)2 VPlexVirtualVolumeInfo (com.emc.storageos.vplex.api.VPlexVirtualVolumeInfo)2 URI (java.net.URI)2 DbClient (com.emc.storageos.db.client.DbClient)1 StringSet (com.emc.storageos.db.client.model.StringSet)1