/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.cinder;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.cinder.CinderConstants;
import com.emc.storageos.cinder.CinderEndPointInfo;
import com.emc.storageos.cinder.api.CinderApi;
import com.emc.storageos.cinder.api.CinderApiFactory;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.TenantOrg;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.model.Volume.ReplicationState;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.exceptions.DeviceControllerErrors;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.svcs.errorhandling.resources.InternalException;
import com.emc.storageos.volumecontroller.CloneOperations;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl;
import com.emc.storageos.volumecontroller.impl.cinder.job.CinderSingleVolumeCreateJob;
import com.emc.storageos.volumecontroller.impl.job.QueueJob;
import com.emc.storageos.volumecontroller.impl.smis.ReplicationUtils;
public class CinderCloneOperations implements CloneOperations
{
private static final Logger log = LoggerFactory.getLogger(CinderCloneOperations.class);
private DbClient dbClient;
private CinderApiFactory cinderApiFactory;
public CinderCloneOperations()
{
}
public void setDbClient(DbClient dbClient)
{
this.dbClient = dbClient;
}
/**
* @param CinderApiFactory the CinderApiFactory to set
*/
public void setCinderApiFactory(CinderApiFactory cinderApiFactory)
{
this.cinderApiFactory = cinderApiFactory;
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.CloneOperations#createSingleClone(
* com.emc.storageos.db.client.model.StorageSystem, java.net.URI, java.net.URI,
* java.lang.Boolean,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void createSingleClone(StorageSystem storageSystem,
URI sourceObject,
URI cloneVolume,
Boolean createInactive,
TaskCompleter taskCompleter)
{
log.info("START createSingleClone operation");
boolean isVolumeClone = true;
try
{
BlockObject sourceObj = BlockObject.fetch(dbClient, sourceObject);
URI tenantUri = null;
if (sourceObj instanceof BlockSnapshot)
{ // In case of snapshot, get the tenant from its parent volume
NamedURI parentVolUri = ((BlockSnapshot) sourceObj).getParent();
Volume parentVolume = dbClient.queryObject(Volume.class, parentVolUri);
tenantUri = parentVolume.getTenant().getURI();
isVolumeClone = false;
}
else
{// This is a default flow
tenantUri = ((Volume) sourceObj).getTenant().getURI();
isVolumeClone = true;
}
Volume cloneObj = dbClient.queryObject(Volume.class, cloneVolume);
StoragePool targetPool = dbClient.queryObject(StoragePool.class, cloneObj.getPool());
TenantOrg tenantOrg = dbClient.queryObject(TenantOrg.class, tenantUri);
// String cloneLabel = generateLabel(tenantOrg, cloneObj);
CinderEndPointInfo ep = CinderUtils.getCinderEndPoint(storageSystem.getActiveProviderURI(), dbClient);
log.info("Getting the cinder APi for the provider with id " + storageSystem.getActiveProviderURI());
CinderApi cinderApi = cinderApiFactory.getApi(storageSystem.getActiveProviderURI(), ep);
String volumeId = "";
if (isVolumeClone)
{
volumeId = cinderApi.cloneVolume(cloneObj.getLabel(), (cloneObj.getCapacity() / (1024 * 1024 * 1024)),
targetPool.getNativeId(), sourceObj.getNativeId());
}
else
{
volumeId = cinderApi.createVolumeFromSnapshot(cloneObj.getLabel(), (cloneObj.getCapacity() / (1024 * 1024 * 1024)),
targetPool.getNativeId(), sourceObj.getNativeId());
}
log.debug("Creating volume with the id " + volumeId + " on Openstack cinder node");
if (volumeId != null)
{
// Cinder volume/snapshot clones are not sync with source, so
// set the replication state as DETACHED
cloneObj.setReplicaState(ReplicationState.DETACHED.name());
dbClient.persistObject(cloneObj);
Map<String, URI> volumeIds = new HashMap<String, URI>();
volumeIds.put(volumeId, cloneObj.getId());
ControllerServiceImpl.enqueueJob(new QueueJob(
new CinderSingleVolumeCreateJob(volumeId, cloneObj
.getLabel(), storageSystem.getId(),
CinderConstants.ComponentType.volume.name(),
ep, taskCompleter, targetPool.getId(), volumeIds)));
}
} catch (InternalException e)
{
String errorMsg = String.format(CREATE_ERROR_MSG_FORMAT, sourceObject, cloneVolume);
log.error(errorMsg, e);
taskCompleter.error(dbClient, e);
} catch (Exception e)
{
String errorMsg = String.format(CREATE_ERROR_MSG_FORMAT, sourceObject, cloneVolume);
log.error(errorMsg, e);
ServiceError serviceError = DeviceControllerErrors.cinder.operationFailed("createSingleClone",
e.getMessage());
taskCompleter.error(dbClient, serviceError);
}
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.CloneOperations#detachSingleClone(
* com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void detachSingleClone(StorageSystem storageSystem,
URI cloneVolume,
TaskCompleter taskCompleter)
{
// Not Supported
Volume clone = dbClient.queryObject(Volume.class, cloneVolume);
ReplicationUtils.removeDetachedFullCopyFromSourceFullCopiesList(clone, dbClient);
clone.setAssociatedSourceVolume(NullColumnValueGetter.getNullURI());
clone.setReplicaState(ReplicationState.DETACHED.name());
dbClient.persistObject(clone);
taskCompleter.ready(dbClient);
}
/*
* (non-Javadoc)
*
* @see com.emc.storageos.volumecontroller.CloneOperations#activateSingleClone(
* com.emc.storageos.db.client.model.StorageSystem,
* java.net.URI,
* com.emc.storageos.volumecontroller.TaskCompleter)
*/
@Override
public void activateSingleClone(StorageSystem storageSystem,
URI fullCopy,
TaskCompleter completer)
{
// Not supported
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void restoreFromSingleClone(StorageSystem storageSystem,
URI clone, TaskCompleter completer) {
// no support
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void fractureSingleClone(StorageSystem storageSystem, URI sourceVolume,
URI clone, TaskCompleter completer) {
// no support
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void resyncSingleClone(StorageSystem storageSystem, URI clone, TaskCompleter completer) {
// no support
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void createGroupClone(StorageSystem storage, List<URI> cloneList,
Boolean createInactive, TaskCompleter taskCompleter) throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void activateGroupClones(StorageSystem storage, List<URI> clone, TaskCompleter taskCompleter) {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void restoreGroupClones(StorageSystem storageSystem, List<URI> clone, TaskCompleter completer) {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void fractureGroupClones(StorageSystem storageSystem, List<URI> clone, TaskCompleter completer) {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void resyncGroupClones(StorageSystem storageSystem, List<URI> clone, TaskCompleter completer) {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void detachGroupClones(StorageSystem storageSystem, List<URI> clone, TaskCompleter completer) {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void establishVolumeCloneGroupRelation(StorageSystem storage, URI sourceVolume, URI clone, TaskCompleter completer) {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
}