/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource.snapshot;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.emc.storageos.Controller;
import com.emc.storageos.api.service.authorization.PermissionsHelper;
import com.emc.storageos.api.service.impl.resource.ArgValidator;
import com.emc.storageos.api.service.impl.resource.BlockServiceApi;
import com.emc.storageos.api.service.impl.resource.fullcopy.BlockFullCopyManager;
import com.emc.storageos.api.service.impl.resource.utils.BlockServiceUtils;
import com.emc.storageos.api.service.impl.resource.utils.VolumeIngestionUtil;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
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.BlockSnapshotSession;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.Project;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.TenantOrg;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.client.util.ResourceOnlyNameGenerator;
import com.emc.storageos.model.ResourceOperationTypeEnum;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.util.VPlexUtil;
import com.emc.storageos.volumecontroller.impl.smis.SmisConstants;
/**
*
*/
public class DefaultBlockSnapshotSessionApiImpl implements BlockSnapshotSessionApi {
// A reference to a database client.
protected DbClient _dbClient;
// A reference to the coordinator.
protected CoordinatorClient _coordinator = null;
// A reference to a permissions helper.
private PermissionsHelper _permissionsHelper = null;
// A reference to the security context
private SecurityContext _securityContext;
// A reference to the snapshot session manager
protected BlockSnapshotSessionManager _blockSnapshotSessionMgr;
@SuppressWarnings("unused")
private static final Logger s_logger = LoggerFactory.getLogger(DefaultBlockSnapshotSessionApiImpl.class);
/**
* Protected default constructor.
*/
protected DefaultBlockSnapshotSessionApiImpl() {
}
/**
* Constructor.
*
* @param dbClient A reference to a data base client.
* @param coordinator A reference to the coordinator client.
* @param permissionsHelper A reference to a permission helper.
* @param securityContext A reference to the security context.
* @param blockSnapshotSessionMgr A reference to the snapshot session manager.
*/
public DefaultBlockSnapshotSessionApiImpl(DbClient dbClient, CoordinatorClient coordinator, PermissionsHelper permissionsHelper,
SecurityContext securityContext, BlockSnapshotSessionManager blockSnapshotSessionMgr) {
_dbClient = dbClient;
_coordinator = coordinator;
_permissionsHelper = permissionsHelper;
_securityContext = securityContext;
_blockSnapshotSessionMgr = blockSnapshotSessionMgr;
}
/**
* {@inheritDoc}
*/
@Override
public void validateSnapshotSessionCreateRequest(BlockObject requestedSourceObj, List<BlockObject> sourceObjList, Project project,
String name, int newTargetsCount, String newTargetsName, String newTargetCopyMode, boolean skipInternalCheck,
BlockFullCopyManager fcManager) {
// Validate the project tenant.
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI());
ArgValidator.checkEntity(tenant, project.getTenantOrg().getURI(), false);
// Verify the user is authorized.
BlockServiceUtils.verifyUserIsAuthorizedForRequest(project,
BlockServiceUtils.getUserFromContext(_securityContext), _permissionsHelper);
// Verify a name was specified in the request.
ArgValidator.checkFieldNotEmpty(name, "name");
// Verify a name length does not exceed the maximum snapshot name length
ArgValidator.checkFieldLengthMaximum(name, SmisConstants.MAX_SMI80_SNAPSHOT_NAME_LENGTH, "name");
if (StringUtils.hasText(newTargetsName)) {
// Verify a name length does not exceed the maximum snapshot name length
ArgValidator.checkFieldLengthMaximum(newTargetsName, SmisConstants.MAX_SMI80_SNAPSHOT_NAME_LENGTH, "Target Name");
}
// Verify the source objects.
List<Volume> sourceVolumeList = new ArrayList<Volume>();
for (BlockObject sourceObj : sourceObjList) {
URI sourceURI = sourceObj.getId();
if (URIUtil.isType(sourceURI, Volume.class)) {
Volume sourceVolume = (Volume) sourceObj;
// Make sure that we don't have some pending
// operation against the volume.
checkForPendingTasks(sourceVolume, sourceVolume.getTenant().getURI());
// Verify the operation is supported for ingested volumes.
VolumeIngestionUtil.checkOperationSupportedOnIngestedVolume(sourceVolume,
ResourceOperationTypeEnum.CREATE_SNAPSHOT_SESSION, _dbClient);
// Verify the source is not an internal object.
if (!skipInternalCheck) {
BlockServiceUtils.validateNotAnInternalBlockObject(sourceObj, false);
}
// Verify that array snapshots are allowed.
VirtualPool vpool = BlockSnapshotSessionUtils.querySnapshotSessionSourceVPool(sourceObj, _dbClient);
int maxVpoolSnaps = vpool.getMaxNativeSnapshots().intValue();
if (maxVpoolSnaps == 0) {
throw APIException.badRequests.maxNativeSnapshotsIsZero(vpool.getLabel());
}
// Verify the number of array snapshots does not exceed
// the limit specified by the virtual pool.
int numNativeArraySnapshots = getNumNativeSnapshots(sourceVolume);
if (numNativeArraySnapshots >= maxVpoolSnaps) {
throw APIException.badRequests.maximumNumberVpoolSnapshotsReached(sourceURI.toString());
}
// Verify the number of array snapshots does not exceed
// the limit specified by the platform.
int maxSnapsForSource = getMaxSnapshotsForSource();
if (numNativeArraySnapshots >= maxSnapsForSource) {
throw APIException.badRequests.maximumNumberSnapshotsForSourceReached(sourceURI.toString());
}
// Check for duplicate name.
checkForDuplicateSnapshotName(name, sourceVolume);
if (StringUtils.hasText(newTargetsName)) {
checkForDuplicateSnapshotName(newTargetsName, sourceVolume);
}
// Verify the new target count. There can be restrictions on the
// number of targets that can be linked to the snapshot sessions
// for a given source.
verifyNewTargetCount(sourceObj, newTargetsCount, true);
} else {
// TBD Future - What if source is a BlockSnapshot i.e., cascaded snapshot?
// What about when the source is a BlockSnapshot. It has no vpool
// and no max snaps value. It could be determined from and be the
// same as the source device. Or, these cascaded snaps could be
// cumulative and count against the max for the source.
throw APIException.badRequests.createSnapSessionNotSupportForSnapshotSource();
}
}
// Some systems, such as VMAX3, don't support array snapshots when there
// are active full copies sessions on the source.
URI requestSourceObjURI = requestedSourceObj.getId();
if (URIUtil.isType(requestSourceObjURI, Volume.class)) {
fcManager.validateSnapshotCreateRequest((Volume) requestedSourceObj, sourceVolumeList);
}
}
/**
* Checks for pending tasks on the passed data object.
*
* @param object A reference to a data object.
* @param tenantURI The URI of the tenant.
*/
protected <T extends DataObject> void checkForPendingTasks(T object, URI tenantURI) {
BlockServiceUtils.checkForPendingTasks(tenantURI, Arrays.asList(object), _dbClient);
}
/**
* Counts and returns the number of arrays snapshots for
* the passed volume. Should be overridden when the number
* of native snapshots are determined in a different manner
* for the platform.
*
* @param volume A reference to a snapshot source volume.
*
* @return The number of array snapshots on a volume.
*/
protected int getNumNativeSnapshots(Volume volume) {
return BlockServiceUtils.getNumNativeSnapshots(volume.getId(), _dbClient);
}
/**
* Get the maximum number of snapshots allowed for a source
* on the storage system. Should be overridden for each
* platform as needed.
*
* @return The maximum number of snapshots allowed for a source.
*/
protected int getMaxSnapshotsForSource() {
return Integer.MAX_VALUE;
}
/**
* Check if a array snapshot with the same name exists for the passed volume.
* Note that we need to compare the passed name to the session label for
* the volumes snapshot sessions because the actual session names can have
* an appended suffix when the volume is in a CG with multiple volumes.
* Also, we need to run the name through the generator, which is done
* prior to setting the session label for a snapshot session. Should be overridden
* when the manner in which duplicate names are checked is determined in a
* different manner for the platform.
*
* @param requestedName The name to verify.
* @param volume A reference to a snapshot source volume.
*/
protected void checkForDuplicateSnapshotName(String requestedName, Volume volume) {
BlockServiceUtils.checkForDuplicateArraySnapshotName(requestedName, volume.getId(), _dbClient);
}
/**
* Verifies that the number of targets to be linked to a snapshot session
* is valid for the specified source. Should be overridden when there are
* different or additional platform restrictions.
*
* @param sourceObj A reference to the snapshot session source
* @param newTargetsCount The number of new targets to be linked to a session.
* @param zeroIsValid true if zero is a valid count, false otherwise.
*/
protected void verifyNewTargetCount(BlockObject sourceObj, int newTargetsCount, boolean zeroIsValid) {
// If zero is no valid and the value is zero, throw an error.
if ((!zeroIsValid) && (newTargetsCount == 0)) {
throw APIException.badRequests.invalidZeroLinkedTargetsRequested();
}
}
/**
* {@inheritDoc}
*/
@Override
public BlockSnapshotSession prepareSnapshotSession(List<BlockObject> sourceObjList, String snapSessionLabel, int newTargetCount,
String newTargetsName, List<Map<URI, BlockSnapshot>> snapSessionSnapshots, String taskId, boolean inApplication) {
// Create a single snap session based on a sample volume in the CG
BlockObject source = sourceObjList.get(0);
BlockSnapshotSession snapSession = prepareSnapshotSessionFromSource(source, snapSessionLabel, snapSessionLabel, taskId, inApplication);
/*
* If linked targets are requested...
*
* Non-CG case for source ["src"] with 2 targets named "linked":
* [
* ["linked-1"],
* ["linked-2"]
* ]
*
* CG case for sources ["src-1", "src-2"] with 2 targets named "linked":
* [
* ["linked-1-1", "linked-1-2"],
* ["linked-2-1", "linked-2-2"]
* ]
*
* i.e. treat non-CG single volumes as single member groups, then for however
* many target requests, copy each group.
*/
if (newTargetCount > 0) {
// Create <newTargetCount> lists of targets
// Snapset labels use format <newTargetsName>-<currentTargetCount>
// Labels will look like <snapsetLabel>-<count>
List<Map<URI, BlockSnapshot>> targetMaps = prepareSnapshotsForSession(sourceObjList, sourceObjList.size(),
newTargetCount, newTargetsName, inApplication);
snapSessionSnapshots.addAll(targetMaps);
}
// Create and return the prepared snapshot session.
_dbClient.createObject(snapSession);
return snapSession;
}
/**
* {@inheritDoc}
*/
@Override
public BlockSnapshotSession prepareSnapshotSessionFromSource(BlockObject sourceObj, String snapSessionLabel, String instanceLabel,
String taskId, boolean inApplication) {
BlockSnapshotSession snapSession = new BlockSnapshotSession();
Project sourceProject = BlockSnapshotSessionUtils.querySnapshotSessionSourceProject(sourceObj, _dbClient);
snapSession.setId(URIUtil.createId(BlockSnapshotSession.class));
snapSession.setProject(new NamedURI(sourceProject.getId(), sourceObj.getLabel()));
snapSession.setStorageController(sourceObj.getStorageController());
if (NullColumnValueGetter.isNotNullValue(sourceObj.getReplicationGroupInstance())) {
snapSession.setConsistencyGroup(sourceObj.getConsistencyGroup());
snapSession.setSessionSetName(snapSessionLabel);
String rgName = sourceObj.getReplicationGroupInstance();
if (NullColumnValueGetter.isNotNullValue(rgName)) {
snapSession.setReplicationGroupInstance(rgName);
if (inApplication) {
// append RG name to user given label to uniquely identify sessions
// when there are multiple RGs in a CG
instanceLabel = String.format("%s-%s", instanceLabel, rgName);
}
}
} else {
snapSession.setParent(new NamedURI(sourceObj.getId(), sourceObj.getLabel()));
}
snapSession.setLabel(instanceLabel);
snapSession.setSessionLabel(ResourceOnlyNameGenerator.removeSpecialCharsForName(snapSessionLabel,
SmisConstants.MAX_SNAPSHOT_NAME_LENGTH));
return snapSession;
}
/**
* {@inheritDoc}
*/
@Override
public BlockSnapshot prepareSnapshotForSession(BlockObject sourceObj, String snapsetLabel, String label) {
BlockSnapshot snapshot = new BlockSnapshot();
snapshot.setId(URIUtil.createId(BlockSnapshot.class));
URI cgUri = sourceObj.getConsistencyGroup();
if (cgUri != null) {
snapshot.setConsistencyGroup(cgUri);
}
snapshot.setSourceNativeId(sourceObj.getNativeId());
snapshot.setParent(new NamedURI(sourceObj.getId(), sourceObj.getLabel()));
snapshot.setLabel(label);
snapshot.setStorageController(sourceObj.getStorageController());
snapshot.setSystemType(sourceObj.getSystemType());
snapshot.setVirtualArray(sourceObj.getVirtualArray());
snapshot.setProtocol(new StringSet());
snapshot.getProtocol().addAll(sourceObj.getProtocol());
Project sourceProject = BlockSnapshotSessionUtils.querySnapshotSessionSourceProject(sourceObj, _dbClient);
snapshot.setProject(new NamedURI(sourceProject.getId(), sourceObj.getLabel()));
snapshot.setSnapsetLabel(ResourceOnlyNameGenerator.removeSpecialCharsForName(
snapsetLabel, SmisConstants.MAX_SNAPSHOT_NAME_LENGTH));
snapshot.setTechnologyType(BlockSnapshot.TechnologyType.NATIVE.name());
_dbClient.createObject(snapshot);
return snapshot;
}
/**
* {@inheritDoc}
*/
@Override
public List<Map<URI, BlockSnapshot>> prepareSnapshotsForSession(List<BlockObject> sourceObjList, int sourceCount, int newTargetCount,
String newTargetsName, boolean inApplication) {
List<Map<URI, BlockSnapshot>> snapSessionSnapshots = new ArrayList<>();
Collections.sort(sourceObjList, new Comparator<BlockObject>() {
@Override
public int compare(BlockObject one, BlockObject two) {
return one.getLabel().compareToIgnoreCase(two.getLabel());
}
});
for (int i = 0; i < newTargetCount; i++) {
int count = 0;
Map<URI, BlockSnapshot> targetMap = new HashMap<>();
for (BlockObject sourceObj : sourceObjList) {
// Generate label here
String snapsetLabel = String.format("%s-%s", newTargetsName, i + 1);
String label = snapsetLabel;
String rgName = sourceObj.getReplicationGroupInstance();
if (sourceObj instanceof Volume && ((Volume) sourceObj).isVPlexVolume(_dbClient)) {
// get RG name from back end volume
Volume srcBEVolume = VPlexUtil.getVPLEXBackendVolume((Volume) sourceObj, true, _dbClient);
rgName = srcBEVolume.getReplicationGroupInstance();
}
if (NullColumnValueGetter.isNotNullValue(rgName) && inApplication) {
// There can be multiple RGs in a CG, in such cases generate unique name
if (sourceObjList.size() > 1) {
label = String.format("%s-%s-%s", snapsetLabel, rgName, ++count);
} else {
label = String.format("%s-%s", snapsetLabel, rgName);
}
} else if (sourceObjList.size() > 1) {
label = String.format("%s-%s", snapsetLabel, ++count);
}
BlockServiceUtils.checkForDuplicateArraySnapshotName(snapsetLabel, sourceObj.getId(), _dbClient);
BlockSnapshot blockSnapshot = prepareSnapshotForSession(sourceObj, snapsetLabel, label);
targetMap.put(blockSnapshot.getId(), blockSnapshot);
}
snapSessionSnapshots.add(targetMap);
}
return snapSessionSnapshots;
}
/**
* {@inheritDoc}
*/
@Override
public void createSnapshotSession(BlockObject sourceObj, URI snapSessionURI,
List<List<URI>> snapSessionSnapshotURIs, String copyMode, String taskId) {
// Must be implemented by platform implementations for which this is supported.
throw APIException.methodNotAllowed.notSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void validateLinkNewTargetsRequest(BlockObject snapSessionSourceObj, Project project, int newTargetsCount,
String newTargetsName, String newTargetCopyMode) {
// Validate the project tenant.
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI());
ArgValidator.checkEntity(tenant, project.getTenantOrg().getURI(), false);
// Verify the user is authorized.
BlockServiceUtils.verifyUserIsAuthorizedForRequest(project,
BlockServiceUtils.getUserFromContext(_securityContext), _permissionsHelper);
// Verify the new target count. There can be restrictions on the
// number of targets that can be linked to the snapshot sessions
// for a given source.
verifyNewTargetCount(snapSessionSourceObj, newTargetsCount, false);
}
/**
* {@inheritDoc}
*/
@Override
public void linkNewTargetVolumesToSnapshotSession(BlockObject snapSessionSourceObj, BlockSnapshotSession snapSession,
List<List<URI>> snapshotURIs, String copyMode, String taskId) {
throw APIException.methodNotAllowed.notSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void validateRelinkSnapshotSessionTargets(BlockObject snapSessionSourceObj, BlockSnapshotSession tgtSnapSession,
Project project, List<URI> snapshotURIs, UriInfo uriInfo) {
// Validate the project tenant.
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI());
ArgValidator.checkEntity(tenant, project.getTenantOrg().getURI(), false);
// Verify the user is authorized.
BlockServiceUtils.verifyUserIsAuthorizedForRequest(project,
BlockServiceUtils.getUserFromContext(_securityContext), _permissionsHelper);
// Verify that each target is currently linked to a block
// snapshot session of the same source.
URI currentSnapSessionSourceURI = null;
String currentSnapSessionSourceGroupName = null;
for (URI snapshotURI : snapshotURIs) {
BlockSnapshotSessionUtils.validateSnapshot(snapshotURI, uriInfo, _dbClient);
List<BlockSnapshotSession> snaphotSessionsList = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient,
BlockSnapshotSession.class, ContainmentConstraint.Factory.getLinkedTargetSnapshotSessionConstraint(snapshotURI));
if (snaphotSessionsList.isEmpty()) {
// The target is not linked to an active snapshot session.
throw APIException.badRequests.relinkTargetNotLinkedToActiveSnapshotSession(snapshotURI.toString());
}
// A target can only be linked to a single session.
BlockSnapshotSession snapshotSnapSession = snaphotSessionsList.get(0);
if (snapshotSnapSession.hasConsistencyGroup()) {
if (currentSnapSessionSourceURI == null) {
currentSnapSessionSourceURI = snapshotSnapSession.getConsistencyGroup();
} else if (!snapshotSnapSession.getConsistencyGroup().equals(currentSnapSessionSourceURI)) {
// Not all targets to be re-linked are linked to a block
// snapshot session of the same source.
throw APIException.badRequests.relinkSnapshotSessionsNotOfSameSource();
}
// validate for source Replication Group since there can be multiple replication groups within a CG.
if (currentSnapSessionSourceGroupName == null) {
currentSnapSessionSourceGroupName = snapshotSnapSession.getReplicationGroupInstance();
} else if (!currentSnapSessionSourceGroupName.equals(snapshotSnapSession.getReplicationGroupInstance())) {
// Not all targets to be re-linked are linked to a block
// snapshot session of the same source group.
throw APIException.badRequests.relinkSnapshotSessionsNotOfSameSource();
}
} else {
// Verify that the snapshot session for the target is the same
// as that for the other targets to be re-linked.
if (currentSnapSessionSourceURI == null) {
currentSnapSessionSourceURI = snapshotSnapSession.getParent().getURI();
} else if (!snapshotSnapSession.getParent().getURI().equals(currentSnapSessionSourceURI)) {
// Not all targets to be re-linked are linked to a block
// snapshot session of the same source.
throw APIException.badRequests.relinkSnapshotSessionsNotOfSameSource();
}
}
}
// All targets to be re-linked are linked to an active block snapshot
// session of the same source. Now make sure target snapshot session
// has this same source.
URI tgtSnapSessionSourceURI = tgtSnapSession.hasConsistencyGroup() ? tgtSnapSession.getConsistencyGroup()
: tgtSnapSession.getParent().getURI();
if (!tgtSnapSessionSourceURI.equals(currentSnapSessionSourceURI)) {
throw APIException.badRequests.relinkTgtSnapshotSessionHasDifferentSource(currentSnapSessionSourceURI.toString());
}
String tgtSnapSessionSourceGroupName = tgtSnapSession.getReplicationGroupInstance();
if (NullColumnValueGetter.isNotNullValue(tgtSnapSessionSourceGroupName)
&& !tgtSnapSessionSourceGroupName.equals(currentSnapSessionSourceGroupName)) {
throw APIException.badRequests.relinkTgtSnapshotSessionHasDifferentSource(currentSnapSessionSourceGroupName);
}
}
/**
* {@inheritDoc}
*/
@Override
public void relinkTargetVolumesToSnapshotSession(BlockObject snapSessionSourceObj, BlockSnapshotSession tgtSnapSession,
List<URI> snapshotURIs, String taskId) {
throw APIException.methodNotAllowed.notSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void validateUnlinkSnapshotSessionTargets(BlockSnapshotSession snapSession, BlockObject snapSessionSourceObj, Project project,
Map<URI, Boolean> targetMap, UriInfo uriInfo) {
// Validate the project tenant.
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI());
ArgValidator.checkEntity(tenant, project.getTenantOrg().getURI(), false);
// Verify the user is authorized.
BlockServiceUtils.verifyUserIsAuthorizedForRequest(project,
BlockServiceUtils.getUserFromContext(_securityContext), _permissionsHelper);
// Validate targets are for the passed session.
Set<URI> snapshotURIs = targetMap.keySet();
BlockSnapshotSessionUtils.validateSnapshotSessionTargets(snapSession, snapshotURIs, uriInfo, _dbClient);
// Targets cannot be unlinked if they are exported as this
// would make the data unavailable to the export host(s).
for (URI snapshotURI : snapshotURIs) {
URIQueryResultList queryResults = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory.getSnapshotExportGroupConstraint(snapshotURI), queryResults);
if (queryResults.iterator().hasNext()) {
throw APIException.badRequests.cantUnlinkExportedSnapshotSessionTarget(snapshotURI.toString());
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void unlinkTargetVolumesFromSnapshotSession(BlockObject snapSessionSourceObj, BlockSnapshotSession snapSession,
Map<URI, Boolean> snapshotDeletionMap, OperationTypeEnum opType, String taskId) {
throw APIException.methodNotAllowed.notSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void validateRestoreSnapshotSession(List<BlockObject> snapSessionSourceObjs, Project project) {
// Validate the project tenant.
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI());
ArgValidator.checkEntity(tenant, project.getTenantOrg().getURI(), false);
// Verify the user is authorized.
BlockServiceUtils.verifyUserIsAuthorizedForRequest(project,
BlockServiceUtils.getUserFromContext(_securityContext), _permissionsHelper);
for (BlockObject snapSessionSourceObj : snapSessionSourceObjs) {
if (URIUtil.isType(snapSessionSourceObj.getId(), Volume.class)) {
// Make sure that we don't have some pending
// operation against the volume.
Volume sourceVolume = (Volume) snapSessionSourceObj;
checkForPendingTasks(sourceVolume, sourceVolume.getTenant().getURI());
// On some platforms it is not possible to restore an array snapshot
// point-in-time copy to a source volume if the volume has active mirrors.
verifyActiveMirrors(sourceVolume);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void verifyActiveMirrors(Volume sourceVolume) {
// By default, disallow if there are active mirrors on the volume.
List<URI> activeMirrorsForSource = BlockServiceUtils.getActiveMirrorsForVolume(sourceVolume, _dbClient);
if (!activeMirrorsForSource.isEmpty()) {
throw APIException.badRequests.snapshotSessionSourceHasActiveMirrors(
sourceVolume.getLabel(), activeMirrorsForSource.size());
}
}
/**
* {@inheritDoc}
*/
@Override
public void restoreSnapshotSession(BlockSnapshotSession snapSession, BlockObject snapSessionSourceObj, String taskId) {
throw APIException.methodNotAllowed.notSupported();
}
/**
* {@inheritDoc}
*/
@Override
public void validateDeleteSnapshotSession(BlockSnapshotSession snapSession, BlockObject snapSessionSourceObj, Project project) {
// Validate the project tenant.
TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI());
ArgValidator.checkEntity(tenant, project.getTenantOrg().getURI(), false);
// Verify the user is authorized.
BlockServiceUtils.verifyUserIsAuthorizedForRequest(project,
BlockServiceUtils.getUserFromContext(_securityContext), _permissionsHelper);
// Verify no pending tasks on the snapshot session.
if (URIUtil.isType(snapSessionSourceObj.getId(), Volume.class)) {
// Make sure that we don't have some pending
// operation against the snapshot session.
checkForPendingTasks(snapSession, ((Volume) snapSessionSourceObj).getTenant().getURI());
}
// Verify the snapshot session has no linked targets.
StringSet linkedTargetIds = snapSession.getLinkedTargets();
if ((linkedTargetIds != null) && (!linkedTargetIds.isEmpty())) {
List<URI> linkedTargetURIs = URIUtil.toURIList(linkedTargetIds);
Iterator<BlockSnapshot> activeLinkedTargets = _dbClient.queryIterativeObjects(BlockSnapshot.class, linkedTargetURIs, true);
if (activeLinkedTargets.hasNext()) {
throw APIException.badRequests.canDeactivateSnapshotSessionWithLinkedTargets();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void deleteSnapshotSession(BlockSnapshotSession snapSession, BlockObject snapSessionSourceObj, String taskId,
String deleteType) {
throw APIException.methodNotAllowed.notSupported();
}
/**
* Looks up controller dependency for given hardware
*
* @param clazz controller interface
* @param hw hardware name
*
* @return A reference to the controller.
*/
protected <T extends Controller> T getController(Class<T> clazz, String hw) {
return _coordinator.locateService(clazz, BlockServiceApi.CONTROLLER_SVC,
BlockServiceApi.CONTROLLER_SVC_VER, hw, clazz.getSimpleName());
}
/**
* {@inheritDoc}
*/
@Override
public List<BlockSnapshotSession> getSnapshotSessionsForSource(BlockObject sourceObj) {
return CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, BlockSnapshotSession.class,
ContainmentConstraint.Factory.getParentSnapshotSessionConstraint(sourceObj.getId()));
}
@Override
public List<BlockSnapshotSession> getSnapshotSessionsForConsistencyGroup(BlockConsistencyGroup group) {
return CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, BlockSnapshotSession.class,
ContainmentConstraint.Factory.getBlockSnapshotSessionByConsistencyGroup(group.getId()));
}
@Override
public List<BlockSnapshotSession> getSnapshotSessionsBySessionInstance(String instance) {
return CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, BlockSnapshotSession.class,
AlternateIdConstraint.Factory.getBlockSnapshotSessionBySessionInstance(instance));
}
/**
* Get the BlockSnapshotSessionApi implementation for the system with the passed URI.
*
* @param systemURI The URI of a storage system.
*
* @return The BlockSnapshotSessionApi implementation for the storage system.
*/
protected BlockSnapshotSessionApi getImplementationForBackendSystem(URI systemURI) {
StorageSystem srcSideBackendSystem = _dbClient.queryObject(StorageSystem.class, systemURI);
BlockSnapshotSessionApi snapSessionImpl = _blockSnapshotSessionMgr
.getPlatformSpecificImplForSystem(srcSideBackendSystem);
return snapSessionImpl;
}
}