/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller;
import java.net.URI;
import java.util.List;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.ProtectionSystem;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.VirtualArray;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.VirtualPool.MetroPointType;
import com.emc.storageos.db.client.util.SizeUtil;
/*
* Represents recommendation for an RP protected volume.
*/
@SuppressWarnings("serial")
public class RPRecommendation extends Recommendation {
public static enum ProtectionType {
REMOTE,
LOCAL
}
private VPlexRecommendation virtualVolumeRecommendation;
private RPRecommendation haRecommendation;
private List<RPRecommendation> targetRecommendations;
private String internalSiteName;
// This is needed for MetroPoint. The concatenated string containing
// both the RP internal site name + associated storage system.
private String rpSiteAssociateStorageSystem;
// This is the Storage System that was chosen by placement for connectivity/visibility to the RP Cluster
private URI internalSiteStorageSystem;
private ProtectionType protectionType;
//Size in Bytes of each resource
private Long size;
private String rpCopyName;
public VPlexRecommendation getVirtualVolumeRecommendation() {
return virtualVolumeRecommendation;
}
public void setVirtualVolumeRecommendation(
VPlexRecommendation virtualVolumeRecommendation) {
this.virtualVolumeRecommendation = virtualVolumeRecommendation;
}
public RPRecommendation getHaRecommendation() {
return haRecommendation;
}
public void setHaRecommendation(RPRecommendation haRecommendation) {
this.haRecommendation = haRecommendation;
}
public List<RPRecommendation> getTargetRecommendations() {
return targetRecommendations;
}
public void setTargetRecommendations(List<RPRecommendation> targetRecommendations) {
this.targetRecommendations = targetRecommendations;
}
public String getInternalSiteName() {
return internalSiteName;
}
public void setInternalSiteName(String sourceInternalSiteName) {
this.internalSiteName = sourceInternalSiteName;
}
public String getRpSiteAssociateStorageSystem() {
return rpSiteAssociateStorageSystem;
}
public void setRpSiteAssociateStorageSystem(
String rpSiteAssociateStorageSystem) {
this.rpSiteAssociateStorageSystem = rpSiteAssociateStorageSystem;
}
public URI getInternalSiteStorageSystem() {
return internalSiteStorageSystem;
}
public void setInternalSiteStorageSystem(
URI sourceInternalSiteStorageSystem) {
this.internalSiteStorageSystem = sourceInternalSiteStorageSystem;
}
public ProtectionType getProtectionType() {
return protectionType;
}
public void setProtectionType(ProtectionType protectionType) {
this.protectionType = protectionType;
}
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
public String getRpCopyName() {
return rpCopyName;
}
public void setRpCopyName(String rpCopyName) {
this.rpCopyName = rpCopyName;
}
/**
* Returns true of the specified internal site is already part of this recommendation.
*
* @param destInternalSiteName
* @return true if the internal site is found for a target recommendation
*/
public boolean containsTargetInternalSiteName(String destInternalSiteName) {
if (this.getTargetRecommendations() != null) {
for (RPRecommendation targetRec : this.getTargetRecommendations()) {
if (targetRec.getInternalSiteName().equals(destInternalSiteName)) {
return true;
}
}
}
return false;
}
/**
* Gets the MetroPoint configuration type for the recommendation. Looks specifically
* at the protection copy types to figure out the configuration. If any of the
* protection copy types is not set, we cannot properly determine the configuration
* so we must return null;
*
* @return the MetroPoint configuration type
*/
public MetroPointType getMetroPointType() {
MetroPointType metroPointType = null;
int primaryLocalCopyCount = 0;
int primaryRemoteCopyCount = 0;
int secondaryLocalCopyCount = 0;
int secondaryRemoteCopyCount = 0;
List<RPRecommendation> targetRecs = this.getTargetRecommendations();
// Return invalid configuration if there is no primary protection specified.
if (targetRecs == null || targetRecs.isEmpty()) {
return MetroPointType.INVALID;
}
for (RPRecommendation targetRec : targetRecs) {
if (targetRec.getProtectionType() == null) {
// If even one protection type is missing, this is not a valid MetroPoint
// recommendation. The protection type is only ever set in
// MetroPoint specific code.
return MetroPointType.INVALID;
}
if (targetRec.getProtectionType() == ProtectionType.LOCAL) {
primaryLocalCopyCount++;
} else if (targetRec.getProtectionType() == ProtectionType.REMOTE) {
primaryRemoteCopyCount++;
}
}
RPRecommendation secondaryRecommendation = null;
if (this.getHaRecommendation() != null ) {
// There will only ever be 1 secondary recommendation in a MetroPoint case.
secondaryRecommendation =
this.getHaRecommendation();
} else {
// There must be a secondary recommendation to satisfy a valid MetroPoint
// configuration.
return MetroPointType.INVALID;
}
// Return invalid configuration if there is no secondary protection specified.
if (secondaryRecommendation.getTargetRecommendations().isEmpty()) {
return MetroPointType.INVALID;
}
for (RPRecommendation secondaryTargetRec : secondaryRecommendation.getTargetRecommendations()) {
if (secondaryTargetRec.getProtectionType() == null) {
// If even one protection type is missing, this is not a valid MetroPoint
// recommendation. The protection type is only ever set in
// MetroPoint specific code.
return MetroPointType.INVALID;
}
if (secondaryTargetRec.getProtectionType() == ProtectionType.LOCAL) {
secondaryLocalCopyCount++;
} else if (secondaryTargetRec.getProtectionType() == ProtectionType.REMOTE) {
secondaryRemoteCopyCount++;
}
}
boolean singleRemoteCopy = false;
boolean primaryLocalCopy = false;
boolean secondaryLocalCopy = false;
if (primaryRemoteCopyCount == 1 && secondaryRemoteCopyCount == 1) {
singleRemoteCopy = true;
}
if (primaryLocalCopyCount == 1) {
primaryLocalCopy = true;
}
if (secondaryLocalCopyCount == 1) {
secondaryLocalCopy = true;
}
metroPointType = MetroPointType.INVALID;
if (singleRemoteCopy && primaryLocalCopy && secondaryLocalCopy) {
metroPointType = MetroPointType.TWO_LOCAL_REMOTE;
} else if (singleRemoteCopy &&
((!primaryLocalCopy && secondaryLocalCopy) || (primaryLocalCopy && !secondaryLocalCopy))) {
metroPointType = MetroPointType.ONE_LOCAL_REMOTE;
} else if (singleRemoteCopy && !primaryLocalCopy && !secondaryLocalCopy) {
metroPointType = MetroPointType.SINGLE_REMOTE;
} else if (!singleRemoteCopy && primaryLocalCopy && secondaryLocalCopy) {
metroPointType = MetroPointType.LOCAL_ONLY;
}
return metroPointType;
}
/**
* Print the recommendation
*
* @param dbClient DBClient reference
* @param ps The protection system in question
* @param noOfTabs Number of tabs to use
* @return Recommendation string output
*/
public String toString(DbClient dbClient, ProtectionSystem ps, int... noOfTabs) {
StringBuffer buff = new StringBuffer();
final String TAB = "\t";
String printTabs = TAB;
if (noOfTabs.length > 0 && noOfTabs[0] > 0) {
for (int i = 0; i < noOfTabs[0]; i++) {
printTabs += TAB;
}
}
VirtualArray varray = dbClient.queryObject(VirtualArray.class, getVirtualArray());
VirtualPool vpool = getVirtualPool();
StoragePool storagePool = dbClient.queryObject(StoragePool.class, getSourceStoragePool());
StorageSystem storageSystem = dbClient.queryObject(StorageSystem.class, getSourceStorageSystem());
buff.append(String.format("%n"));
buff.append(printTabs + String.format("Resource Count \t\t: %s %n", this.getResourceCount()));
String siteName = ((ps.getRpSiteNames() != null) ? ps.getRpSiteNames().get(this.getInternalSiteName()) : "");
String siteId = this.getInternalSiteName();
if (this.getInternalSiteName() == null) {
siteName = "(no RP protection specified)";
siteId = "";
}
buff.append(printTabs + String.format("Internal Site \t\t: %s %s %n", siteName, siteId));
buff.append(printTabs + String.format("RP Copy Name \t\t: %s %n",
(this.getRpCopyName() == null ? "Not determined yet" : this.getRpCopyName())));
buff.append(printTabs + String.format("Virtual Array \t\t: %s %n", varray.getLabel()));
buff.append(printTabs + String.format("Virtual Pool \t\t: %s %n", vpool.getLabel()));
if (virtualVolumeRecommendation != null && virtualVolumeRecommendation.getVPlexStorageSystem() != null) {
StorageSystem vplexStorageSystem = dbClient.queryObject(StorageSystem.class,
virtualVolumeRecommendation.getVPlexStorageSystem());
buff.append(printTabs + String.format("VPLEX Storage \t\t: %s %n", vplexStorageSystem.getLabel()));
}
buff.append(printTabs + String.format("Storage Pool \t\t: %s %n", storagePool.getLabel()));
buff.append(printTabs + String.format("Storage System \t\t: %s %n", storageSystem.getLabel()));
buff.append(printTabs + String.format("Resource Size \t\t: %s GB %n", SizeUtil.translateSize(this.getSize(), SizeUtil.SIZE_GB)));
buff.append(String.format("----------------------%n"));
if (this.getHaRecommendation() != null) {
buff.append(printTabs + String.format("High Availability Recommendation : %n"));
buff.append(getHaRecommendation().toString(dbClient, ps, 1));
if (this.getHaRecommendation().getTargetRecommendations() != null &&
!this.getHaRecommendation().getTargetRecommendations().isEmpty()){
buff.append(printTabs + String.format("High Availability Target : %n"));
for(RPRecommendation haTargetRec : this.getHaRecommendation().getTargetRecommendations()) {
buff.append(String.format("%s", haTargetRec.toString(dbClient, ps, 1)));
}
}
}
return buff.toString();
}
}