/*
* 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.List;
import java.util.Map;
import javax.ws.rs.core.SecurityContext;
import com.emc.storageos.api.service.authorization.PermissionsHelper;
import com.emc.storageos.api.service.impl.resource.fullcopy.BlockFullCopyManager;
import com.emc.storageos.blockorchestrationcontroller.BlockOrchestrationController;
import com.emc.storageos.blockorchestrationcontroller.VolumeDescriptor;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshotSession;
import com.emc.storageos.db.client.model.Operation;
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.util.CustomQueryUtility;
import com.emc.storageos.model.block.VolumeDeleteTypeEnum;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.volumecontroller.BlockController;
import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper;
/**
* Block snapshot session implementation for volumes a VMAX3 systems.
*/
public class VMAX3BlockSnapshotSessionApiImpl extends DefaultBlockSnapshotSessionApiImpl {
private static final int MAX_LINKED_TARGETS_PER_SOURCE = 1024;
private static final int MAX_SNAPSHOTS_PER_SOURCE = 256;
/**
* Private default constructor should not be called outside class.
*/
@SuppressWarnings("unused")
private VMAX3BlockSnapshotSessionApiImpl() {
super();
}
/**
* 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 VMAX3BlockSnapshotSessionApiImpl(DbClient dbClient, CoordinatorClient coordinator, PermissionsHelper permissionsHelper,
SecurityContext securityContext, BlockSnapshotSessionManager blockSnapshotSessionMgr) {
super(dbClient, coordinator, permissionsHelper, securityContext, 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) {
// Do the super class validation.
super.validateSnapshotSessionCreateRequest(requestedSourceObj, sourceObjList, project, name, newTargetsCount,
newTargetsName, newTargetCopyMode, skipInternalCheck, fcManager);
// Verify new target copy mode is a valid value.
verifyNewTargetCopyMode(newTargetCopyMode);
}
/**
* Verifies the copy mode specified is valid.
*
* @param copyMode The copy mode specified in the request.
*/
private void verifyNewTargetCopyMode(String copyMode) {
if ((!BlockSnapshotSession.CopyMode.copy.name().equals(copyMode))
&& (!BlockSnapshotSession.CopyMode.nocopy.name().equals(copyMode))) {
throw APIException.badRequests.invalidCopyModeForLinkedTarget(copyMode);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void verifyNewTargetCount(BlockObject sourceObj, int newTargetsCount, boolean zeroIsValid) {
// Call super first.
super.verifyNewTargetCount(sourceObj, newTargetsCount, zeroIsValid);
// Now make sure max is not exceeded.
if (newTargetsCount > 0) {
// The total number of linked targets for all sessions for a given
// source can't exceed 1024. So, get all sessions for the source
// and add all linked targets for these sessions. That value plus
// the number of new targets cannot exceed the max.
int totalLinkedTargets = newTargetsCount;
List<BlockSnapshotSession> snapSessions = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient,
BlockSnapshotSession.class, ContainmentConstraint.Factory.getParentSnapshotSessionConstraint(sourceObj.getId()));
for (BlockSnapshotSession snapSession : snapSessions) {
StringSet linkedTargetIds = snapSession.getLinkedTargets();
if (linkedTargetIds != null) {
totalLinkedTargets += linkedTargetIds.size();
}
}
if (totalLinkedTargets > MAX_LINKED_TARGETS_PER_SOURCE) {
throw APIException.badRequests.invalidNewLinkedTargetsCount(newTargetsCount, sourceObj.getLabel(),
MAX_LINKED_TARGETS_PER_SOURCE - totalLinkedTargets);
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected int getMaxSnapshotsForSource() {
return MAX_SNAPSHOTS_PER_SOURCE;
}
/**
* {@inheritDoc}
*/
@Override
public void createSnapshotSession(BlockObject sourceObj, URI snapSessionURI,
List<List<URI>> snapSessionSnapshotURIs, String copyMode, String taskId) {
// Invoke the BlockDeviceController to create the array snapshot session and create and link
// target volumes as necessary.
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, sourceObj.getStorageController());
VirtualPoolCapabilityValuesWrapper capabilities = new VirtualPoolCapabilityValuesWrapper();
capabilities.put(VirtualPoolCapabilityValuesWrapper.SNAPSHOT_SESSION_COPY_MODE, copyMode);
VolumeDescriptor sessionDescriptor = new VolumeDescriptor(VolumeDescriptor.Type.BLOCK_SNAPSHOT_SESSION,
storageSystem.getId(), snapSessionURI, null, sourceObj.getConsistencyGroup(), capabilities,
snapSessionSnapshotURIs);
List<VolumeDescriptor> volumeDescriptors = new ArrayList<VolumeDescriptor>();
volumeDescriptors.add(sessionDescriptor);
BlockOrchestrationController controller = getController(BlockOrchestrationController.class,
BlockOrchestrationController.BLOCK_ORCHESTRATION_DEVICE);
controller.createSnapshotSession(volumeDescriptors, taskId);
}
/**
* {@inheritDoc}
*/
@Override
public void validateLinkNewTargetsRequest(BlockObject snapSessionSourceObj, Project project, int newTargetsCount,
String newTargetsName, String newTargetCopyMode) {
// Do the super class validation.
super.validateLinkNewTargetsRequest(snapSessionSourceObj, project, newTargetsCount, newTargetsName, newTargetCopyMode);
// Verify new target copy mode is a valid value.
verifyNewTargetCopyMode(newTargetCopyMode);
}
/**
* {@inheritDoc}
*/
@Override
public void linkNewTargetVolumesToSnapshotSession(BlockObject snapSessionSourceObj, BlockSnapshotSession snapSession,
List<List<URI>> snapshotURIs, String copyMode, String taskId) {
// Invoke the BlockDeviceController to create and link new target
// volumes to the passed snapshot session.
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, snapSessionSourceObj.getStorageController());
BlockController controller = getController(BlockController.class, storageSystem.getSystemType());
controller.linkNewTargetVolumesToSnapshotSession(storageSystem.getId(), snapSession.getId(), snapshotURIs, copyMode, taskId);
}
/**
* {@inheritDoc}
*/
@Override
public void relinkTargetVolumesToSnapshotSession(BlockObject snapSessionSourceObj, BlockSnapshotSession tgtSnapSession,
List<URI> snapshotURIs, String taskId) {
// Invoke the BlockDeviceController to relink the targets
// to the passed target snapshot session.
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, snapSessionSourceObj.getStorageController());
BlockController controller = getController(BlockController.class, storageSystem.getSystemType());
controller.relinkTargetsToSnapshotSession(storageSystem.getId(), tgtSnapSession.getId(), snapshotURIs, Boolean.TRUE, taskId);
}
/**
* {@inheritDoc}
*/
@Override
public void unlinkTargetVolumesFromSnapshotSession(BlockObject snapSessionSourceObj, BlockSnapshotSession snapSession,
Map<URI, Boolean> snapshotDeletionMap, OperationTypeEnum opType, String taskId) {
// Invoke the BlockDeviceController to unlink the targets
// from the snapshot session.
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, snapSessionSourceObj.getStorageController());
BlockController controller = getController(BlockController.class, storageSystem.getSystemType());
controller.unlinkTargetsFromSnapshotSession(storageSystem.getId(), snapSession.getId(), snapshotDeletionMap, opType, taskId);
}
/**
* {@inheritDoc}
*/
@Override
public void restoreSnapshotSession(BlockSnapshotSession snapSession, BlockObject snapSessionSourceObj, String taskId) {
// Invoke the BlockDeviceController to restore the snapshot session source.
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, snapSessionSourceObj.getStorageController());
BlockController controller = getController(BlockController.class, storageSystem.getSystemType());
controller.restoreSnapshotSession(storageSystem.getId(), snapSession.getId(), Boolean.TRUE, taskId);
}
/**
* {@inheritDoc}
*/
@Override
public void deleteSnapshotSession(BlockSnapshotSession snapSession, BlockObject snapSessionSourceObj, String taskId, String deleteType) {
if (VolumeDeleteTypeEnum.VIPR_ONLY.name().equals(deleteType)) {
// Update the task status for the session.
// Note that we must get the session form the database to get the latest status map.
BlockSnapshotSession updatedSession = _dbClient.queryObject(BlockSnapshotSession.class, snapSession.getId());
Operation op = updatedSession.getOpStatus().get(taskId);
op.ready("Snapshot session succesfully deleted from ViPR");
updatedSession.getOpStatus().updateTaskStatus(taskId, op);
_dbClient.updateObject(updatedSession);
// Mark the snapshot session for deletion.
_dbClient.markForDeletion(updatedSession);
} else {
// Invoke the BlockDeviceController to delete the snapshot session.
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, snapSessionSourceObj.getStorageController());
BlockController controller = getController(BlockController.class, storageSystem.getSystemType());
controller.deleteSnapshotSession(storageSystem.getId(), snapSession.getId(), taskId);
}
}
}