/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.vplexcontroller.job;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import com.emc.storageos.volumecontroller.TaskCompleter;
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.db.client.model.Volume;
import com.emc.storageos.exceptions.DeviceControllerErrors;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.volumecontroller.Job;
import com.emc.storageos.volumecontroller.JobContext;
import com.emc.storageos.volumecontroller.impl.JobPollResult;
import com.emc.storageos.vplex.api.VPlexApiClient;
import com.emc.storageos.vplex.api.VPlexApiFactory;
import com.emc.storageos.vplex.api.VPlexCacheStatusInfo;
import com.emc.storageos.vplex.api.VPlexCacheStatusInfo.InvalidateStatus;
import com.emc.storageos.vplexcontroller.VPlexControllerUtils;
import com.emc.storageos.vplexcontroller.completers.CacheStatusTaskCompleter;
/**
* Job checks the progress of a cache invalidate operation on a VPLEX volume.
*/
public class VPlexCacheStatusJob extends Job implements Serializable {
// For serialization interface.
private static final long serialVersionUID = 1L;
// A reference to the task completer
private CacheStatusTaskCompleter _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(VPlexCacheStatusJob.class);
/**
* Constructor.
*
* @param taskCompleter The task completer.
*/
public VPlexCacheStatusJob(CacheStatusTaskCompleter taskCompleter) {
_taskCompleter = taskCompleter;
}
/**
* {@inheritDoc}
*/
public JobPollResult poll(JobContext jobContext, long trackingPeriodInMillis) {
s_logger.debug("Polled cache status job");
// Get the DB client from the job context.
DbClient dbClient = jobContext.getDbClient();
// Get the VPLEX volume associated with the cache invalidation job.
Volume vplexVolume = dbClient.queryObject(Volume.class,
_taskCompleter.getId());
String vplexVolumeName = vplexVolume.getDeviceLabel();
s_logger.debug("VPLEX volume is {}", vplexVolume.getId());
// Get the VPlex storage system for that VPLEX volume.
StorageSystem vplexSystem = dbClient.queryObject(StorageSystem.class,
vplexVolume.getStorageController());
s_logger.debug("VPlex system is {}", vplexSystem.getId());
try {
// Update the job info.
_pollResult.setJobName(vplexVolumeName);
_pollResult.setJobId(vplexSystem.getId().toString());
_pollResult.setJobPercentComplete(0);
s_logger.debug("Updated poll result");
// Get the VPlex API client for this VPlex storage system
// and get the cache invalidation status for the VPLEX volume.
VPlexApiClient vplexApiClient = VPlexControllerUtils.getVPlexAPIClient(
jobContext.getVPlexApiFactory(), vplexSystem, dbClient);
s_logger.debug("Got VPlex APi Client");
VPlexCacheStatusInfo cacheStatusInfo = vplexApiClient
.getCacheStatus(vplexVolumeName);
s_logger.debug("Got cache status info from VPlex");
// Examine the status.
InvalidateStatus invalidateStatus = cacheStatusInfo.getCacheInvalidateStatus();
if (InvalidateStatus.SUCCESS.equals(invalidateStatus)) {
// Completed successfully
s_logger.info("Cache Invalidate for Volume: {} completed sucessfully",
vplexVolume.getId());
_pollResult.setJobPercentComplete(100);
_status = JobStatus.SUCCESS;
} else if (InvalidateStatus.FAILED.equals(invalidateStatus)) {
// Failed.
s_logger.info("Cache Invalidate for Volume : {} failed",
vplexVolume.getId());
_pollResult.setJobPercentComplete(100);
_errorDescription = cacheStatusInfo.getCacheInvalidateFailedMessage();
_status = JobStatus.FAILED;
}
} catch (Exception e) {
_errorDescription = e.getMessage();
s_logger.error(String.format(
"Unexpected error getting cache status for volume %s on VPlex %s: %s",
vplexVolume.getId(), vplexSystem.getId(), _errorDescription), e);
_status = JobStatus.FAILED;
} finally {
s_logger.debug("Updating status {}", _status);
updateStatus(jobContext);
}
_pollResult.setJobStatus(_status);
_pollResult.setErrorDescription(_errorDescription);
return _pollResult;
}
/**
* Get the HTTP client for making requests to the VPlex at the endpoint
* specified in the passed profile.
*
* @param jobContext The job context
* @param vplexSystem The VPlex storage system
*
* @return A reference to the VPlex API HTTP client.
* @throws URISyntaxException
*/
private VPlexApiClient getVPlexAPIClient(JobContext jobContext,
StorageSystem vplexSystem) throws URISyntaxException {
// Create the URI to access the VPlex Management Station based
// on the IP and port for the passed VPlex system.
URI vplexEndpointURI = new URI("https", null, vplexSystem.getIpAddress(), vplexSystem.getPortNumber(), "/", null, null);
s_logger.debug("VPlex base URI is {}", vplexEndpointURI.toString());
VPlexApiFactory vplexApiFactory = jobContext.getVPlexApiFactory();
s_logger.debug("Got VPlex API factory");
VPlexApiClient client = vplexApiFactory.getClient(vplexEndpointURI,
vplexSystem.getUsername(), vplexSystem.getPassword());
s_logger.debug("Got VPlex API client");
return client;
}
/**
* Update the status after a poll.
*
* @param jobContext the job context.
*/
public void updateStatus(JobContext jobContext) {
try {
if (_status == JobStatus.SUCCESS) {
s_logger.debug("Calling task completer for successful job");
_taskCompleter.ready(jobContext.getDbClient());
} else if (_status == JobStatus.FAILED) {
s_logger.debug("Calling task completer for failed job");
ServiceError error = DeviceControllerErrors.vplex
.cacheInvalidateJobFailed(_errorDescription);
_taskCompleter.error(jobContext.getDbClient(), error);
}
} catch (Exception e) {
s_logger.error("Problem while trying to update status", e);
}
}
public TaskCompleter getTaskCompleter() {
return _taskCompleter;
}
}