/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.externaldevice.job; import java.io.Serializable; import java.net.URI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.storagedriver.BlockStorageDriver; import com.emc.storageos.storagedriver.DriverTask; import com.emc.storageos.storagedriver.DriverTask.TaskStatus; import com.emc.storageos.svcs.errorhandling.model.ServiceCoded; import com.emc.storageos.volumecontroller.Job; import com.emc.storageos.volumecontroller.JobContext; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.JobPollResult; import com.emc.storageos.volumecontroller.impl.externaldevice.ExternalBlockStorageDevice; import com.emc.storageos.volumecontroller.impl.externaldevice.ExternalDeviceException; /** * Job checks the progress of an external device driver operation. */ abstract public class ExternalDeviceJob extends Job implements Serializable { // For serialization interface. private static final long serialVersionUID = 1L; // The URI of the external storage system on which the task is running. protected URI _storageSystemURI; // The id of the task monitored by the job. private String _driverTaskId; // A reference to the task completer private TaskCompleter _taskCompleter; // A reference to the poll result. private JobPollResult _pollResult = new JobPollResult(); // A reference to the job status. protected JobStatus _status = JobStatus.IN_PROGRESS; // A reference to an error description. private String _errorDescription = null; // Logger reference. private static final Logger s_logger = LoggerFactory.getLogger(ExternalDeviceJob.class); /** * Constructor. * * @param storageSystemURI The URI of the external storage system on which the task is running. * @param driverTaskId The id of the task monitored by the job. * @param taskCompleter The task completer. */ public ExternalDeviceJob(URI storageSystemURI, String driverTaskId, TaskCompleter taskCompleter) { _storageSystemURI = storageSystemURI; _driverTaskId = driverTaskId; _taskCompleter = taskCompleter; } /** * {@inheritDoc} */ public JobPollResult poll(JobContext jobContext, long trackingPeriodInMillis) { s_logger.info("Polled external device job for driver task {} on storage system {}", _driverTaskId, _storageSystemURI); DriverTask driverTask = null; DbClient dbClient = jobContext.getDbClient(); try { // Update the job info. _pollResult.setJobName(_driverTaskId); _pollResult.setJobId(_driverTaskId); _pollResult.setJobPercentComplete(0); // Get the external storage system on which the driver task is running. StorageSystem storageSystem = dbClient.queryObject(StorageSystem.class, _storageSystemURI); if (storageSystem == null) { s_logger.error("Could not find external storage system {}", _storageSystemURI); throw ExternalDeviceException.exceptions.cantFindStorageSystemForDriverTask( _storageSystemURI.toString(), _driverTaskId); } String systemType = storageSystem.getSystemType(); // Get the external storage driver for the system on which the task is executing. BlockStorageDriver driver = ExternalBlockStorageDevice.getBlockStorageDriver(systemType); if (driver == null) { s_logger.error("Could not find storage driver for system type {}", systemType); throw ExternalDeviceException.exceptions.noDriverDefinedForDevice(systemType); } // Get the storage driver task. driverTask = driver.getTask(_driverTaskId); if (driverTask == null) { s_logger.error("Could not find storage driver task {} for storage system {}", _driverTaskId, _storageSystemURI.toString()); throw ExternalDeviceException.exceptions.cantFindDriverTaskOnSystem( _driverTaskId, _storageSystemURI.toString()); } TaskStatus taskStatus = driverTask.getStatus(); String taskStatusMsg = driverTask.getMessage(); if (isTaskSuccessful(taskStatus)) { // Completed successfully s_logger.info(String.format("Task %s completed successfully with status %s:%s", _driverTaskId, taskStatus, taskStatusMsg)); doTaskSucceeded(driverTask, dbClient); _pollResult.setJobPercentComplete(100); _status = JobStatus.SUCCESS; } else if (isTaskFailed(taskStatus)) { // Failed. s_logger.info(String.format("Task %s failed with status %s:%s", _driverTaskId, taskStatus, taskStatusMsg)); doTaskFailed(driverTask, dbClient); _pollResult.setJobPercentComplete(100); _errorDescription = taskStatusMsg; _status = JobStatus.FAILED; } } catch (Exception e) { _errorDescription = e.getMessage(); s_logger.error(String.format( "Unexpected error getting external driver task status for task %s on storage system %s: %s", _driverTaskId, _storageSystemURI.toString(), _errorDescription), e); try { doTaskFailed(driverTask, dbClient); } catch (Exception dtfe) { s_logger.error("Unexpected error handling task failed", e); } _status = JobStatus.FAILED; } finally { updateStatus(dbClient); } _pollResult.setJobStatus(_status); _pollResult.setErrorDescription(_errorDescription); return _pollResult; } /** * Determines if the passed status indicates the task was successful. * Override in derived classes as appropriate. When overridden be sure * to consider isTaskFailed as well. * * @param taskStatus The task status. * * @return true if the task is successful, false otherwise. */ protected boolean isTaskSuccessful(TaskStatus taskStatus) { return (TaskStatus.READY == taskStatus); } /** * Determines if the passed status indicates the task failed. * Override in derived classes as appropriate. When overridden * be sure to consider isTaskSuccessful as well. * * @param taskStatus The task status. * * @return true if the task failed, false otherwise. */ protected boolean isTaskFailed(TaskStatus taskStatus) { return (TaskStatus.FAILED == taskStatus ||TaskStatus.ABORTED == taskStatus || TaskStatus.WARNING == taskStatus || TaskStatus.PARTIALLY_FAILED == taskStatus); } /** * If necessary, update the task completer after a poll. * * @param dbClient A reference to a database client. */ protected void updateStatus(DbClient dbClient) { try { if (_status == JobStatus.SUCCESS) { _taskCompleter.ready(dbClient); } else if (_status == JobStatus.FAILED) { ServiceCoded sc = ExternalDeviceException.errors.driverTaskFailed( _driverTaskId, _storageSystemURI.toString(), _errorDescription); _taskCompleter.error(dbClient, sc); } } catch (Exception e) { s_logger.error(String.format("Unexpected error trying to update completer status for driver task %s on system %s", _driverTaskId, _storageSystemURI.toString()), e); } } /** * Job specific actions to be done upon successful completion of a task. * * @param driverTask A reference to the driver task. * @param dbClient A reference to a database client. * * @throws Exception */ protected abstract void doTaskSucceeded(DriverTask driverTask, DbClient dbClient) throws Exception; /** * Job specific actions to be done when a task fails to complete successfully * * @param taskStatus A reference to the driver task. * @param dbClient A reference to a database client. * * @throws Exception */ protected abstract void doTaskFailed(DriverTask driverTask, DbClient dbClient) throws Exception; /** * {@inheritDoc} */ @Override public TaskCompleter getTaskCompleter() { return _taskCompleter; } }