/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package controllers.resources;
import static com.emc.sa.util.ResourceType.BLOCK_CONTINUOUS_COPY;
import static com.emc.sa.util.ResourceType.VOLUME;
import static com.emc.sa.util.ResourceType.VPLEX_CONTINUOUS_COPY;
import static com.emc.vipr.client.core.util.ResourceUtils.uri;
import static com.emc.vipr.client.core.util.ResourceUtils.uris;
import java.net.URI;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import models.datatable.BlockVolumesDataTable;
import org.apache.commons.lang.StringUtils;
import play.data.binding.As;
import play.i18n.Messages;
import play.mvc.Util;
import play.mvc.With;
import plugin.StorageOsPlugin;
import util.BlockConsistencyGroupUtils;
import util.BourneUtil;
import util.MessagesUtils;
import util.StorageSystemUtils;
import util.StringOption;
import util.VirtualArrayUtils;
import util.VirtualPoolUtils;
import util.datatable.DataTablesSupport;
import com.emc.sa.util.ResourceType;
import com.emc.storageos.coordinator.client.model.Constants;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.model.NamedRelatedResourceRep;
import com.emc.storageos.model.RelatedResourceRep;
import com.emc.storageos.model.block.BlockMirrorRestRep;
import com.emc.storageos.model.block.BlockSnapshotRestRep;
import com.emc.storageos.model.block.BlockSnapshotSessionRestRep;
import com.emc.storageos.model.block.CopiesParam;
import com.emc.storageos.model.block.Copy;
import com.emc.storageos.model.block.MigrationRestRep;
import com.emc.storageos.model.block.SnapshotSessionUnlinkTargetParam;
import com.emc.storageos.model.block.SnapshotSessionUnlinkTargetsParam;
import com.emc.storageos.model.block.VolumeDeleteTypeEnum;
import com.emc.storageos.model.block.VolumeRestRep;
import com.emc.storageos.model.block.export.ExportGroupRestRep;
import com.emc.storageos.model.block.export.ITLRestRep;
import com.emc.vipr.client.Task;
import com.emc.vipr.client.Tasks;
import com.emc.vipr.client.ViPRCoreClient;
import com.emc.vipr.client.exceptions.ViPRHttpException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import controllers.Common;
import controllers.util.FlashException;
@With(Common.class)
public class BlockVolumes extends ResourceController {
public static final String COPY_NATIVE = "native";
public static final String COPY_RP = "rp";
public static final String COPY_SRDF = "srdf";
public static final String APPLICATION = "Application";
public static final String PROJECT = "Project";
private static final String UNKNOWN = "resources.volumes.unknown";
private static final String NOTARGET = "resources.snapshot.session.targets.none";
private static BlockVolumesDataTable blockVolumesDataTable = new BlockVolumesDataTable();
private static Set<String> roles = new HashSet(Arrays.asList("COPY"));
public static final StringOption[] FILTER_OPTIONS = StringOption.options(new String[]{APPLICATION, PROJECT});
public static void volumes(String projectId) {
setActiveProjectId(projectId);
renderArgs.put("dataTable", blockVolumesDataTable);
renderArgs.put("filterOptions", FILTER_OPTIONS);
CoordinatorClient coordinatorClient = StorageOsPlugin.getInstance().getCoordinatorClient();
String limit = coordinatorClient.getPropertyInfo().getProperty(Constants.RESOURCE_LIMIT_PROJECT_VOLUMES);
renderArgs.put(Constants.RESOURCE_LIMIT_PROJECT_VOLUMES, limit);
addReferenceData();
render();
}
public static void volumesJson(String projectId, String applicationId) {
List<BlockVolumesDataTable.Volume> volumes = BlockVolumesDataTable.fetch(uri(projectId), uri(applicationId));
renderJSON(DataTablesSupport.createJSON(volumes, params));
}
public static void volumeDetails(String volumeId) {
ViPRCoreClient client = BourneUtil.getViprClient();
String consistencygroup = "";
VolumeRestRep volume = client.blockVolumes().get(uri(volumeId));
if (volume == null) {
error(MessagesUtils.get(UNKNOWN, volumeId));
}
if (volume.getConsistencyGroup() != null) {
consistencygroup = client.blockConsistencyGroups().get(volume.getConsistencyGroup().getId()).getName();
}
render(consistencygroup);
}
public static void volume(String volumeId, String continuousCopyId) {
ViPRCoreClient client = BourneUtil.getViprClient();
VolumeRestRep volume = null;
if (isVolumeId(volumeId)) {
if (isContinuousCopyId(continuousCopyId)) {
volume = client.blockVolumes().getContinuousCopy(uri(volumeId), uri(continuousCopyId));
renderArgs.put("isContinuousCopy", Boolean.TRUE);
renderArgs.put("isBlockContinuousCopy", isBlockContinuousCopyId(continuousCopyId));
renderArgs.put("isVplexContinuousCopy", isVplexContinuousCopyId(continuousCopyId));
} else {
try {
volume = client.blockVolumes().get(uri(volumeId));
} catch (ViPRHttpException e) {
if (e.getHttpCode() == 404) {
flash.error(MessagesUtils.get(UNKNOWN, volumeId));
volumes(null);
}
throw e;
}
}
}
if (volume == null) {
notFound(Messages.get("resources.volume.notfound"));
}
if (volume.getVirtualArray() != null) { // NOSONAR
// ("Suppressing Sonar violation of Possible null pointer dereference of volume. When volume is null, the previous if condition handles with throw")
renderArgs.put("virtualArray", VirtualArrayUtils.getVirtualArrayRef(volume.getVirtualArray()));
}
if (volume.getVirtualPool() != null) {
renderArgs.put("virtualPool", VirtualPoolUtils.getBlockVirtualPoolRef(volume.getVirtualPool()));
}
if (volume.getConsistencyGroup() != null) {
renderArgs.put("consistencyGroup",
BlockConsistencyGroupUtils.getBlockConsistencyGroupRef(volume.getConsistencyGroup()));
}
if (volume.getStorageController() != null) {
renderArgs.put("storageSystem", StorageSystemUtils.getStorageSystemRef(volume.getStorageController()));
}
if (volume.getCompressionRatio() != null) {
renderArgs.put("compressionRatio", volume.getCompressionRatio());
}
if (volume.getAccessState() == null || volume.getAccessState().isEmpty()) {
renderArgs.put("isAccessStateEmpty", "true");
}
Tasks<VolumeRestRep> tasksResponse = client.blockVolumes().getTasks(volume.getId());
List<Task<VolumeRestRep>> tasks = tasksResponse.getTasks();
renderArgs.put("tasks", tasks);
render(volume);
}
public static void volumeExports(String volumeId) {
ViPRCoreClient client = BourneUtil.getViprClient();
Map<URI, ExportGroupRestRep> exportGroups = Maps.newHashMap();
Map<URI, List<ITLRestRep>> exportGroupItlMap = Maps.newHashMap();
List<ITLRestRep> itls = Lists.newArrayList();
VolumeRestRep volume = client.blockVolumes().get(uri(volumeId));
if (volume != null && volume.getInactive() == false) {
itls = client.blockVolumes().getExports(uri(volumeId));
for (ITLRestRep itl : itls) {
NamedRelatedResourceRep export = itl.getExport();
if (export != null && export.getId() != null) {
List<ITLRestRep> exportGroupItls = exportGroupItlMap.get(export.getId());
if (exportGroupItls == null) {
exportGroupItls = Lists.newArrayList();
exportGroupItlMap.put(export.getId(), exportGroupItls);
}
exportGroupItls.add(itl);
if (exportGroups.keySet().contains(export.getId()) == false) {
ExportGroupRestRep exportGroup = client.blockExports().get(export.getId());
exportGroups.put(exportGroup.getId(), exportGroup);
}
}
}
}
// Remove 'internal' marked export groups, we don't want to show these in the exports list
Set<URI> internalExportGroups = Sets.newHashSet();
for (ExportGroupRestRep exportGroup : exportGroups.values()) {
if (Boolean.TRUE.equals(exportGroup.getInternal())) {
internalExportGroups.add(exportGroup.getId());
}
}
// Remove internal export groups
exportGroups.keySet().removeAll(internalExportGroups);
// Remove initiators from interal export groups
exportGroupItlMap.keySet().removeAll(internalExportGroups);
render(itls, exportGroups, exportGroupItlMap);
}
public static void volumeSnapshots(String volumeId) {
ViPRCoreClient client = BourneUtil.getViprClient();
List<NamedRelatedResourceRep> refs = client.blockSnapshots().listByVolume(uri(volumeId));
List<BlockSnapshotRestRep> snapshots = client.blockSnapshots().getByRefs(refs);
render(snapshots);
}
public static void volumeSnapshotSessions(String volumeId) {
ViPRCoreClient client = BourneUtil.getViprClient();
VolumeRestRep volume = client.blockVolumes().get(uri(volumeId));
List<BlockSnapshotSessionRestRep> snapshotSessions = Lists.newArrayList();
if (volume.getConsistencyGroup() != null) {
URI consistencygroup = volume.getConsistencyGroup().getId();
List<NamedRelatedResourceRep> cgSessions = client.blockConsistencyGroups().getSnapshotSessions(consistencygroup);
snapshotSessions = client.blockSnapshotSessions().getByRefs(cgSessions);
} else {
List<NamedRelatedResourceRep> refs = client.blockSnapshotSessions().listByVolume(uri(volumeId));
snapshotSessions = client.blockSnapshotSessions().getByRefs(refs);
}
render(snapshotSessions, volumeId);
}
public static void unlinkTargetSnapshot(String sessionId, String volumeId, Boolean deleteOption) {
ViPRCoreClient client = BourneUtil.getViprClient();
SnapshotSessionUnlinkTargetsParam sessionTargets = new SnapshotSessionUnlinkTargetsParam();
List<SnapshotSessionUnlinkTargetParam> targetLists = Lists.newArrayList();
List<RelatedResourceRep> targets = client.blockSnapshotSessions().get(uri(sessionId)).getLinkedTarget();
List<BlockSnapshotRestRep> snapshots = client.blockSnapshots().getByRefs(targets);
for (BlockSnapshotRestRep snap : snapshots) {
SnapshotSessionUnlinkTargetParam targetList = new SnapshotSessionUnlinkTargetParam();
targetList.setId(snap.getId());
targetList.setDeleteTarget(deleteOption);
targetLists.add(targetList);
}
if (!targetLists.isEmpty()) {
sessionTargets.setLinkedTargets(targetLists);
Task<BlockSnapshotSessionRestRep> tasks = client.blockSnapshotSessions().unlinkTargets(uri(sessionId), sessionTargets);
flash.put("info", MessagesUtils.get("resources.snapshot.session.unlink.success", sessionId));
}
else {
flash.error(MessagesUtils.get(NOTARGET, sessionId));
}
volume(volumeId, null);
}
public static void volumeContinuousCopies(String volumeId) {
ViPRCoreClient client = BourneUtil.getViprClient();
List<BlockMirrorRestRep> continuousCopies = client.blockVolumes().getContinuousCopies(uri(volumeId));
render(continuousCopies);
}
public static void volumeFullCopies(String volumeId) {
ViPRCoreClient client = BourneUtil.getViprClient();
List<NamedRelatedResourceRep> refs = client.blockVolumes().listFullCopies(uri(volumeId));
List<VolumeRestRep> fullCopies = client.blockVolumes().getByRefs(refs);
render(fullCopies);
}
public static void volumeMigrations(String volumeId) {
ViPRCoreClient client = BourneUtil.getViprClient();
List<NamedRelatedResourceRep> migrationsRep = client.blockVolumes().listMigrations(uri(volumeId));
List<MigrationRestRep> migrations = client.blockMigrations().getByRefs(migrationsRep);
render(migrations);
}
@FlashException("volumes")
public static void delete(@As(",") String[] ids, VolumeDeleteTypeEnum type) {
delete(uris(ids), type);
}
@FlashException(referrer = { "volume" })
public static void deleteVolume(String volumeId, VolumeDeleteTypeEnum type) {
if (StringUtils.isNotBlank(volumeId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
Task<VolumeRestRep> task = client.blockVolumes().deactivate(uri(volumeId), type);
flash.put("info", MessagesUtils.get("resources.volume.deactivate"));
}
volume(volumeId, null);
}
@FlashException(referrer = { "volume" })
public static void pauseContinuousCopy(String volumeId, String continuousCopyId) {
if (StringUtils.isNotBlank(volumeId) && StringUtils.isNotBlank(continuousCopyId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
CopiesParam input = createCopiesParam(continuousCopyId);
Tasks<VolumeRestRep> tasks = client.blockVolumes().pauseContinuousCopies(uri(volumeId), input);
flash.put("info", MessagesUtils.get("resources.continuouscopy.pause"));
}
volume(volumeId, null);
}
@FlashException(referrer = { "volume" })
public static void resumeContinuousCopy(String volumeId, String continuousCopyId) {
if (StringUtils.isNotBlank(volumeId) && StringUtils.isNotBlank(continuousCopyId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
CopiesParam input = createCopiesParam(continuousCopyId);
Tasks<VolumeRestRep> tasks = client.blockVolumes().resumeContinuousCopies(uri(volumeId), input);
flash.put("info", MessagesUtils.get("resources.continuouscopy.resume"));
}
volume(volumeId, null);
}
@FlashException(referrer = { "volume" })
public static void stopContinuousCopy(String volumeId, String continuousCopyId) {
if (StringUtils.isNotBlank(volumeId) && StringUtils.isNotBlank(continuousCopyId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
CopiesParam input = createCopiesParam(continuousCopyId);
Tasks<VolumeRestRep> tasks = client.blockVolumes().stopContinuousCopies(uri(volumeId), input);
flash.put("info", MessagesUtils.get("resources.continuouscopy.stop"));
}
volume(volumeId, null);
}
@FlashException(referrer = { "volume" })
public static void deleteContinuousCopy(String volumeId, String continuousCopyId) {
if (StringUtils.isNotBlank(volumeId) && StringUtils.isNotBlank(continuousCopyId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
CopiesParam input = createCopiesParam(continuousCopyId);
Tasks<VolumeRestRep> tasks = client.blockVolumes().deactivateContinuousCopies(uri(volumeId), input, VolumeDeleteTypeEnum.FULL);
flash.put("info", MessagesUtils.get("resources.continuouscopy.deactivate"));
}
volume(volumeId, continuousCopyId);
}
@FlashException(referrer = { "volume" })
public static void pauseMigration(String volumeId, String migrationId) {
if (StringUtils.isNotBlank(volumeId) && StringUtils.isNotBlank(migrationId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
client.blockMigrations().pause(uri(migrationId));
flash.put("info", MessagesUtils.get("resources.migrations.pause"));
}
volume(volumeId, null);
}
@FlashException(referrer = { "volume" })
public static void cancelMigration(String volumeId, String migrationId) {
if (StringUtils.isNotBlank(volumeId) && StringUtils.isNotBlank(migrationId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
client.blockMigrations().cancel(uri(migrationId));
flash.put("info", MessagesUtils.get("resources.migrations.cancel"));
}
volume(volumeId, null);
}
@FlashException(referrer = { "volume" })
public static void resumeMigration(String volumeId, String migrationId) {
if (StringUtils.isNotBlank(volumeId) && StringUtils.isNotBlank(migrationId)) {
ViPRCoreClient client = BourneUtil.getViprClient();
client.blockMigrations().resume(uri(migrationId));
flash.put("info", MessagesUtils.get("resources.migrations.resume"));
}
volume(volumeId, null);
}
@Util
private static CopiesParam createCopiesParam(String continuousCopyId) {
Copy copy = new Copy();
copy.setType(COPY_NATIVE);
copy.setCopyID(uri(continuousCopyId));
List<Copy> copies = Lists.newArrayList();
copies.add(copy);
CopiesParam input = new CopiesParam(copies);
return input;
}
private static void delete(List<URI> ids, VolumeDeleteTypeEnum type) {
if (ids != null) {
ViPRCoreClient client = BourneUtil.getViprClient();
Tasks<VolumeRestRep> tasks = client.blockVolumes().deactivate(ids, type);
flash.put("info", MessagesUtils.get("resources.volumes.deactivate", tasks.getTasks().size()));
}
volumes(null);
}
@Util
private static boolean isVolumeId(String id) {
return ResourceType.isType(VOLUME, id);
}
@Util
private static boolean isContinuousCopyId(String id) {
return isBlockContinuousCopyId(id) || isVplexContinuousCopyId(id);
}
@Util
private static boolean isVplexContinuousCopyId(String id) {
return ResourceType.isType(VPLEX_CONTINUOUS_COPY, id);
}
@Util
private static boolean isBlockContinuousCopyId(String id) {
return ResourceType.isType(BLOCK_CONTINUOUS_COPY, id);
}
}