/*
* Copyright 2012-2015 EMC
* All Rights Reserved
*/
package com.emc.sa.service.vipr.block;
import static com.emc.sa.service.ServiceParams.CONSISTENCY_GROUP;
import static com.emc.sa.service.ServiceParams.PROJECT;
import static com.emc.sa.service.ServiceParams.VOLUMES;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.emc.sa.engine.bind.Param;
import com.emc.sa.engine.service.Service;
import com.emc.sa.service.vipr.ViPRService;
import com.emc.sa.service.vipr.block.tasks.GetActiveContinuousCopiesForVolume;
import com.emc.sa.service.vipr.block.tasks.GetActiveFullCopiesForVolume;
import com.emc.sa.service.vipr.block.tasks.GetActiveSnapshotsForVolume;
import com.emc.storageos.model.block.BlockMirrorRestRep;
import com.emc.storageos.model.block.BlockObjectRestRep;
import com.emc.storageos.model.block.BlockSnapshotRestRep;
import com.emc.storageos.model.block.VolumeRestRep;
import com.google.common.collect.Lists;
@Service("AddVolumesToConsistencyGroup")
public class AddVolumesToConsistencyGroupService extends ViPRService {
@Param(PROJECT)
protected URI project;
@Param(CONSISTENCY_GROUP)
protected URI consistencyGroup;
@Param(VOLUMES)
protected List<String> volumeIds;
@Override
public void execute() throws Exception {
// add volumes to CG
BlockStorageUtils.addVolumesToConsistencyGroup(consistencyGroup, uris(volumeIds));
// start continuous copies on one of the volumes
BlockObjectRestRep blockObject = BlockStorageUtils.getBlockResource(uri(volumeIds.get(0)));
List<URI> targets = BlockStorageUtils.getSrdfTargetVolumes(blockObject);
if (!targets.isEmpty()) {
BlockStorageUtils.createContinuousCopy(uri(volumeIds.get(0)), null, 1, BlockStorageUtils.COPY_SRDF, targets.get(0));
}
// Continuous copy
// add source volume mirror's to the CG
Map<URI, List<URI>> sourceMirrors = addSourceVolumeMirrors();
// start continuous copies on the r1 mirrors
startContinuousCopy(sourceMirrors);
// add target mirrors to the CG
Map<URI, List<URI>> targetMirrors = addTargetVolumeMirrors();
// start continuous copies on the r2 mirrors
startContinuousCopy(targetMirrors);
// Snapshot
// add source volumes' snapshots to the CG
Map<URI, List<URI>> sourceSnapshots = addSourceVolumeSnapshots();
// start snapshot on the r1 snapshots
startSnapshot(sourceSnapshots);
// add target volumes' snapshots to the CG
Map<URI, List<URI>> targetSnapshots = addTargetVolumeSnapshots();
// start snapshot on the r2 snapshots
startSnapshot(targetSnapshots);
// Full copy
// add source volumes' full copies to the CG
Map<URI, List<URI>> sourceFullCopies = addSourceVolumeFullCopies();
// start full copies on the r1 full copies
startFullCopy(sourceFullCopies);
// add target volumes' full copies to the CG
Map<URI, List<URI>> targetFullCopies = addTargetVolumeFullCopies();
// start full copies on the r2 full copies
startFullCopy(targetFullCopies);
}
/**
* Start continuous copy on one block object that has a mirror
*
* @param mirrors map of block object to mirrors
*/
public void startContinuousCopy(Map<URI, List<URI>> mirrors) {
Iterator<URI> it = mirrors.keySet().iterator();
while (it.hasNext()) {
URI blockObject = it.next();
List<URI> copyIds = mirrors.get(blockObject);
if (!copyIds.isEmpty()) {
BlockStorageUtils.createContinuousCopy(blockObject, null, 1, BlockStorageUtils.COPY_NATIVE, copyIds.get(0));
break;
}
}
}
/**
* Start full copy on one block object that has a full copy
*
* @param fullCopies map of block object to full copies
*/
public void startFullCopy(Map<URI, List<URI>> fullCopies) {
Iterator<URI> it = fullCopies.keySet().iterator();
while (it.hasNext()) {
URI blockObject = it.next();
List<URI> copyIds = fullCopies.get(blockObject);
if (!copyIds.isEmpty()) {
BlockStorageUtils.startFullCopy(copyIds.get(0));
break;
}
}
}
/**
* Start snapshot on one block object that has a snapshot
*
* @param snapshots map of block object to snapshots
*/
public void startSnapshot(Map<URI, List<URI>> snapshots) {
Iterator<URI> it = snapshots.keySet().iterator();
while (it.hasNext()) {
URI blockObject = it.next();
List<URI> copyIds = snapshots.get(blockObject);
if (!copyIds.isEmpty()) {
BlockStorageUtils.startSnapshot(copyIds.get(0));
break;
}
}
}
/**
* Get mirrors for a given volume id
*
* @param volumeId the volume id to use
* @return list of mirror ids
*/
public List<URI> getMirrors(URI volumeId) {
List<URI> blockMirrors = Lists.newArrayList();
List<BlockMirrorRestRep> blockMirrorRestReps = execute(new GetActiveContinuousCopiesForVolume(volumeId));
for (BlockMirrorRestRep blockMirrorId : blockMirrorRestReps) {
blockMirrors.add(blockMirrorId.getId());
}
return blockMirrors;
}
/**
* Get full copies for a given volume id
*
* @param volumeId the volume id to use
* @return list of full copy ids
*/
public List<URI> getFullCopies(URI volumeId) {
List<URI> fullCopies = Lists.newArrayList();
List<VolumeRestRep> fullCopyRestReps = execute(new GetActiveFullCopiesForVolume(volumeId));
for (VolumeRestRep fullCopyId : fullCopyRestReps) {
fullCopies.add(fullCopyId.getId());
}
return fullCopies;
}
/**
* Get snapshots for a given volume id
*
* @param volumeId the volume id to use
* @return list of snapshot ids
*/
public List<URI> getSnapshots(URI volumeId) {
List<URI> blockSnapshots = Lists.newArrayList();
List<BlockSnapshotRestRep> blockSnapshotRestReps = execute(new GetActiveSnapshotsForVolume(volumeId));
for (BlockSnapshotRestRep blockSnapshotId : blockSnapshotRestReps) {
blockSnapshots.add(blockSnapshotId.getId());
}
return blockSnapshots;
}
/**
* Get SRDF targets for a given volume id
*
* @param volumeId the volume id to use
* @return list of target ids
*/
public List<URI> getTargets(URI volumeId) {
BlockObjectRestRep blockObject = BlockStorageUtils.getBlockResource(volumeId);
return BlockStorageUtils.getSrdfTargetVolumes(blockObject);
}
/**
* Adds all source volume mirrors to the consistency group
*
* @return map of source volume to mirrors
*/
public Map<URI, List<URI>> addSourceVolumeMirrors() {
List<URI> blockMirrors = Lists.newArrayList();
Map<URI, List<URI>> mirrorsMap = new HashMap<>();
for (URI volumeId : uris(volumeIds)) {
List<URI> mirrors = getMirrors(volumeId);
blockMirrors.addAll(mirrors);
mirrorsMap.put(volumeId, mirrors);
}
if (!blockMirrors.isEmpty()) {
BlockStorageUtils.addVolumesToConsistencyGroup(consistencyGroup, blockMirrors);
}
return mirrorsMap;
}
/**
* Adds all target volume mirrors to the target consistency group
*
* @return map of target volume to mirrors
*/
public Map<URI, List<URI>> addTargetVolumeMirrors() {
List<URI> blockMirrors = Lists.newArrayList();
Map<URI, List<URI>> mirrorsMap = new HashMap<>();
URI targetCG = null;
for (URI volumeId : uris(volumeIds)) {
List<URI> targets = getTargets(volumeId);
for (URI target : targets) {
if (targetCG == null) {
targetCG = getConsistencyGroup(target);
}
List<URI> mirrors = getMirrors(target);
blockMirrors.addAll(mirrors);
mirrorsMap.put(target, mirrors);
}
}
if (!blockMirrors.isEmpty() && targetCG != null) {
BlockStorageUtils.addVolumesToConsistencyGroup(targetCG, blockMirrors);
}
return mirrorsMap;
}
/**
* Adds all source volumes' full copies to the consistency group
*
* @return map of source volume to full copies
*/
public Map<URI, List<URI>> addSourceVolumeFullCopies() {
List<URI> fullCopies = Lists.newArrayList();
Map<URI, List<URI>> fullCopiesMap = new HashMap<>();
for (URI volumeId : uris(volumeIds)) {
List<URI> volumeFullCopies = getFullCopies(volumeId);
fullCopies.addAll(volumeFullCopies);
fullCopiesMap.put(volumeId, volumeFullCopies);
}
if (!fullCopies.isEmpty()) {
BlockStorageUtils.addVolumesToConsistencyGroup(consistencyGroup, fullCopies);
}
return fullCopiesMap;
}
/**
* Adds all target volumes' full copies to the target consistency group
*
* @return map of target volume to full copies
*/
public Map<URI, List<URI>> addTargetVolumeFullCopies() {
List<URI> fullCopies = Lists.newArrayList();
Map<URI, List<URI>> fullCopiesMap = new HashMap<>();
URI targetCG = null;
for (URI volumeId : uris(volumeIds)) {
List<URI> targets = getTargets(volumeId);
for (URI target : targets) {
if (targetCG == null) {
targetCG = getConsistencyGroup(target);
}
List<URI> volumeFullCopies = getFullCopies(target);
fullCopies.addAll(volumeFullCopies);
fullCopiesMap.put(target, volumeFullCopies);
}
}
if (!fullCopies.isEmpty() && targetCG != null) {
BlockStorageUtils.addVolumesToConsistencyGroup(targetCG, fullCopies);
}
return fullCopiesMap;
}
/**
* Adds all source volumes' snapshots to the consistency group
*
* @return map of source volume to snapshots
*/
public Map<URI, List<URI>> addSourceVolumeSnapshots() {
List<URI> blockSnapshots = Lists.newArrayList();
Map<URI, List<URI>> snapshotsMap = new HashMap<>();
for (URI volumeId : uris(volumeIds)) {
List<URI> snapshots = getSnapshots(volumeId);
blockSnapshots.addAll(snapshots);
snapshotsMap.put(volumeId, snapshots);
}
if (!blockSnapshots.isEmpty()) {
BlockStorageUtils.addVolumesToConsistencyGroup(consistencyGroup, blockSnapshots);
}
return snapshotsMap;
}
/**
* Adds all target volumes' snapshots to the target consistency group
*
* @return map of target volume to snapshots
*/
public Map<URI, List<URI>> addTargetVolumeSnapshots() {
List<URI> blockSnapshots = Lists.newArrayList();
Map<URI, List<URI>> snapshotsMap = new HashMap<>();
URI targetCG = null;
for (URI volumeId : uris(volumeIds)) {
List<URI> targets = getTargets(volumeId);
for (URI target : targets) {
if (targetCG == null) {
targetCG = getConsistencyGroup(target);
}
List<URI> snapshots = getSnapshots(target);
blockSnapshots.addAll(snapshots);
snapshotsMap.put(target, snapshots);
}
}
if (!blockSnapshots.isEmpty() && targetCG != null) {
BlockStorageUtils.addVolumesToConsistencyGroup(targetCG, blockSnapshots);
}
return snapshotsMap;
}
/**
* Get consistency group id for a given block id
*
* @param blockId the block id
* @return consistency group URI or null if block volume doesn't belong to a consistency group
*/
public URI getConsistencyGroup(URI blockId) {
BlockObjectRestRep blockObject = BlockStorageUtils.getBlockResource(blockId);
return blockObject.getConsistencyGroup() != null ? blockObject.getConsistencyGroup().getId() : null;
}
}