/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.vnxe;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.model.BlockConsistencyGroup;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshot;
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.util.NameGenerator;
import com.emc.storageos.exceptions.DeviceControllerErrors;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.exceptions.DeviceControllerExceptions;
import com.emc.storageos.svcs.errorhandling.model.ServiceCoded;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.vnxe.VNXeApiClient;
import com.emc.storageos.vnxe.VNXeException;
import com.emc.storageos.vnxe.models.VNXeCommandJob;
import com.emc.storageos.vnxe.models.VNXeLunGroupSnap;
import com.emc.storageos.vnxe.models.VNXeLunSnap;
import com.emc.storageos.volumecontroller.SnapshotOperations;
import com.emc.storageos.volumecontroller.TaskCompleter;
import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl;
import com.emc.storageos.volumecontroller.impl.ControllerUtils;
import com.emc.storageos.volumecontroller.impl.job.QueueJob;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.emc.storageos.volumecontroller.impl.vnxe.job.VNXeBlockCreateCGSnapshotJob;
import com.emc.storageos.volumecontroller.impl.vnxe.job.VNXeBlockDeleteSnapshotJob;
import com.emc.storageos.volumecontroller.impl.vnxe.job.VNXeBlockRestoreSnapshotJob;
import com.emc.storageos.volumecontroller.impl.vnxe.job.VNXeBlockSnapshotCreateJob;
public class VNXeSnapshotOperation extends VNXeOperations implements SnapshotOperations {
private static final Logger _log = LoggerFactory.getLogger(VNXeSnapshotOperation.class);
protected NameGenerator _nameGenerator;
public static final int MAX_SNAPSHOT_NAME_LENGTH = 85;
public void setNameGenerator(NameGenerator nameGenerator) {
_nameGenerator = nameGenerator;
}
@Override
public void createGroupSnapshots(StorageSystem storage,
List<URI> snapshotList, Boolean createInactive, Boolean readOnly,
TaskCompleter taskCompleter) throws DeviceControllerException {
try {
URI snapshot = snapshotList.get(0);
BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);
Volume volume = _dbClient.queryObject(Volume.class, snapshotObj.getParent());
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, volume.getTenant().getURI());
String tenantName = tenant.getLabel();
String snapLabelToUse =
_nameGenerator.generate(tenantName, snapshotObj.getLabel(),
snapshot.toString(), '-', SmisConstants.MAX_SNAPSHOT_NAME_LENGTH);
String groupName = getConsistencyGroupName(snapshotObj);
VNXeApiClient apiClient = getVnxeClient(storage);
VNXeCommandJob job = apiClient.createLunGroupSnap(groupName, snapLabelToUse);
if (job != null) {
ControllerServiceImpl.enqueueJob(
new QueueJob(new VNXeBlockCreateCGSnapshotJob(job.getId(),
storage.getId(), !createInactive, taskCompleter)));
}
} catch (VNXeException e) {
_log.error("Create volume snapshot got the exception", e);
taskCompleter.error(_dbClient, e);
} catch (Exception ex) {
_log.error("Create volume snapshot got the exception", ex);
ServiceError error = DeviceControllerErrors.vnxe.jobFailed("CreateCGSnapshot", ex.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void activateSingleVolumeSnapshot(StorageSystem storage,
URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void activateGroupSnapshots(StorageSystem storage, URI snapshot,
TaskCompleter taskCompleter) throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void deleteSingleVolumeSnapshot(StorageSystem storage, URI snapshot,
TaskCompleter taskCompleter) throws DeviceControllerException {
try {
BlockSnapshot snap = _dbClient.queryObject(BlockSnapshot.class, snapshot);
VNXeApiClient apiClient = getVnxeClient(storage);
VNXeLunSnap lunSnap = apiClient.getLunSnapshot(snap.getNativeId());
if (lunSnap != null) {
VNXeCommandJob job = apiClient.deleteLunSnap(lunSnap.getId());
if (job != null) {
ControllerServiceImpl.enqueueJob(
new QueueJob(new VNXeBlockDeleteSnapshotJob(job.getId(),
storage.getId(), taskCompleter)));
}
} else {
// Perhaps, it's already been deleted or was deleted on the array.
// In that case, we'll just say all is well, so that this operation
// is idempotent.
snap.setInactive(true);
snap.setIsSyncActive(false);
_dbClient.updateObject(snap);
taskCompleter.ready(_dbClient);
}
} catch (VNXeException e) {
_log.error("Delete volume snapshot got the exception", e);
taskCompleter.error(_dbClient, e);
} catch (Exception ex) {
_log.error("Delete volume snapshot got the exception", ex);
ServiceError error = DeviceControllerErrors.vnxe.jobFailed("DeleteSnapshot", ex.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void deleteGroupSnapshots(StorageSystem storage, URI snapshot,
TaskCompleter taskCompleter) throws DeviceControllerException {
try {
List<BlockSnapshot> snapshots = _dbClient.queryObject(BlockSnapshot.class, Arrays.asList(snapshot));
BlockSnapshot snapshotObj = snapshots.get(0);
VNXeApiClient apiClient = getVnxeClient(storage);
VNXeLunGroupSnap lunGroupSnap = apiClient.getLunGroupSnapshot(snapshotObj.getReplicationGroupInstance());
if (lunGroupSnap != null) {
VNXeCommandJob job = apiClient.deleteLunGroupSnap(lunGroupSnap.getId());
if (job != null) {
ControllerServiceImpl.enqueueJob(
new QueueJob(new VNXeBlockDeleteSnapshotJob(job.getId(),
storage.getId(), taskCompleter)));
} else {
// Should not take this path, but treat as an error if we do
// happen to get a null job due to some error in the client.
_log.error("Unexpected null job from VNXe client call to delete group snapshot.");
ServiceCoded sc = DeviceControllerExceptions.vnxe.nullJobForDeleteGroupSnapshot(snapshotObj.forDisplay(),
snapshotObj.getReplicationGroupInstance());
taskCompleter.error(_dbClient, sc);
}
} else {
// Treat as in the single volume snapshot case and presume
// the group snapshot has already been deleted.
List<BlockSnapshot> grpSnapshots = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshotObj, _dbClient);
for (BlockSnapshot grpSnapshot : grpSnapshots) {
grpSnapshot.setInactive(true);
grpSnapshot.setIsSyncActive(false);
}
_dbClient.updateObject(grpSnapshots);
taskCompleter.ready(_dbClient);
}
} catch (VNXeException e) {
_log.error("Delete group snapshot got the exception", e);
taskCompleter.error(_dbClient, e);
} catch (Exception ex) {
_log.error("Delete group snapshot got the exception", ex);
ServiceError error = DeviceControllerErrors.vnxe.jobFailed("DeletGroupSnapshot", ex.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void restoreSingleVolumeSnapshot(StorageSystem storage, URI volume,
URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);
VNXeApiClient apiClient = getVnxeClient(storage);
VNXeLunSnap lunSnap = apiClient.getLunSnapshot(snapshotObj.getNativeId());
// Error out if the snapshot is attached
if (lunSnap.getIsAttached()) {
_log.error("Snapshot {})is attached and cannot be used for restore", snapshotObj.getLabel());
ServiceError error = DeviceControllerErrors.vnxe.cannotRestoreAttachedSnapshot(snapshot.toString());
taskCompleter.error(_dbClient, error);
}
VNXeCommandJob job = apiClient.restoreLunSnap(lunSnap.getId());
if (job != null) {
ControllerServiceImpl.enqueueJob(
new QueueJob(new VNXeBlockRestoreSnapshotJob(job.getId(),
storage.getId(), taskCompleter)));
}
} catch (VNXeException e) {
_log.error("Restore snapshot got the exception", e);
taskCompleter.error(_dbClient, e);
} catch (Exception ex) {
_log.error("Restore snapshot got the exception", ex);
ServiceError error = DeviceControllerErrors.vnxe.jobFailed("RestoreSnapshotJob", ex.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void restoreGroupSnapshots(StorageSystem storage, URI volume,
URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);
VNXeApiClient apiClient = getVnxeClient(storage);
VNXeLunGroupSnap lunGroupSnap = apiClient.getLunGroupSnapshot(snapshotObj.getReplicationGroupInstance());
// Error out if the snapshot is attached
if (lunGroupSnap.getIsAttached()) {
_log.error("Snapshot {})is attached and cannot be used for restore", snapshotObj.getLabel());
ServiceError error = DeviceControllerErrors.vnxe.cannotRestoreAttachedSnapshot(snapshot.toString());
taskCompleter.error(_dbClient, error);
}
VNXeCommandJob job = apiClient.restoreLunGroupSnap(lunGroupSnap.getId());
if (job != null) {
ControllerServiceImpl.enqueueJob(
new QueueJob(new VNXeBlockRestoreSnapshotJob(job.getId(),
storage.getId(), taskCompleter)));
}
} catch (VNXeException e) {
_log.error("Restore group snapshot got the exception", e);
taskCompleter.error(_dbClient, e);
} catch (Exception ex) {
_log.error("Restore group snapshot got the exception", ex);
ServiceError error = DeviceControllerErrors.vnxe.jobFailed("RestoreSnapshotJob", ex.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void createSingleVolumeSnapshot(StorageSystem storage, URI snapshot,
Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);
Volume volume = _dbClient.queryObject(Volume.class, snapshotObj.getParent());
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, volume.getTenant().getURI());
String tenantName = tenant.getLabel();
String snapLabelToUse =
_nameGenerator.generate(tenantName, snapshotObj.getLabel(),
snapshot.toString(), '-', SmisConstants.MAX_SNAPSHOT_NAME_LENGTH);
VNXeApiClient apiClient = getVnxeClient(storage);
VNXeCommandJob job = apiClient.createLunSnap(volume.getNativeId(), snapLabelToUse);
if (job != null) {
ControllerServiceImpl.enqueueJob(
new QueueJob(new VNXeBlockSnapshotCreateJob(job.getId(),
storage.getId(), !createInactive, taskCompleter)));
}
} catch (VNXeException e) {
_log.error("Create volume snapshot got the exception", e);
taskCompleter.error(_dbClient, e);
} catch (Exception ex) {
_log.error("Create volume snapshot got the exception", ex);
ServiceError error = DeviceControllerErrors.vnxe.jobFailed("CreateVolumeSnapshot", ex.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void copySnapshotToTarget(StorageSystem storage, URI snapshot,
TaskCompleter taskCompleter) throws DeviceControllerException {
throw DeviceControllerException.exceptions.operationNotSupported();
}
@Override
public void copyGroupSnapshotsToTarget(StorageSystem storage,
List<URI> snapshotList, TaskCompleter taskCompleter)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.operationNotSupported();
}
@Override
public void terminateAnyRestoreSessions(StorageSystem storage, BlockObject from, URI volume,
TaskCompleter taskCompleter) throws Exception {
throw DeviceControllerException.exceptions.operationNotSupported();
}
public String getConsistencyGroupName(BlockObject bo) {
if (bo.getConsistencyGroup() == null) {
return null;
}
final BlockConsistencyGroup group = _dbClient.queryObject(BlockConsistencyGroup.class,
bo.getConsistencyGroup());
return getConsistencyGroupName(group, bo);
}
public String getConsistencyGroupName(final BlockConsistencyGroup group, BlockObject bo) {
String groupName = null;
if (group != null && bo != null) {
groupName = group.getCgNameOnStorageSystem(bo.getStorageController());
}
return groupName;
}
@Override
public void resyncSingleVolumeSnapshot(StorageSystem storage, URI volume, URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.operationNotSupported();
}
@Override
public void resyncGroupSnapshots(StorageSystem storage, URI volume, URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.operationNotSupported();
}
@Override
public void establishVolumeSnapshotGroupRelation(StorageSystem storage, URI sourceVolume,
URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void createSnapshotSession(StorageSystem system, URI snapSessionURI, TaskCompleter completer)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void createGroupSnapshotSession(StorageSystem system, URI snapSessionURI, String groupName, TaskCompleter completer)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void linkSnapshotSessionTarget(StorageSystem system, URI snapSessionURI, URI snapshotURI,
String copyMode, Boolean targetExists, TaskCompleter completer)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
@Override
public void linkSnapshotSessionTargetGroup(StorageSystem system, URI snapshotSessionURI, List<URI> snapSessionSnapshotURIs,
String copyMode, Boolean targetsExist, TaskCompleter completer) throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void relinkSnapshotSessionTarget(StorageSystem system, URI tgtSnapSessionURI, URI snapshotURI,
TaskCompleter completer) throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void relinkSnapshotSessionTargetGroup(StorageSystem system, URI tgtSnapSessionURI, URI snapshotURI, TaskCompleter completer) throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void unlinkSnapshotSessionTarget(StorageSystem system, URI snapSessionURI, URI snapshotURI,
Boolean deleteTarget, TaskCompleter completer) throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void restoreSnapshotSession(StorageSystem system, URI snapSessionURI, TaskCompleter completer)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void deleteSnapshotSession(StorageSystem system, URI snapSessionURI, String groupName, TaskCompleter completer)
throws DeviceControllerException {
throw DeviceControllerException.exceptions.blockDeviceOperationNotSupported();
}
}