/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.recoverpoint.utils; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.fapiclient.ws.AccountState; import com.emc.fapiclient.ws.ClusterConfiguration; import com.emc.fapiclient.ws.ClusterSANVolumes; import com.emc.fapiclient.ws.ClusterSplittersSettings; import com.emc.fapiclient.ws.ClusterUID; import com.emc.fapiclient.ws.ConnectionOutThroughput; import com.emc.fapiclient.ws.ConsistencyGroupCopySettings; import com.emc.fapiclient.ws.ConsistencyGroupCopyState; import com.emc.fapiclient.ws.ConsistencyGroupCopyUID; import com.emc.fapiclient.ws.ConsistencyGroupSettings; import com.emc.fapiclient.ws.ConsistencyGroupState; import com.emc.fapiclient.ws.ConsistencyGroupUID; import com.emc.fapiclient.ws.DeviceUID; import com.emc.fapiclient.ws.FullRecoverPointSettings; import com.emc.fapiclient.ws.FunctionalAPIActionFailedException_Exception; import com.emc.fapiclient.ws.FunctionalAPIImpl; import com.emc.fapiclient.ws.FunctionalAPIInternalError_Exception; import com.emc.fapiclient.ws.FunctionalAPIValidationException_Exception; import com.emc.fapiclient.ws.GlobalCopyUID; import com.emc.fapiclient.ws.InOutThroughputStatistics; import com.emc.fapiclient.ws.LicenseState; import com.emc.fapiclient.ws.LicenseStatus; import com.emc.fapiclient.ws.ReplicationSetSettings; import com.emc.fapiclient.ws.RpaStatistics; import com.emc.fapiclient.ws.RpaUID; import com.emc.fapiclient.ws.SetVolumeParam; import com.emc.fapiclient.ws.SplitterSettings; import com.emc.fapiclient.ws.SplitterUID; import com.emc.fapiclient.ws.SystemStatistics; import com.emc.fapiclient.ws.TrafficStatistics; import com.emc.fapiclient.ws.UserVolumeSettings; import com.emc.fapiclient.ws.VolumeInformation; import com.emc.storageos.recoverpoint.exceptions.RecoverPointException; import com.emc.storageos.recoverpoint.impl.RecoverPointClient; import com.emc.storageos.recoverpoint.objectmodel.RPSite; import com.emc.storageos.recoverpoint.requests.CreateCopyParams; import com.emc.storageos.recoverpoint.responses.RecoverPointVolumeProtectionInfo; public class RecoverPointUtils { private static Logger logger = LoggerFactory.getLogger(RecoverPointClient.class); /** * @param buffer * @param useSeparator * @return String - GUID representation in a string format. */ public static String getGuidBufferAsString(List<Byte> buffer, boolean useSeparator) { StringBuffer sb = new StringBuffer(); boolean isFirst = true; Iterator<Byte> itr = buffer.iterator(); while (itr.hasNext()) { if (useSeparator) { if (isFirst) { isFirst = false; } else { sb.append(','); } } int i = itr.next().intValue(); if (i < 0) { i += 256; // byte is signed, u8 isn't. } sb.append(getHex(i)); } return sb.toString(); } public static String getHex(int i) { String res = Integer.toHexString(i); return res.length() > 1 ? res : "0" + res; } /** * @param impl - RP handle to use for RP operations * @param cgUID - Consistency Group UID * @param localCopyUID * @param remoteCopiesUID * @throws FunctionalAPIActionFailedException_Exception * @throws FunctionalAPIInternalError_Exception * @throws RecoverPointException * @throws FunctionalAPIValidationException_Exception */ public static void enableNewConsistencyGroup(FunctionalAPIImpl impl, ConsistencyGroupUID cgUID, List<ConsistencyGroupCopyUID> localCopiesUID, List<ConsistencyGroupCopyUID> remoteCopiesUID) throws FunctionalAPIActionFailedException_Exception, FunctionalAPIInternalError_Exception, RecoverPointException, FunctionalAPIValidationException_Exception { logger.info("Start enableNewConsistencyGroup..."); if (remoteCopiesUID != null && !remoteCopiesUID.isEmpty()) { for (ConsistencyGroupCopyUID remoteCopyUID : remoteCopiesUID) { try { logger.info("Validate Remote copy..."); // CG validation warnings will be caught, logged, and // processing will continue impl.validateEnableConsistencyGroupCopy(remoteCopyUID, true); } catch (FunctionalAPIValidationException_Exception e) { logger.warn(e.getMessage(), e); } } } if (localCopiesUID != null && !localCopiesUID.isEmpty()) { for (ConsistencyGroupCopyUID localCopyUID : localCopiesUID) { try { logger.info("Validate Local copy..."); // CG validation warnings will be caught, logged, and // processing will continue impl.validateEnableConsistencyGroupCopy(localCopyUID, true); } catch (FunctionalAPIValidationException_Exception e) { logger.warn(e.getMessage(), e); } } } // Last thing to do is enable the CG logger.info("Enable Consistency Group and all copies"); try { // CG validation warnings will be caught, logged, and // processing will continue impl.validateEnableConsistencyGroup(cgUID, true); } catch (FunctionalAPIValidationException_Exception e) { logger.warn(e.getMessage(), e); } impl.enableConsistencyGroup(cgUID, true); // Make sure the CG is ready RecoverPointImageManagementUtils imageManager = new RecoverPointImageManagementUtils(); imageManager.waitForCGLinkState(impl, cgUID, RecoverPointImageManagementUtils.getPipeActiveState(impl, cgUID)); logger.info("End enableNewConsistencyGroup."); } /** * Validates that the production and/or local/remote copies are not null * * @param prodCopy * @param localCopy * @param remoteCopies * @throws RecoverPointException */ public static void validateCopiesNotNull(List<CreateCopyParams> prodCopies, List<CreateCopyParams> localCopies, List<CreateCopyParams> remoteCopies) throws RecoverPointException { if (prodCopies == null) { throw RecoverPointException.exceptions.didNotFindProductionCopyWWNs(); } if (localCopies == null && remoteCopies == null) { throw RecoverPointException.exceptions.didNotFindLocalRemoteCopyWWNs(); } } /** * Removes a consistency group * * @param impl - RP handle to use for RP operations * @param cgUID - UID of the consistency group which needs to be removed. * @throws RecoverPointException */ public static void cleanupCG(FunctionalAPIImpl impl, ConsistencyGroupUID cgUID) throws RecoverPointException { if (impl != null && cgUID != null) { try { impl.removeConsistencyGroup(cgUID); } catch (FunctionalAPIActionFailedException_Exception e1) { throw RecoverPointException.exceptions.cannotCleanupCG(e1); } catch (FunctionalAPIInternalError_Exception e1) { throw RecoverPointException.exceptions.cannotCleanupCG(e1); } } } /** * @param WWN * @param useSeparator * @return - WWN as string */ public static String getWWNAsString(long WWN, boolean useSeparator) { String hexString = Long.toHexString(WWN); if (useSeparator) { String formattedWWN = new String(); for (int i = 0; i < hexString.length(); i += 2) { formattedWWN += hexString.substring(i, i + 2); if (i < hexString.length() - 2) { formattedWWN += ":"; } } return formattedWWN; } return hexString; } /** * verify that the volumes in a consistency group are connected to a splitter * * @param impl - handle for FAPI * @param groupUID - consistency group to examine volumes on * @throws - RecoverPointException */ public static void verifyCGVolumesAttachedToSplitter(FunctionalAPIImpl impl, ConsistencyGroupUID groupUID) throws RecoverPointException { ConsistencyGroupSettings groupSettings; try { groupSettings = impl.getGroupSettings(groupUID); // Get the consistency group settings for (ReplicationSetSettings replicationSet : groupSettings.getReplicationSetsSettings()) { // Run over all replication sets for (UserVolumeSettings userVolume : replicationSet.getVolumes()) { logger.info("Volume : " + RecoverPointUtils.getGuidBufferAsString(userVolume.getVolumeInfo().getRawUids(), false) + " is of type " + userVolume.getVolumeType()); if (userVolume.getAttachedSplitters().isEmpty()) { String volumeWWN = RecoverPointUtils.getGuidBufferAsString(userVolume.getVolumeInfo().getRawUids(), false); logger.warn("Volume " + volumeWWN + " is not attached to any splitters"); Set<SplitterUID> splittersToAttachTo = getSplittersToAttachToForVolume(impl, userVolume.getClusterUID(), userVolume .getVolumeInfo().getVolumeID()); for (SplitterUID splitterUID : splittersToAttachTo) { SetVolumeParam volumeParam = new SetVolumeParam(); volumeParam.setShouldAttachAsClean(false); volumeParam.setVolumeID(userVolume.getVolumeInfo().getVolumeID()); logger.info("Attaching volume " + volumeWWN + " to splitter" + impl.getSplitterName(splitterUID)); impl.attachVolumeToSplitter(splitterUID, volumeParam); } } else { for (SplitterUID splitterUID : userVolume.getAttachedSplitters()) { logger.info("Volume " + RecoverPointUtils.getGuidBufferAsString(userVolume.getVolumeInfo().getRawUids(), false) + " is attached to splitter " + impl.getSplitterName(splitterUID)); } } } } } catch (FunctionalAPIActionFailedException_Exception e) { logger.error(e.getMessage(), e); throw RecoverPointException.exceptions.exceptionGettingSettingsCG(e); } catch (FunctionalAPIInternalError_Exception e) { logger.error(e.getMessage(), e); throw RecoverPointException.exceptions.exceptionGettingSettingsCG(e); } } /** * Get all of the arrays associated with a cluster * * @param impl endpoint interface * @param clusterUID cluster ID * @return set of storage systems * @throws RecoverPointException */ public static Set<String> getArraysForCluster(FunctionalAPIImpl impl, ClusterUID clusterUID) throws RecoverPointException { Set<String> returnArrays = new HashSet<>(); try { logger.info("Finding arrays associated with RP cluster: " + clusterUID.getId()); // Get the arrays that are configured as splitters. ClusterSplittersSettings splitterSettings = impl.getSplittersSettingsFromCluster(clusterUID); if (splitterSettings != null && splitterSettings.getSplittersSettings() != null) { for (SplitterSettings splitterSetting : splitterSettings.getSplittersSettings()) { // The splitter name will arrive as: // VPLEX: FNM0123456789 // VNX: APM0123467890-A // VMAX: SYMM-01947656483 // In all cases, we need to distill that into a serial number. // // NOTE: What would be ideal is to take the SplitterSetting.getArrayID() and get back // native array information. I could not find that method, so I had to resort to // this for now. It does work, but it's not ideal. WJEIV Pattern myPattern = Pattern.compile("[A-Z,a-z,0-9]*"); Matcher m = myPattern.matcher(splitterSetting.getSplitterName()); while (m.find()) { String s = m.group(0); // VMAX is a special case; they put SYMM- at the beginning. // We get around this by finding the third group in the pattern. if (s.equals("SYMM")) { // Iterate to the "-" m.find(); // Iterate to the serial number m.find(); s = m.group(0); } returnArrays.add(s); logger.info("Found array name: " + s); break; } } } return returnArrays; } catch (FunctionalAPIActionFailedException_Exception e) { logger.error(e.getMessage(), e); throw RecoverPointException.exceptions.exceptionGettingArrays(e); } catch (FunctionalAPIInternalError_Exception e) { logger.error(e.getMessage(), e); throw RecoverPointException.exceptions.exceptionGettingArrays(e); } } /** * Finds the splitter(s) to attach a volume to (if any need to be attached). * * @param impl - handle for FAPI * @param ClusterUID - site for the volume * @param volume - volume ID we are looking for * @return - Set<SplitterUID> */ private static Set<SplitterUID> getSplittersToAttachToForVolume(FunctionalAPIImpl impl, ClusterUID ClusterUID, DeviceUID volume) throws RecoverPointException { Set<SplitterUID> returnSplitters = new HashSet<SplitterUID>(); try { logger.info("Finding splitters with unattached volumes"); List<SplitterUID> splittersWithUnattachedVols = impl.getAvailableSplittersToAttachToVolume(ClusterUID, volume); for (SplitterUID splitterUID : splittersWithUnattachedVols) { SplitterSettings splitterSettings = impl.getSplitterSettings(splitterUID); List<DeviceUID> unattachedVolumes = impl.getAvailableVolumesToAttachToSplitter(splitterUID, true); if (!unattachedVolumes.isEmpty()) { for (DeviceUID unattachedVolume : unattachedVolumes) { if (unattachedVolume.getId() == volume.getId()) { returnSplitters.add(splitterSettings.getSplitterUID()); } } } } return returnSplitters; } catch (FunctionalAPIActionFailedException_Exception e) { logger.error(e.getMessage(), e); throw RecoverPointException.exceptions.exceptionGettingSplittersVolume(e); } catch (FunctionalAPIInternalError_Exception e) { logger.error(e.getMessage(), e); throw RecoverPointException.exceptions.exceptionGettingSplittersVolume(e); } } /** * Convenience method that determines if 2 CG copies are equal. The cluster and copy UIDs * for each copy must be equal in order for the copies to be equal. * * @param firstCopy the first copy in the comparison * @param secondCopy the second copy in the comparison. * @return true if the copies are equals, false otherwise. */ public static boolean copiesEqual(ConsistencyGroupCopyUID firstCopy, ConsistencyGroupCopyUID secondCopy) { if (firstCopy != null && secondCopy != null) { GlobalCopyUID firstCopyGlobalCopyUID = firstCopy.getGlobalCopyUID(); GlobalCopyUID secondCopyGlobalCopyUID = secondCopy.getGlobalCopyUID(); return copiesEqual(firstCopyGlobalCopyUID, secondCopyGlobalCopyUID); } return false; } /** * Convenience method that determines if 2 CG copies are equal. The cluster and copy UIDs * for each copy must be equal in order for the copies to be equal. * * @param firstCopy the first copy in the comparison * @param secondCopy the second copy in the comparison. * @return true if the copy UIDs are the same */ public static boolean copiesEqual(GlobalCopyUID firstCopy, GlobalCopyUID secondCopy) { if (firstCopy != null && secondCopy != null) { ClusterUID firstCopyClusterUID = firstCopy.getClusterUID(); ClusterUID secondCopyClusterUID = secondCopy.getClusterUID(); if (firstCopyClusterUID != null && secondCopyClusterUID != null && firstCopyClusterUID.getId() == secondCopyClusterUID.getId() && firstCopy.getCopyUID() == secondCopy.getCopyUID()) { return true; } } return false; } /** * Determines if a list of CG copy UIDs contains the specified copy UID. * * @param cgCopyUIDs the list of CG copy UIDs * @param cgCopyUID the search CG copy UID * @return true if the copy UID is found in the list, false otherwise. */ public static boolean containsCopy(List<ConsistencyGroupCopyUID> cgCopyUIDs, ConsistencyGroupCopyUID cgCopyUID) { for (ConsistencyGroupCopyUID currentCopyUID : cgCopyUIDs) { if (copiesEqual(cgCopyUID, currentCopyUID)) { return true; } } return false; } /** * Determine if the CG passed in is a production copy. In the case of metropoint, there are more than one production copy, active and * stand-by, * and they have different CG Copy UID. * * @param copyUID * @param productionCopiesUIDs * @return */ public static boolean isProductionCopy(ConsistencyGroupCopyUID copyUID, List<ConsistencyGroupCopyUID> productionCopiesUIDs) { // check if the passed in cgCopyUID is in the list of production copies UID for (ConsistencyGroupCopyUID productionCopyUID : productionCopiesUIDs) { if ((productionCopyUID.getGroupUID().getId() == copyUID.getGroupUID().getId()) && (productionCopyUID.getGlobalCopyUID().getCopyUID() == copyUID.getGlobalCopyUID().getCopyUID()) && (productionCopyUID.getGlobalCopyUID().getClusterUID().getId() == copyUID.getGlobalCopyUID().getClusterUID().getId())) { return true; } } return false; } /** * Determines if a consistency group copy is the standby production copy. * * @param copyUID the consistency group copy to check. * @param state the consistency group state. * @param productionCopiesUIDs the list of production copies in the consistency group. * @return true if the copy is a standby production copy, false otherwise. */ public static boolean isStandbyProductionCopy(ConsistencyGroupCopyUID copyUID, ConsistencyGroupState state, List<ConsistencyGroupCopyUID> productionCopiesUIDs) { if (RecoverPointUtils.isProductionCopy(copyUID, productionCopiesUIDs)) { for (ConsistencyGroupCopyState copyState : state.getGroupCopiesStates()) { // If the state of this production copy is not active, it is the standby production copy if (copiesEqual(copyUID, copyState.getCopyUID()) && !copyState.isActive()) { return true; } } } return false; } /** * Gets the standby production copy if one exists. This will only be the case in MetroPoint * configurations. * * @param cgSettings the consistency group settings. * @param state the consistency group state. * @return the standby copy if one exists, null otherwise. */ public static ConsistencyGroupCopyUID getStandbyProductionCopy(ConsistencyGroupSettings cgSettings, ConsistencyGroupState state) { logger.info("Attempting to find standby production copy"); if (cgSettings != null && cgSettings.getGroupCopiesSettings() != null) { List<ConsistencyGroupCopyUID> productionCopies = cgSettings.getProductionCopiesUIDs(); // If there are 2 production copies, we are dealing with a MetroPoint configuration. There will // be an active and a standby production copy. if (productionCopies != null && productionCopies.size() == 2) { for (ConsistencyGroupCopySettings copySetting : cgSettings.getGroupCopiesSettings()) { if (isStandbyProductionCopy(copySetting.getCopyUID(), state, productionCopies)) { return copySetting.getCopyUID(); } } } } return null; } /** * @param rpSites * @param wwnString * @return */ public static DeviceUID getDeviceID(Collection<RPSite> rpSites, String wwnString) { for (RPSite rpSite : rpSites) { ClusterSANVolumes siteSANVolumes = rpSite.getSiteVolumes(); for (VolumeInformation volume : siteSANVolumes.getVolumesInformations()) { String siteVolUID = RecoverPointUtils.getGuidBufferAsString(volume.getRawUids(), false); if (siteVolUID.equalsIgnoreCase(wwnString)) { return volume.getVolumeID(); } } } return null; } /** * @param rpSites * @param wwnString * @return */ public static DeviceUID getDeviceID(Collection<RPSite> rpSites, String volInternalSiteName, String wwnString) { for (RPSite rpSite : rpSites) { if (volInternalSiteName.equals(rpSite.getInternalSiteName())) { ClusterSANVolumes siteSANVolumes = rpSite.getSiteVolumes(); for (VolumeInformation volume : siteSANVolumes.getVolumesInformations()) { String siteVolUID = RecoverPointUtils.getGuidBufferAsString(volume.getRawUids(), false); if (siteVolUID.equalsIgnoreCase(wwnString)) { logger.info("Found volume " + wwnString + " on site " + rpSite.getInternalSiteName() + " as volume ID: " + volume.getVolumeID().getId()); return volume.getVolumeID(); } } } } return null; } /** * Find the transient site ID, given the permanent/unchanging unique internal site name. * Needed for some internal operations, like creating cgs. * * @param impl the established connection to an appliance * @param internalSiteName internal site name, never changes * @return ClusterUID corresponding to the site that has that internal site name. * @throws FunctionalAPIActionFailedException_Exception * @throws FunctionalAPIInternalError_Exception */ public static ClusterUID getRPSiteID(FunctionalAPIImpl impl, String internalSiteName) throws FunctionalAPIActionFailedException_Exception, FunctionalAPIInternalError_Exception { FullRecoverPointSettings fullRecoverPointSettings = impl.getFullRecoverPointSettings(); for (ClusterConfiguration siteSettings : fullRecoverPointSettings.getSystemSettings().getGlobalSystemConfiguration() .getClustersConfigurations()) { if (siteSettings.getInternalClusterName().equals(internalSiteName)) { return siteSettings.getCluster(); } } return null; } /** * Find the internal site name, given the cluster UID * * @param impl the established connection to an appliance * @param ClusterUID corresponding to the site that has that internal site name. * @return string internal site name * @throws FunctionalAPIActionFailedException_Exception * @throws FunctionalAPIInternalError_Exception */ public static String getInternalSiteName(FunctionalAPIImpl impl, ClusterUID clusterID) throws FunctionalAPIActionFailedException_Exception, FunctionalAPIInternalError_Exception { FullRecoverPointSettings fullRecoverPointSettings = impl.getFullRecoverPointSettings(); for (ClusterConfiguration siteSettings : fullRecoverPointSettings.getSystemSettings().getGlobalSystemConfiguration() .getClustersConfigurations()) { if (siteSettings.getCluster().getId() == clusterID.getId()) { return siteSettings.getInternalClusterName(); } } return null; } /** * @param rpProtectionInfo * @return */ public static ConsistencyGroupCopyUID mapRPVolumeProtectionInfoToCGCopyUID(RecoverPointVolumeProtectionInfo rpProtectionInfo) { ConsistencyGroupUID cgUID = new ConsistencyGroupUID(); ConsistencyGroupCopyUID cgCopyUID = new ConsistencyGroupCopyUID(); if (rpProtectionInfo != null) { cgUID.setId(rpProtectionInfo.getRpVolumeGroupID()); cgCopyUID.setGlobalCopyUID(new GlobalCopyUID()); cgCopyUID.getGlobalCopyUID().setCopyUID(rpProtectionInfo.getRpVolumeGroupCopyID()); cgCopyUID.setGroupUID(cgUID); ClusterUID ClusterUID = new ClusterUID(); ClusterUID.setId(rpProtectionInfo.getRpVolumeSiteID()); cgCopyUID.getGlobalCopyUID().setClusterUID(ClusterUID); } return cgCopyUID; } /** * Returns true if the specified RecoverPoint site is licensed. * * @param impl * @return boolean * @throws Exception */ public static boolean isSiteLicensed(FunctionalAPIImpl impl) throws Exception { // A bad license will be caught hear 99% of the time. try { AccountState accountState = impl.getAccountState(); List<LicenseState> licenseStates = accountState.getLicensesStates(); for (LicenseState licenseState : licenseStates) { if (licenseState.getLicenseStatus().equals(LicenseStatus.ACTIVE)) { logger.info("Found an active license"); return true; } } logger.error("RecoverPoint licenses do not exist, are invalid, or have expired. Check your RP configuration"); } catch (FunctionalAPIActionFailedException_Exception e) { return false; } catch (FunctionalAPIInternalError_Exception e) { ; return false; } catch (Exception f) { throw f; } return false; } /** * Returns the preferred RPA number to use as the primary RPA for a new * consistency group. The preferred RPA is determined by examining the * current throughput for all of the passed in cluster's RPAs and selecting * the RPA that is currently handling the least amount of throughput. * * @param impl - the established connection to an appliance * @param clusterUID - corresponding to the site that we are trying to determine the preferred RPA for. * @return RpaUID - object with the preferred RPA number * @throws FunctionalAPIActionFailedException_Exception * @throws FunctionalAPIInternalError_Exception * */ public static RpaUID getPreferredRPAForNewCG(FunctionalAPIImpl impl, ClusterUID clusterUID) throws FunctionalAPIActionFailedException_Exception, FunctionalAPIInternalError_Exception { RpaUID preferredRPA = new RpaUID(); // set the cluster UID to the value being passed preferredRPA.setClusterUID(clusterUID); // default the rpa to 1 preferredRPA.setRpaNumber(1); try { SystemStatistics systemStatistics = impl.getSystemStatistics(); List<RpaStatistics> rpaStatisticsList = systemStatistics.getRpaStatistics(); Long smallestThroughput = Long.valueOf(0); Long currenThroughput = Long.valueOf(0); for (RpaStatistics rpaStatistics : rpaStatisticsList) { if (rpaStatistics.getRpaUID().getClusterUID().getId() == clusterUID.getId()) { currenThroughput = Long.valueOf(0); logger.info("Looking at current throughput for RPA " + rpaStatistics.getRpaUID().getRpaNumber() + " on cluster " + rpaStatistics.getRpaUID().getClusterUID().getId()); TrafficStatistics trafficStatistics = rpaStatistics.getTraffic(); InOutThroughputStatistics throughput = trafficStatistics.getApplicationThroughputStatistics(); List<ConnectionOutThroughput> out = throughput.getConnectionsOutThroughputs(); for (ConnectionOutThroughput a : out) { logger.info("RPA " + rpaStatistics.getRpaUID().getRpaNumber() + " throughput to cluster " + a.getCluster().getId() + ": " + a.getOutThroughput() + " bytes/sec"); currenThroughput += a.getOutThroughput(); } if (smallestThroughput.longValue() == 0) { smallestThroughput = currenThroughput; } logger.info("Total throughput for RPA " + rpaStatistics.getRpaUID().getRpaNumber() + ": " + currenThroughput.toString() + " bytes/sec"); if (currenThroughput.compareTo(smallestThroughput) <= 0) { smallestThroughput = currenThroughput; preferredRPA.setRpaNumber(rpaStatistics.getRpaUID().getRpaNumber()); } } } } catch (Exception e) { logger.error(e.getMessage()); logger.info("Encountered error determining the preferred RPA, defaulting to RPA 1"); preferredRPA.setRpaNumber(1); return preferredRPA; } logger.info("Selected RPA " + preferredRPA.getRpaNumber() + " of cluster " + preferredRPA.getClusterUID().getId() + " for the new consistency group"); return preferredRPA; } /** * Gets the consistency group copy settings for a specific copy. * * @param impl the established connection to an appliance * @param cgCopyUID the consistency group copy id * @return the copy settings for the consistency group copy id or null if not found * @throws FunctionalAPIActionFailedException_Exception * @throws FunctionalAPIInternalError_Exception */ public static ConsistencyGroupCopySettings getCopySettings(FunctionalAPIImpl impl, ConsistencyGroupCopyUID cgCopyUID) throws FunctionalAPIActionFailedException_Exception, FunctionalAPIInternalError_Exception { ConsistencyGroupSettings groupSettings = impl.getGroupSettings(cgCopyUID.getGroupUID()); for (ConsistencyGroupCopySettings copySettings : groupSettings.getGroupCopiesSettings()) { if (copiesEqual(copySettings.getCopyUID(), cgCopyUID)) { return copySettings; } } return null; } /** * Determine the NAA identifier of the xtremio volume in the format RP requires * * @param nativeGuid string * @return the NAA identifier for the xtremio volume */ public static String getXioNativeGuid(String nativeGuid) { // nativeGuid coming in XTREMIO+APM00142114518+VOLUME+ea85e053e92a4076bc7c6b76935e14a2 // we want the final value after the third + sign return nativeGuid.split("\\+")[3]; } /** * Determines if the volume is an xtremio volume * * @param nativeGuid string * @return boolean indicating if this is an xtremio volume */ public static boolean isXioVolume(String nativeGuid) { // nativeGuid coming in XTREMIO+APM00142114518+VOLUME+ea85e053e92a4076bc7c6b76935e14a2 return nativeGuid.contains("XTREMIO"); } }