/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.externaldevice.job;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.volumecontroller.impl.externaldevice.ExternalBlockStorageDevice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.storagedriver.DriverTask;
import com.emc.storageos.storagedriver.model.VolumeClone;
import com.emc.storageos.storagedriver.task.CreateGroupCloneDriverTask;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.externaldevice.ExternalDeviceUtils;
/**
* This ExternalDeviceJob derived class is created to monitor the progress
* of a request to a create group clone that will complete asynchronously.
*/
public class CreateGroupCloneExternalDeviceJob extends ExternalDeviceJob {
private static final long serialVersionUID = 1L;
// The URI of the volume serving as the clone.
private List<URI> _volumeURIs;
// The URI of the consistency group
private URI _cgURI;
// Logger reference.
private static final Logger s_logger = LoggerFactory.getLogger(CreateGroupCloneExternalDeviceJob.class);
/**
* Constructor.
*
* @param storageSystemURI The URI of the external storage system on which the task is running.
* @param volumeURIs The URI of the volume serving as the clone.
* @param cgURI The consistency group URI.
* @param driverTaskId The id of the task monitored by the job.
* @param taskCompleter The task completer.
*/
public CreateGroupCloneExternalDeviceJob(URI storageSystemURI, List<URI> volumeURIs, URI cgURI,
String driverTaskId, TaskCompleter taskCompleter) {
super(storageSystemURI, driverTaskId, taskCompleter);
_volumeURIs = volumeURIs;
}
/**
* {@inheritDoc}
*/
@Override
protected void doTaskSucceeded(DriverTask driverTask, DbClient dbClient) throws Exception {
s_logger.info(String.format("Successfully created group clone: %s", driverTask.getMessage()));
// Update the ViPR volumes representing the clone with the
// corresponding driver clone.
List<Volume> updatedVolumes = new ArrayList<>();
for (URI volumeURI : _volumeURIs) {
Volume volume = dbClient.queryObject(Volume.class, volumeURI);
if (volume == null) {
s_logger.error(String.format("Failed to find volume %s", volumeURI));
throw DeviceControllerException.exceptions.objectNotFound(volumeURI);
}
// Update the ViPR clone with the driver clone information.
CreateGroupCloneDriverTask createCloneDriverTask = (CreateGroupCloneDriverTask) driverTask;
List<VolumeClone> updatedClones = createCloneDriverTask.getClones();
for (VolumeClone updatedClone: updatedClones) {
if (ExternalDeviceUtils.isVolumeExternalDeviceClone(volume, updatedClone, dbClient)) {
ExternalDeviceUtils.updateNewlyCreatedGroupClone(volume, updatedClone, _cgURI, dbClient);
updatedVolumes.add(volume);
break;
}
}
}
dbClient.updateObject(updatedVolumes);
try {
// post process storage pool capacity for clone's pools
// map clones to their storage pool
updateStoragePoolCapacityAfterOperationComplete(updatedVolumes, dbClient);
} catch (Exception ex) {
s_logger.error("Failed to update storage pool after create group clone operation completion.", ex);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void doTaskFailed(DriverTask driverTask, DbClient dbClient) throws Exception {
s_logger.error(String.format("Failed to create group volume clone: %s", driverTask.getMessage()));
List<Volume> volumes = new ArrayList<>();
for (URI volumeURI : _volumeURIs) {
Volume volume = dbClient.queryObject(Volume.class, volumeURI);
if (volume == null) {
s_logger.error(String.format("Failed to find volume %s", volumeURI));
} else {
volume.setInactive(true);
volumes.add(volume);
}
}
dbClient.updateObject(volumes);
try {
// post process storage pool capacity for clone's pools
// map clones to their storage pool
updateStoragePoolCapacityAfterOperationComplete(volumes, dbClient);
} catch (Exception ex) {
s_logger.error("Failed to update storage pool after create group clone operation completion.", ex);
}
}
/**
* Updates capacity of storage pools used for clones.
*
* @param clones list of clones
* @param dbClient db client
*/
private void updateStoragePoolCapacityAfterOperationComplete(List<Volume> clones, DbClient dbClient) {
Map<URI, List<URI>> dbPoolToClone = new HashMap<>();
for (Volume clone : clones) {
URI dbPoolUri = clone.getPool();
List<URI> poolClones = dbPoolToClone.get(dbPoolUri);
if (poolClones == null) {
poolClones = new ArrayList<>();
dbPoolToClone.put(dbPoolUri, poolClones);
}
poolClones.add(clone.getId());
}
StorageSystem dbSystem = dbClient.queryObject(StorageSystem.class, _storageSystemURI);
for (URI dbPoolUri : dbPoolToClone.keySet()) {
StoragePool dbPool = dbClient.queryObject(StoragePool.class, dbPoolUri);
ExternalBlockStorageDevice.updateStoragePoolCapacity(dbPool, dbSystem,
dbPoolToClone.get(dbPoolUri), dbClient);
}
}
}