/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.smis.vnx;
import static com.emc.storageos.volumecontroller.impl.smis.ReplicationUtils.callEMCRefreshIfRequired;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.cim.CIMArgument;
import javax.cim.CIMInstance;
import javax.cim.CIMObjectPath;
import javax.wbem.WBEMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshot;
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.exceptions.DeviceControllerErrors;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
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.block.taskcompleter.BlockSnapshotCreateCompleter;
import com.emc.storageos.volumecontroller.impl.job.QueueJob;
import com.emc.storageos.volumecontroller.impl.providerfinders.FindProviderFactory;
import com.emc.storageos.volumecontroller.impl.smis.AbstractSnapshotOperations;
import com.emc.storageos.volumecontroller.impl.smis.ReplicationUtils;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants.SYNC_TYPE;
import com.emc.storageos.volumecontroller.impl.smis.job.SmisBlockCreateCGSnapshotJob;
import com.emc.storageos.volumecontroller.impl.smis.job.SmisBlockRestoreSnapshotJob;
import com.emc.storageos.volumecontroller.impl.utils.ConsistencyGroupUtils;
import com.emc.storageos.workflow.WorkflowException;
public class VnxSnapshotOperations extends AbstractSnapshotOperations {
private static final Logger _log = LoggerFactory.getLogger(VnxSnapshotOperations.class);
private FindProviderFactory findProviderFactory;
public void setFindProviderFactory(final FindProviderFactory findProviderFactory) {
this.findProviderFactory = findProviderFactory;
}
/**
* This interface is for the snapshot active. The createSnapshot may have done
* whatever is necessary to setup the snapshot for this call. The goal is to
* make this a quick operation and the create operation has already done a lot
* of the "heavy lifting".
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshot [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
*/
@Override
public void activateSingleVolumeSnapshot(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
BlockSnapshot snapshotObj = null;
try {
snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);
if (snapshotObj.getIsSyncActive()) {
taskCompleter.ready(_dbClient);
return;
}
BlockObject bo = BlockObject.fetch(_dbClient,
snapshotObj.getParent().getURI());
_log.info("activateSingleVolumeSnapshot operation START");
CIMObjectPath blockObjectPath = _cimPath.getBlockObjectPath(storage, bo);
CIMArgument[] inArgs =
_helper.getCreateSynchronizationAspectInput(blockObjectPath, true, null, null);
CIMArgument[] outArgs = new CIMArgument[5];
CIMObjectPath replicationSvcPath =
_cimPath.getControllerReplicationSvcPath(storage);
_helper.invokeMethod(storage, replicationSvcPath,
SmisConstants.CREATE_SYNCHRONIZATION_ASPECT, inArgs, outArgs);
setIsSyncActive(snapshotObj, true);
CIMObjectPath settingsPath = (CIMObjectPath) outArgs[0].getValue();
CIMObjectPath syncPath = (CIMObjectPath) settingsPath.getKey(SmisConstants.CP_SETTING_DATA).getValue();
String instanceId = (String) syncPath.getKey(SmisConstants.CP_INSTANCE_ID).getValue();
snapshotObj.setSettingsInstance(instanceId);
snapshotObj.setNeedsCopyToTarget(true);
snapshotObj.setRefreshRequired(true);
_dbClient.persistObject(snapshotObj);
// Success -- Update status
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.info("Problem making SMI-S call: ", e);
ServiceError error = DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} finally {
_log.info("activateSingleVolumeSnapshot operation END");
}
}
/**
* This interface is for the snapshot active. The createSnapshot may have done
* whatever is necessary to setup the snapshot for this call. The goal is to
* make this a quick operation and the create operation has already done a lot
* of the "heavy lifting".
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshot [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
*/
@Override
public void activateGroupSnapshots(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException {
List<BlockSnapshot> snapshots = null;
try {
_log.info("activateGroupSnapshots operation START");
BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot);
if (snapshotObj.getIsSyncActive()) {
taskCompleter.ready(_dbClient);
return;
}
// Check if the consistency group exists
String consistencyGroupName = ConsistencyGroupUtils.getSourceConsistencyGroupName(snapshotObj, _dbClient);
storage = findProviderFactory.withGroup(storage, consistencyGroupName).find();
if (storage == null) {
ServiceError error = DeviceControllerErrors.smis.noConsistencyGroupWithGivenName();
taskCompleter.error(_dbClient, error);
return;
}
CIMObjectPath replicationGroupPath =
_cimPath.getReplicationGroupPath(storage, consistencyGroupName);
CIMArgument[] inArgs =
_helper.getCreateGroupSynchronizationAspectInput(replicationGroupPath);
CIMArgument[] outArgs = new CIMArgument[5];
CIMObjectPath replicationSvcPath =
_cimPath.getControllerReplicationSvcPath(storage);
_helper.invokeMethod(storage, replicationSvcPath,
SmisConstants.CREATE_SYNCHRONIZATION_ASPECT, inArgs, outArgs);
snapshots = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshotObj, _dbClient);
setIsSyncActive(snapshots, true);
// Get the settings object and apply it to all the snap objects
CIMObjectPath settingsPath = (CIMObjectPath) outArgs[0].getValue();
CIMObjectPath syncPath = (CIMObjectPath) settingsPath.getKey(SmisConstants.CP_SETTING_DATA).getValue();
String instanceId = (String) syncPath.getKey(SmisConstants.CP_INSTANCE_ID).getValue();
for (BlockSnapshot it : snapshots) {
it.setSettingsGroupInstance(instanceId);
it.setNeedsCopyToTarget(true);
it.setRefreshRequired(true);
}
_dbClient.persistObject(snapshots);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.info("Problem making SMI-S call: ", e);
ServiceError error = DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} finally {
_log.info("activateGroupSnapshots operation END");
}
}
/**
* Should implement deletion of single volume snapshot. That is, deleting a snap that was
* created independent of other volumes.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshot [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
*/
@Override
public void deleteSingleVolumeSnapshot(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
callEMCRefreshIfRequired(_dbClient, _helper, storage,
Arrays.asList(snapshot));
BlockSnapshot snap = _dbClient.queryObject(BlockSnapshot.class, snapshot);
CIMObjectPath syncObjectPath = _cimPath.getSyncObject(storage, snap);
if (_helper.checkExists(storage, syncObjectPath, false, false) != null) {
CIMArgument[] outArgs = new CIMArgument[5];
_helper.callModifyReplica(storage, _helper.getDeleteSnapshotSynchronousInputArguments(syncObjectPath), outArgs);
snap.setInactive(true);
snap.setIsSyncActive(false);
_dbClient.updateObject(snap);
taskCompleter.ready(_dbClient);
} 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 (WBEMException e) {
String message = String.format("Error encountered during delete snapshot %s on array %s",
snapshot.toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} catch (Exception e) {
String message = String.format("Generic exception when trying to delete snapshot %s on array %s",
snapshot.toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("deleteSingleVolumeSnapshot", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
/**
* Should implement create of a snapshot from a source volume that is part of a
* consistency group.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshot [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param createInactive - Indicates if the snapshots should be created but not
* activated
* @param readOnly - Indicates if the snapshot should be read only.
* @param taskCompleter - TaskCompleter object used for the updating operation status.
* @throws DeviceControllerException
*/
@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());
if (ControllerUtils.isNotInRealVNXRG(volume, _dbClient)) {
throw DeviceControllerException.exceptions.groupSnapshotNotSupported(volume.getReplicationGroupInstance());
}
// CTRL-5640: ReplicationGroup may not be accessible after provider fail-over.
ReplicationUtils.checkReplicationGroupAccessibleOrFail(storage, snapshotObj, _dbClient, _helper, _cimPath);
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 = ConsistencyGroupUtils.getSourceConsistencyGroupName(snapshotObj, _dbClient);
CIMObjectPath cgPath = _cimPath.getReplicationGroupPath(storage, groupName);
CIMObjectPath replicationSvc = _cimPath.getControllerReplicationSvcPath(storage);
CIMArgument[] inArgs = _helper.getCreateGroupReplicaInputArgumentsForVNX(storage, cgPath,
createInactive, snapLabelToUse, SYNC_TYPE.SNAPSHOT.getValue());
CIMArgument[] outArgs = new CIMArgument[5];
_helper.invokeMethod(storage, replicationSvc, SmisConstants.CREATE_GROUP_REPLICA, inArgs, outArgs);
CIMObjectPath job = _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.JOB);
if (job != null) {
ControllerServiceImpl.enqueueJob(
new QueueJob(new SmisBlockCreateCGSnapshotJob(job,
storage.getId(), !createInactive, null, taskCompleter)));
}
} catch (Exception e) {
_log.info("Problem making SMI-S call: ", e);
ServiceError error = DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
setInactive(((BlockSnapshotCreateCompleter) taskCompleter).getSnapshotURIs(), true);
}
}
/**
* Should implement clean up of all the snapshots in a volume consistency
* group 'snap-set'. The 'snap-set' is a set of block snapshots created for a
* set of volumes in a consistency group.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshot [required] - BlockSnapshot object representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
*/
@Override
public void deleteGroupSnapshots(StorageSystem storage, URI snapshot, TaskCompleter taskCompleter) throws DeviceControllerException {
try {
callEMCRefreshIfRequired(_dbClient, _helper, storage,
Arrays.asList(snapshot));
List<BlockSnapshot> snapshots = _dbClient.queryObject(BlockSnapshot.class, Arrays.asList(snapshot));
BlockSnapshot snapshotObj = snapshots.get(0);
// Check if the consistency group exists
String consistencyGroupName = ConsistencyGroupUtils.getSourceConsistencyGroupName(snapshotObj, _dbClient);
StorageSystem newStorage = findProviderFactory.withGroup(storage, consistencyGroupName).find();
if (newStorage == null) {
_log.warn("Replication Group {} not found.", consistencyGroupName);
// Don't return, let the below code do its clean-up.
} // else - storage will have right Provider to use.
String snapshotGroupName = snapshotObj.getReplicationGroupInstance();
boolean snapshotGroupExists = false;
CIMObjectPath groupSynchronized = _cimPath.getGroupSynchronizedPath(storage, consistencyGroupName, snapshotGroupName);
if (_helper.checkExists(storage, groupSynchronized, false, false) != null) {
// Delete the snapshot group (not the consistency group). This group is for
// the specific snaps that were taken for the consistency group.
snapshotGroupExists = true;
CIMArgument[] returnSnapGroupInput = _helper.getReturnGroupSyncToPoolInputArguments(groupSynchronized);
_helper.callModifyReplica(storage, returnSnapGroupInput);
}
// Individually delete each snap in the snapshot group
boolean hadDeleteFailure = false;
List<BlockSnapshot> snaps = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshotObj, _dbClient);
if (snapshotGroupExists) {
for (BlockSnapshot snap : snaps) {
_log.info(String.format("vnxDeleteGroupSnapshots -- deleting snapshot %s", snap.getId().toString()));
if (!deleteConsistencyGroupSnapshot(storage, snap, taskCompleter)) {
// Delete has failed, it would have called complete task
hadDeleteFailure = true;
}
}
}
if (!hadDeleteFailure) {
// Set inactive=true for all snapshots in the snaps set
for (BlockSnapshot snap : snaps) {
snap.setInactive(true);
snap.setIsSyncActive(false);
_dbClient.updateObject(snap);
}
taskCompleter.ready(_dbClient);
}
} catch (Exception e) {
String message =
String.format("Generic exception when trying to delete snapshots from consistency group on array %s",
storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("deleteGroupSnapshots", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
/**
* Implementation for restoring of a single volume snapshot restore. That is, this
* volume is independent of other volumes and a snapshot was taken previously, and
* now we want to restore that snap to the original volume.
*
* @param storage [required] - StorageSystem object representing the array
* @param volume [required] - Volume URI for the volume to be restored
* @param snapshot [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
*/
@Override
public void restoreSingleVolumeSnapshot(StorageSystem storage, URI volume, URI snapshot, TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
callEMCRefreshIfRequired(_dbClient, _helper, storage,
Arrays.asList(snapshot));
BlockSnapshot from = _dbClient.queryObject(BlockSnapshot.class, snapshot);
Volume to = _dbClient.queryObject(Volume.class, volume);
CIMObjectPath syncObjectPath = _cimPath.getSyncObject(storage, from);
if (_helper.checkExists(storage, syncObjectPath, false, false) != null) {
CIMObjectPath cimJob;
if (_helper.isThinlyProvisioned(storage, to) || isBasedOnVNXThinStoragePool(to)) {
_log.info(
"Volume {} is thinly provisioned or based on a Thin StoragePool, need to deactivate the volume before restore",
to.getLabel());
deactivateSnapshot(storage, from, syncObjectPath);
cimJob = _helper
.callModifySettingsDefineState(storage, _helper.getRestoreFromSnapshotInputArguments(storage, to, from));
} else {
// Thick volumes do not need to be deactivated prior to restore.
// The can be restored directly. WaitForCopyState should not be supplied in this scenario
_log.info("Volume {} is not thinly provisioned, will attempt restore", to.getLabel());
cimJob = _helper.callModifyReplica(storage, _helper.getRestoreFromReplicaInputArgumentsWithForce(syncObjectPath));
}
ControllerServiceImpl.enqueueJob(new QueueJob(new SmisBlockRestoreSnapshotJob(cimJob, storage.getId(), taskCompleter)));
} else {
ServiceError error = DeviceControllerErrors.smis.unableToFindSynchPath(storage.getLabel());
taskCompleter.error(_dbClient, error);
}
} catch (WBEMException e) {
String message = String.format("Error encountered when trying to restore from snapshot %s on array %s",
snapshot.toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} catch (Exception e) {
String message = String.format("Generic exception when trying to restore from snapshot %s on array %s",
snapshot.toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("restoreSingleVolumeSnapshot", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
/**
* Implementation should restore the set of snapshots that were taken for a set of
* volumes in a consistency group. That is, at some time there was a consistency
* group of volumes created and snapshot was taken of these; these snapshots would
* belong to a "snap-set". This restore operation, will restore the volumes in the
* consistency group from this snap-set. Any snapshot from the snap-set can be
* provided to restore the whole snap-set.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshotURI [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
*/
@Override
public void restoreGroupSnapshots(StorageSystem storage, URI volume, URI snapshotURI, TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
callEMCRefreshIfRequired(_dbClient, _helper, storage,
Arrays.asList(snapshotURI));
final BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshotURI);
// Check if the consistency group exists
final String consistencyGroupName = ConsistencyGroupUtils.getSourceConsistencyGroupName(snapshotObj, _dbClient);
storage = findProviderFactory.withGroup(storage, consistencyGroupName).find();
if (storage == null) {
ServiceError error = DeviceControllerErrors.smis.noConsistencyGroupWithGivenName();
taskCompleter.error(_dbClient, error);
return;
}
final String snapshotGroupName = snapshotObj.getReplicationGroupInstance();
final CIMObjectPath groupSynchronized = _cimPath.getGroupSynchronizedPath(storage, consistencyGroupName, snapshotGroupName);
final CIMInstance groupSynchronizedInstance = _helper.checkExists(storage, groupSynchronized, false, false);
List<BlockSnapshot> snapshots = ControllerUtils.getSnapshotsPartOfReplicationGroup(snapshotObj, _dbClient);
if (groupSynchronizedInstance != null) {
// Check if the snapshot requires a copy-to-target. This is essentially
// the operation that would make the snapshot 'active', though it's
// different from the ViPR snapshot activate. The copy-to-target would
// usually be done after a ViPR snapshot activate and as part of a
// snapshot export operation. If the copy-to-target is required, then it
// would mean that there wasn't any export performed.
if (snapshotObj.getNeedsCopyToTarget()) {
_log.info("Consistency group {} snapshots require copy-to-target",
consistencyGroupName);
List<URI> snapshotList = new ArrayList<URI>();
for (BlockSnapshot snapshot : snapshots) {
snapshotList.add(snapshot.getId());
}
internalGroupSnapCopyToTarget(storage, snapshotObj, snapshotList);
}
CIMObjectPath settingsPathFromOutputArg = null;
// Deactivate Synchronization if not already deactivated
String copyState = groupSynchronizedInstance.getPropertyValue(SmisConstants.CP_COPY_STATE).toString();
if (!String.valueOf(SmisConstants.INACTIVE_VALUE).equalsIgnoreCase(copyState)) {
CIMArgument[] deactivateGroupInput = _helper.getDeactivateSnapshotSynchronousInputArguments(groupSynchronized);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.callModifyReplica(storage, deactivateGroupInput, outArgs);
settingsPathFromOutputArg = (CIMObjectPath) outArgs[0].getValue();
}
final boolean isSynchronizationAspectSet = snapshotObj.getSettingsGroupInstance() != null;
// Get the Clar_SettingsDefineState_RG_SAFS path
final CIMObjectPath settingsPath = isSynchronizationAspectSet ?
_helper.getSettingsDefineStateForSourceGroup(storage, snapshotObj.getSettingsGroupInstance()) :
settingsPathFromOutputArg;
// If the Clar_SynchronizationAspectForSourceGroup hasn't been set in the snapshots, then set it.
if (!isSynchronizationAspectSet) {
CIMObjectPath syncPath = (CIMObjectPath) settingsPath.getKey(SmisConstants.CP_SETTING_DATA).getValue();
String instanceId = (String) syncPath.getKey(SmisConstants.CP_INSTANCE_ID).getValue();
for (BlockSnapshot it : snapshots) {
it.setSettingsGroupInstance(instanceId);
}
_dbClient.persistObject(snapshots);
}
// Restore snapshot
CIMArgument[] restoreInput = _helper.getRestoreFromSettingsStateInputArguments(settingsPath, false);
CIMObjectPath cimJob = _helper.callModifySettingsDefineState(storage, restoreInput);
ControllerServiceImpl.enqueueJob(new QueueJob(new SmisBlockRestoreSnapshotJob(cimJob, storage.getId(), taskCompleter)));
} else {
taskCompleter.ready(_dbClient);
}
} catch (Exception e) {
String message =
String.format("Generic exception when trying to restoring snapshots from consistency group on array %s",
storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("restoreGroupSnapshots", e.getMessage());
taskCompleter.error(_dbClient, error);
}
}
@Override
public void copySnapshotToTarget(StorageSystem storage, URI snapshot,
TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
_log.info("copySnapshotToTarget operation START");
callEMCRefreshIfRequired(_dbClient, _helper, storage,
Arrays.asList(snapshot));
BlockSnapshot snapshotObj =
_dbClient.queryObject(BlockSnapshot.class, snapshot);
CIMObjectPath target = _cimPath.getBlockObjectPath(storage, snapshotObj);
if (snapshotObj.getSettingsInstance() == null) {
_log.error("Snap session is null for target {}", snapshotObj.getSnapsetLabel());
taskCompleter.error(_dbClient, DeviceControllerErrors.vnx
.copySnapshotToTargetSettingsInstanceNull(snapshotObj
.getSnapsetLabel(), snapshotObj.getId().toString()));
return;
}
CIMObjectPath settingsState =
_helper.getSettingsDefineStateForSource(storage,
snapshotObj.getSettingsInstance());
CIMArgument[] inArgs =
_helper.getVNXCopyToTargetInputArguments(settingsState, target);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.callModifySettingsDefineState(storage, inArgs, outArgs);
snapshotObj.setNeedsCopyToTarget(true);
_dbClient.persistObject(snapshotObj);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Exception in copySnapshotToTarget", e);
taskCompleter.error(_dbClient, DeviceControllerErrors.vnx
.copySnapshotToTargetException(e));
}
}
/**
* This operation will make the call to copy the source information to the target
* volumes of the snap.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshotList [required] - List of URIs pointing to BlockSnapshots
* @param taskCompleter [required] - TaskCompleter to update with status.
*
* @throws DeviceControllerException
*/
@Override
public void copyGroupSnapshotsToTarget(StorageSystem storage,
List<URI> snapshotList,
TaskCompleter taskCompleter)
throws DeviceControllerException {
try {
_log.info("copyGroupSnapshotsToTarget operation START");
callEMCRefreshIfRequired(_dbClient, _helper, storage, snapshotList);
BlockSnapshot snapshot =
_dbClient.queryObject(BlockSnapshot.class, snapshotList.get(0));
if (snapshot.getSettingsGroupInstance() == null) {
taskCompleter.error(_dbClient, DeviceControllerErrors.vnx
.copyGroupSnapshotsToTargetSettingsInstanceNull(snapshot
.getSnapsetLabel(), snapshot.getId().toString()));
return;
}
internalGroupSnapCopyToTarget(storage, snapshot, snapshotList);
taskCompleter.ready(_dbClient);
} catch (Exception e) {
_log.error("Exception in copyGroupSnapshotsToTarget", e);
taskCompleter.error(_dbClient, DeviceControllerErrors.vnx
.copyGroupSnapshotsToTargetException(e));
}
}
/**
* This method will delete a snapshot that was created as part of volume consistency
* group 'snap-set'.
*
* @param storage [required] - StorageSystem object representing the array
* @param snapshot [required] - BlockSnapshot URI representing the previously created
* snap for the volume
* @param taskCompleter - TaskCompleter object used for the updating operation status.
* @return true - All the snaps in the 'snap-set' where deleted successfully.
* @throws WorkflowException
*/
private boolean deleteConsistencyGroupSnapshot(StorageSystem storage, BlockSnapshot snap, TaskCompleter taskCompleter)
throws DeviceControllerException {
boolean wasSuccess = false;
try {
callEMCRefreshIfRequired(_dbClient, _helper, storage,
Arrays.asList(snap.getId()));
CIMObjectPath syncObjectPath = _cimPath.getSyncObject(storage, snap);
if (_helper.checkExists(storage, syncObjectPath, false, false) != null) {
deactivateSnapshot(storage, snap, syncObjectPath);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.callModifyReplica(storage, _helper.getDeleteSnapshotSynchronousInputArguments(syncObjectPath), outArgs);
if (snap.getSettingsInstance() != null) {
Volume volume = _dbClient.queryObject(Volume.class, snap.getParent());
outArgs = new CIMArgument[5];
_helper.callModifySettingsDefineState(storage,
_helper.getDeleteSettingsForSnapshotInputArguments(storage, volume, snap), outArgs);
}
}
wasSuccess = true;
} catch (WBEMException e) {
String message = String.format("Error encountered during delete snapshot %s on array %s",
snap.getId().toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.unableToCallStorageProvider(e.getMessage());
taskCompleter.error(_dbClient, error);
} catch (Exception e) {
String message = String.format("Generic exception when trying to delete snapshot %s on array %s",
snap.getId().toString(), storage.getSerialNumber());
_log.error(message, e);
ServiceError error = DeviceControllerErrors.smis.methodFailed("deleteConsistencyGroupSnapshot", e.getMessage());
taskCompleter.error(_dbClient, error);
}
return wasSuccess;
}
/**
* Internal function to call SMI-S to run Copy-to-Target for CG snapshot
*
* @param storage [in] - StorageSystem object
* @param snapshot [in] - BlockSnapshot object. One of the snaps in the CG
* @param snapshotList [in] - List of BlockSnapshot URIs. These are all the snaps in
* CG snap set.
* @throws Exception
*/
private void internalGroupSnapCopyToTarget(StorageSystem storage,
BlockSnapshot snapshot,
List<URI> snapshotList)
throws Exception {
String snapGroupName = snapshot.getReplicationGroupInstance();
CIMObjectPath targetGroup =
_cimPath.getReplicationGroupPath(storage, snapGroupName);
CIMObjectPath settingsState =
_helper.getSettingsDefineStateForSourceGroup(storage,
snapshot.getSettingsGroupInstance());
CIMArgument[] inArgs =
_helper.getVNXCopyToTargetGroupInputArguments(settingsState,
targetGroup);
CIMArgument[] outArgs = new CIMArgument[5];
_helper.callModifySettingsDefineState(storage, inArgs, outArgs);
List<BlockSnapshot> snapshots =
_dbClient.queryObject(BlockSnapshot.class, snapshotList);
for (BlockSnapshot it : snapshots) {
it.setNeedsCopyToTarget(false);
}
_dbClient.persistObject(snapshots);
}
/**
* Check if 'volume' is based on a ThinPool
*
* @param volume [in] Volume object used for checking the StoragePool
* @return true iff 'volume' is based of a StoragePool that supports Thin volumes.
*/
private boolean isBasedOnVNXThinStoragePool(Volume volume) {
boolean result = false;
if (volume != null) {
StoragePool pool = _dbClient.queryObject(StoragePool.class, volume.getPool());
if (pool != null) {
String supportedResourceTypes = pool.getSupportedResourceTypes();
result = (supportedResourceTypes.equals(StoragePool.SupportedResourceTypes.THIN_ONLY.name()) ||
supportedResourceTypes.equals(StoragePool.SupportedResourceTypes.THIN_AND_THICK.name()));
}
}
return result;
}
/**
* {@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();
}
}