cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mtutkow...@apache.org
Subject [1/2] git commit: updated refs/heads/sf-4.3.2 to a004fba
Date Fri, 19 Dec 2014 06:20:20 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/sf-4.3.2 [created] a004fba77


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a004fba7/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
index 2d528ef..ea73ab5 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java
@@ -17,8 +17,8 @@
 package org.apache.cloudstack.storage.datastore.util;
 
 import java.io.BufferedReader;
-import java.io.InputStreamReader;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -27,18 +27,26 @@ import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
+import org.apache.commons.lang.StringUtils;
 import org.apache.http.HttpResponse;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpPost;
 import org.apache.http.conn.scheme.Scheme;
 import org.apache.http.conn.scheme.SchemeRegistry;
 import org.apache.http.conn.ssl.SSLSocketFactory;
@@ -46,13 +54,22 @@ import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.impl.conn.BasicClientConnectionManager;
 
-import com.cloud.utils.exception.CloudRuntimeException;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
-public class SolidFireUtil
-{
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterDetailsVO;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.user.AccountDetailVO;
+import com.cloud.user.AccountDetailsDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class SolidFireUtil {
     public static final String PROVIDER_NAME = "SolidFire";
+    public static final String SHARED_PROVIDER_NAME = "SolidFireShared";
+
+    public static final String LOG_PREFIX = "SolidFire: ";
 
     public static final String MANAGEMENT_VIP = "mVip";
     public static final String STORAGE_VIP = "sVip";
@@ -63,11 +80,25 @@ public class SolidFireUtil
     public static final String CLUSTER_ADMIN_USERNAME = "clusterAdminUsername";
     public static final String CLUSTER_ADMIN_PASSWORD = "clusterAdminPassword";
 
+    // these three variables should only be used for the SolidFire plug-in with the name SolidFireUtil.PROVIDER_NAME
     public static final String CLUSTER_DEFAULT_MIN_IOPS = "clusterDefaultMinIops";
     public static final String CLUSTER_DEFAULT_MAX_IOPS = "clusterDefaultMaxIops";
     public static final String CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS = "clusterDefaultBurstIopsPercentOfMaxIops";
 
+    // these three variables should only be used for the SolidFire plug-in with the name SolidFireUtil.SHARED_PROVIDER_NAME
+    public static final String MIN_IOPS = "minIops";
+    public static final String MAX_IOPS = "maxIops";
+    public static final String BURST_IOPS = "burstIops";
+
     public static final String ACCOUNT_ID = "accountId";
+    public static final String VOLUME_ID = "volumeId";
+    public static final String SNAPSHOT_ID = "snapshotId";
+    public static final String CLONE_ID = "cloneId";
+
+    public static final String VOLUME_SIZE = "sfVolumeSize";
+    public static final String SNAPSHOT_SIZE = "sfSnapshotSize";
+
+    public static final String SNAPSHOT_STORAGE_POOL_ID = "sfSnapshotStoragePoolId";
 
     public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername";
     public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret";
@@ -75,18 +106,367 @@ public class SolidFireUtil
     public static final String CHAP_TARGET_USERNAME = "chapTargetUsername";
     public static final String CHAP_TARGET_SECRET = "chapTargetSecret";
 
-    public static long createSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
-            String strSfVolumeName, long lSfAccountId, long lTotalSize, boolean bEnable512e, final String strCloudStackVolumeSize,
-            long lMinIops, long lMaxIops, long lBurstIops)
+    public static final String DATACENTER = "datacenter";
+
+    public static final String DATASTORE_NAME = "datastoreName";
+    public static final String IQN = "iqn";
+
+    public static final long MAX_IOPS_PER_VOLUME = 100000;
+
+    private static final int DEFAULT_MANAGEMENT_PORT = 443;
+    private static final int DEFAULT_STORAGE_PORT = 3260;
+
+    public static class SolidFireConnection {
+        private final String _managementVip;
+        private final int _managementPort;
+        private final String _clusterAdminUsername;
+        private final String _clusterAdminPassword;
+
+        public SolidFireConnection(String managementVip, int managementPort, String clusterAdminUsername, String clusterAdminPassword) {
+            _managementVip = managementVip;
+            _managementPort = managementPort;
+            _clusterAdminUsername = clusterAdminUsername;
+            _clusterAdminPassword = clusterAdminPassword;
+        }
+
+        public String getManagementVip() {
+            return _managementVip;
+        }
+
+        public int getManagementPort() {
+            return _managementPort;
+        }
+
+        public String getClusterAdminUsername() {
+            return _clusterAdminUsername;
+        }
+
+        public String getClusterAdminPassword() {
+            return _clusterAdminPassword;
+        }
+    }
+
+    public static SolidFireConnection getSolidFireConnection(long storagePoolId, StoragePoolDetailsDao storagePoolDetailsDao) {
+        StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_VIP);
+
+        String mVip = storagePoolDetail.getValue();
+
+        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.MANAGEMENT_PORT);
+
+        int mPort = Integer.parseInt(storagePoolDetail.getValue());
+
+        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_USERNAME);
+
+        String clusterAdminUsername = storagePoolDetail.getValue();
+
+        storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_ADMIN_PASSWORD);
+
+        String clusterAdminPassword = storagePoolDetail.getValue();
+
+        return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword);
+    }
+
+    public static String getSolidFireAccountName(String csAccountUuid, long csAccountId) {
+        return "CloudStack_" + csAccountUuid + "_" + csAccountId;
+    }
+
+    public static void updateCsDbWithSolidFireIopsInfo(long storagePoolId, PrimaryDataStoreDao primaryDataStoreDao, StoragePoolDetailsDao storagePoolDetailsDao,
+            long minIops, long maxIops, long burstIops) {
+        Map<String, String> existingDetails = storagePoolDetailsDao.listDetailsKeyPairs(storagePoolId);
+        Set<String> existingKeys = existingDetails.keySet();
+
+        Map<String, String> existingDetailsToKeep = new HashMap<String, String>();
+
+        for (String existingKey : existingKeys) {
+            String existingValue = existingDetails.get(existingKey);
+
+            if (!SolidFireUtil.MIN_IOPS.equalsIgnoreCase(existingValue) &&
+                    !SolidFireUtil.MAX_IOPS.equalsIgnoreCase(existingValue) &&
+                    !SolidFireUtil.BURST_IOPS.equalsIgnoreCase(existingValue)) {
+                existingDetailsToKeep.put(existingKey, existingValue);
+            }
+        }
+
+        existingDetailsToKeep.put(SolidFireUtil.MIN_IOPS, String.valueOf(minIops));
+        existingDetailsToKeep.put(SolidFireUtil.MAX_IOPS, String.valueOf(maxIops));
+        existingDetailsToKeep.put(SolidFireUtil.BURST_IOPS, String.valueOf(burstIops));
+
+        primaryDataStoreDao.updateDetails(storagePoolId, existingDetailsToKeep);
+    }
+
+    public static void updateCsDbWithSolidFireAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount,
+            long storagePoolId, AccountDetailsDao accountDetailsDao) {
+        AccountDetailVO accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.getAccountKey(storagePoolId),
+                String.valueOf(sfAccount.getId()));
+
+        accountDetailsDao.persist(accountDetail);
+
+        /*
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_USERNAME,
+                String.valueOf(sfAccount.getName()));
+
+        accountDetailsDao.persist(accountDetail);
+
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_INITIATOR_SECRET,
+                String.valueOf(sfAccount.getInitiatorSecret()));
+
+        accountDetailsDao.persist(accountDetail);
+
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_USERNAME,
+                sfAccount.getName());
+
+        accountDetailsDao.persist(accountDetail);
+
+        accountDetail = new AccountDetailVO(csAccountId,
+                SolidFireUtil.CHAP_TARGET_SECRET,
+                sfAccount.getTargetSecret());
+
+        accountDetailsDao.persist(accountDetail);
+        */
+    }
+
+    public static SolidFireAccount getSolidFireAccount(SolidFireConnection sfConnection, String sfAccountName) {
+        try {
+            return getSolidFireAccountByName(sfConnection, sfAccountName);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId,
+            String vagUuid, List<HostVO> hosts, ClusterDetailsDao clusterDetailsDao) {
+        if (hosts == null || hosts.isEmpty()) {
+            throw new CloudRuntimeException("There must be at least one host in the cluster.");
+        }
+
+        long lVagId;
+
+        try {
+            lVagId = SolidFireUtil.createSolidFireVag(sfConnection, "CloudStack-" + vagUuid,
+                SolidFireUtil.getIqnsFromHosts(hosts), new long[] { sfVolumeId });
+        }
+        catch (Exception ex) {
+            String iqnInVagAlready = "Exceeded maximum number of Volume Access Groups per initiator";
+
+            if (!ex.getMessage().contains(iqnInVagAlready)) {
+                throw new CloudRuntimeException(ex.getMessage());
+            }
+
+            // getCompatibleVag throws an exception if an existing VAG can't be located
+            SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(sfConnection, hosts);
+
+            lVagId = sfVag.getId();
+
+            long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
+
+            SolidFireUtil.modifySolidFireVag(sfConnection, lVagId,
+                sfVag.getInitiators(), volumeIds);
+        }
+
+        ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId));
+
+        clusterDetailsDao.persist(clusterDetail);
+
+        return lVagId;
+    }
+
+    public static boolean hostsSupport_iScsi(List<HostVO> hosts) {
+        if (hosts == null || hosts.size() == 0) {
+            return false;
+        }
+
+        for (Host host : hosts) {
+            if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static String[] getNewHostIqns(String[] currentIqns, String[] newIqns) {
+        List<String> lstIqns = new ArrayList<String>();
+
+        if (currentIqns != null) {
+            for (String currentIqn : currentIqns) {
+                lstIqns.add(currentIqn);
+            }
+        }
+
+        if (newIqns != null) {
+            for (String newIqn : newIqns) {
+                if (!lstIqns.contains(newIqn)) {
+                    lstIqns.add(newIqn);
+                }
+            }
+        }
+
+        return lstIqns.toArray(new String[0]);
+    }
+
+    public static long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) {
+        if (add) {
+            return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove);
+        }
+
+        return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove);
+    }
+
+    private static long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) {
+        List<Long> lstVolumeIds = new ArrayList<Long>();
+
+        if (volumeIds != null) {
+            for (long volumeId : volumeIds) {
+                lstVolumeIds.add(volumeId);
+            }
+        }
+
+        if (lstVolumeIds.contains(volumeIdToAdd)) {
+            return volumeIds;
+        }
+
+        lstVolumeIds.add(volumeIdToAdd);
+
+        return convertArray(lstVolumeIds);
+    }
+
+    private static long[] getNewVolumeIdsRemove(long[] volumeIds, long volumeIdToRemove) {
+        List<Long> lstVolumeIds = new ArrayList<Long>();
+
+        if (volumeIds != null) {
+            for (long volumeId : volumeIds) {
+                lstVolumeIds.add(volumeId);
+            }
+        }
+
+        lstVolumeIds.remove(volumeIdToRemove);
+
+        return convertArray(lstVolumeIds);
+    }
+
+    private static long[] convertArray(List<Long> items) {
+        if (items == null) {
+            return new long[0];
+        }
+
+        long[] outArray = new long[items.size()];
+
+        for (int i = 0; i < items.size(); i++) {
+            Long value = items.get(i);
+
+            outArray[i] = value;
+        }
+
+        return outArray;
+    }
+
+    public static String getVagKey(long storagePoolId) {
+        return "sfVolumeAccessGroup_" + storagePoolId;
+    }
+
+    public static String getAccountKey(long storagePoolId) {
+        return SolidFireUtil.ACCOUNT_ID + "_" + storagePoolId;
+    }
+
+    public static AccountDetailVO getAccountDetail(long csAccountId, long storagePoolId, AccountDetailsDao accountDetailsDao) {
+        AccountDetailVO accountDetail = accountDetailsDao.findDetail(csAccountId, SolidFireUtil.getAccountKey(storagePoolId));
+
+        if (accountDetail == null || accountDetail.getValue() == null) {
+            accountDetail = accountDetailsDao.findDetail(csAccountId, SolidFireUtil.ACCOUNT_ID);
+        }
+
+        return accountDetail;
+    }
+
+    public static String[] getIqnsFromHosts(List<? extends Host> hosts) {
+        if (hosts == null || hosts.size() == 0) {
+            throw new CloudRuntimeException("There do not appear to be any hosts in this cluster.");
+        }
+
+        List<String> lstIqns = new ArrayList<String>();
+
+        for (Host host : hosts) {
+            lstIqns.add(host.getStorageUrl());
+        }
+
+        return lstIqns.toArray(new String[0]);
+    }
+
+    // this method takes in a collection of hosts and tries to find an existing VAG that has all of them in it
+    // if successful, the VAG is returned; else, a CloudRuntimeException is thrown and this issue should be corrected by an admin
+    private static SolidFireUtil.SolidFireVag getCompatibleVag(SolidFireConnection sfConnection, List<HostVO> hosts) {
+        List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection);
+
+        if (sfVags != null) {
+            List<String> hostIqns = new ArrayList<String>();
+
+            // where the method we're in is called, hosts should not be null
+            for (HostVO host : hosts) {
+                // where the method we're in is called, host.getStorageUrl() should not be null (it actually should start with "iqn")
+                hostIqns.add(host.getStorageUrl().toLowerCase());
+            }
+
+            for (SolidFireUtil.SolidFireVag sfVag : sfVags) {
+                List<String> lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators());
+
+                // lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null
+                if (lstInitiators.containsAll(hostIqns)) {
+                    return sfVag;
+                }
+            }
+        }
+
+        throw new CloudRuntimeException("Unable to locate the appropriate SolidFire Volume Access Group");
+    }
+
+    private static List<String> getStringArrayAsLowerCaseStringList(String[] aString) {
+        List<String> lstLowerCaseString = new ArrayList<String>();
+
+        if (aString != null) {
+            for (String str : aString) {
+                if (str != null) {
+                    lstLowerCaseString.add(str.toLowerCase());
+                }
+            }
+        }
+
+        return lstLowerCaseString;
+    }
+
+    public static String getSolidFireVolumeName(String strCloudStackVolumeName) {
+        final String specialChar = "-";
+
+        StringBuilder strSolidFireVolumeName = new StringBuilder();
+
+        for (int i = 0; i < strCloudStackVolumeName.length(); i++) {
+            String strChar = strCloudStackVolumeName.substring(i, i + 1);
+
+            if (StringUtils.isAlphanumeric(strChar)) {
+                strSolidFireVolumeName.append(strChar);
+            } else {
+                strSolidFireVolumeName.append(specialChar);
+            }
+        }
+
+        return strSolidFireVolumeName.toString();
+    }
+
+    public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize,
+            boolean bEnable512e, String strCloudStackVolumeSize, long minIops, long maxIops, long burstIops)
     {
         final Gson gson = new GsonBuilder().create();
 
-        VolumeToCreate volumeToCreate = new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e,
-                strCloudStackVolumeSize, lMinIops, lMaxIops, lBurstIops);
+        Object volumeToCreate = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ?
+                new VolumeToCreateWithCloudStackVolumeSize(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, minIops, maxIops, burstIops) :
+                new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, minIops, maxIops, burstIops);
 
         String strVolumeToCreateJson = gson.toJson(volumeToCreate);
 
-        String strVolumeCreateResultJson = executeJsonRpc(strVolumeToCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVolumeCreateResultJson = executeJsonRpc(sfConnection, strVolumeToCreateJson);
 
         VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class);
 
@@ -95,7 +475,27 @@ public class SolidFireUtil
         return volumeCreateResult.result.volumeID;
     }
 
-    public static SolidFireVolume getSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+    public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, long totalSize, String strCloudStackVolumeSize,
+            long minIops, long maxIops, long burstIops)
+    {
+        final Gson gson = new GsonBuilder().create();
+
+        Object volumeToModify = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ?
+                new VolumeToModifyWithCloudStackVolumeSize(volumeId, totalSize, strCloudStackVolumeSize, minIops, maxIops, burstIops) :
+                new VolumeToModify(volumeId, totalSize, minIops, maxIops, burstIops);
+
+        String strVolumeToModifyJson = gson.toJson(volumeToModify);
+
+        String strVolumeModifyResultJson = executeJsonRpc(sfConnection, strVolumeToModifyJson);
+
+        JsonError jsonError = gson.fromJson(strVolumeModifyResultJson, JsonError.class);
+
+        if (jsonError.error != null) {
+            throw new IllegalStateException(jsonError.error.message);
+        }
+    }
+
+    public static SolidFireVolume getSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -103,7 +503,7 @@ public class SolidFireUtil
 
         String strVolumeToGetJson = gson.toJson(volumeToGet);
 
-        String strVolumeGetResultJson = executeJsonRpc(strVolumeToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVolumeGetResultJson = executeJsonRpc(sfConnection, strVolumeToGetJson);
 
         VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class);
 
@@ -118,17 +518,14 @@ public class SolidFireUtil
         return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, lTotalSize);
     }
 
-    public static List<SolidFireVolume> getSolidFireVolumesForAccountId(String strSfMvip, int iSfPort,
-            String strSfAdmin, String strSfPassword, long lAccountId)
-    {
+    public static List<SolidFireVolume> getSolidFireVolumesForAccountId(SolidFireConnection sfConnection, long lAccountId) {
         final Gson gson = new GsonBuilder().create();
 
         VolumesToGetForAccount volumesToGetForAccount = new VolumesToGetForAccount(lAccountId);
 
         String strVolumesToGetForAccountJson = gson.toJson(volumesToGetForAccount);
 
-        String strVolumesGetForAccountResultJson = executeJsonRpc(strVolumesToGetForAccountJson, strSfMvip, iSfPort,
-                strSfAdmin, strSfPassword);
+        String strVolumesGetForAccountResultJson = executeJsonRpc(sfConnection, strVolumesToGetForAccountJson);
 
         VolumeGetResult volumeGetResult = gson.fromJson(strVolumesGetForAccountResultJson, VolumeGetResult.class);
 
@@ -143,7 +540,7 @@ public class SolidFireUtil
         return sfVolumes;
     }
 
-    public static List<SolidFireVolume> getDeletedVolumes(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
+    public static List<SolidFireVolume> getDeletedVolumes(SolidFireConnection sfConnection)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -151,8 +548,7 @@ public class SolidFireUtil
 
         String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes);
 
-        String strListDeletedVolumesResultJson = executeJsonRpc(strListDeletedVolumesJson, strSfMvip, iSfPort,
-                strSfAdmin, strSfPassword);
+        String strListDeletedVolumesResultJson = executeJsonRpc(sfConnection, strListDeletedVolumesJson);
 
         VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class);
 
@@ -167,9 +563,9 @@ public class SolidFireUtil
         return deletedVolumes;
     }
 
-    public static SolidFireVolume deleteSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+    public static SolidFireVolume deleteSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
-        SolidFireVolume sfVolume = getSolidFireVolume(strSfMvip, iSfPort, strSfAdmin, strSfPassword, lVolumeId);
+        SolidFireVolume sfVolume = getSolidFireVolume(sfConnection, lVolumeId);
 
         final Gson gson = new GsonBuilder().create();
 
@@ -177,12 +573,12 @@ public class SolidFireUtil
 
         String strVolumeToDeleteJson = gson.toJson(volumeToDelete);
 
-        executeJsonRpc(strVolumeToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVolumeToDeleteJson);
 
         return sfVolume;
     }
 
-   public static void purgeSolidFireVolume(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVolumeId)
+   public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -190,13 +586,12 @@ public class SolidFireUtil
 
         String strVolumeToPurgeJson = gson.toJson(volumeToPurge);
 
-        executeJsonRpc(strVolumeToPurgeJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVolumeToPurgeJson);
     }
 
     private static final String ACTIVE = "active";
 
-    public static class SolidFireVolume
-    {
+    public static class SolidFireVolume {
         private final long _id;
         private final String _name;
         private final String _iqn;
@@ -215,28 +610,23 @@ public class SolidFireUtil
             _totalSize = totalSize;
         }
 
-        public long getId()
-        {
+        public long getId() {
             return _id;
         }
 
-        public String getName()
-        {
+        public String getName() {
             return _name;
         }
 
-        public String getIqn()
-        {
+        public String getIqn() {
             return _iqn;
         }
 
-        public long getAccountId()
-        {
+        public long getAccountId() {
             return _accountId;
         }
 
-        public boolean isActive()
-        {
+        public boolean isActive() {
             return ACTIVE.equalsIgnoreCase(_status);
         }
 
@@ -276,7 +666,50 @@ public class SolidFireUtil
         }
     }
 
-    public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strAccountName)
+    public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName) {
+        final Gson gson = new GsonBuilder().create();
+
+        SnapshotToCreate snapshotToCreate = new SnapshotToCreate(lVolumeId, snapshotName);
+
+        String strSnapshotToCreateJson = gson.toJson(snapshotToCreate);
+
+        String strSnapshotCreateResultJson = executeJsonRpc(sfConnection, strSnapshotToCreateJson);
+
+        SnapshotCreateResult snapshotCreateResult = gson.fromJson(strSnapshotCreateResultJson, SnapshotCreateResult.class);
+
+        verifyResult(snapshotCreateResult.result, strSnapshotCreateResultJson, gson);
+
+        return snapshotCreateResult.result.snapshotID;
+    }
+
+    public static void deleteSolidFireSnapshot(SolidFireConnection sfConnection, long lSnapshotId)
+    {
+        final Gson gson = new GsonBuilder().create();
+
+        SnapshotToDelete snapshotToDelete = new SnapshotToDelete(lSnapshotId);
+
+        String strSnapshotToDeleteJson = gson.toJson(snapshotToDelete);
+
+        executeJsonRpc(sfConnection, strSnapshotToDeleteJson);
+    }
+
+    public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, String cloneName) {
+        final Gson gson = new GsonBuilder().create();
+
+        CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, cloneName);
+
+        String strCloneToCreateJson = gson.toJson(cloneToCreate);
+
+        String strCloneCreateResultJson = executeJsonRpc(sfConnection, strCloneToCreateJson);
+
+        CloneCreateResult cloneCreateResult = gson.fromJson(strCloneCreateResultJson, CloneCreateResult.class);
+
+        verifyResult(cloneCreateResult.result, strCloneCreateResultJson, gson);
+
+        return cloneCreateResult.result.cloneID;
+    }
+
+    public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -284,7 +717,7 @@ public class SolidFireUtil
 
         String strAccountAddJson = gson.toJson(accountToAdd);
 
-        String strAccountAddResultJson = executeJsonRpc(strAccountAddJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAccountAddResultJson = executeJsonRpc(sfConnection, strAccountAddJson);
 
         AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class);
 
@@ -293,7 +726,7 @@ public class SolidFireUtil
         return accountAddResult.result.accountID;
     }
 
-    public static SolidFireAccount getSolidFireAccountById(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lSfAccountId)
+    public static SolidFireAccount getSolidFireAccountById(SolidFireConnection sfConnection, long lSfAccountId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -301,7 +734,7 @@ public class SolidFireUtil
 
         String strAccountToGetByIdJson = gson.toJson(accountToGetById);
 
-        String strAccountGetByIdResultJson = executeJsonRpc(strAccountToGetByIdJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAccountGetByIdResultJson = executeJsonRpc(sfConnection, strAccountToGetByIdJson);
 
         AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class);
 
@@ -314,7 +747,7 @@ public class SolidFireUtil
         return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
     }
 
-    public static SolidFireAccount getSolidFireAccountByName(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strSfAccountName)
+    public static SolidFireAccount getSolidFireAccountByName(SolidFireConnection sfConnection, String strSfAccountName)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -322,7 +755,7 @@ public class SolidFireUtil
 
         String strAccountToGetByNameJson = gson.toJson(accountToGetByName);
 
-        String strAccountGetByNameResultJson = executeJsonRpc(strAccountToGetByNameJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAccountGetByNameResultJson = executeJsonRpc(sfConnection, strAccountToGetByNameJson);
 
         AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class);
 
@@ -335,7 +768,7 @@ public class SolidFireUtil
         return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret);
     }
 
-    public static void deleteSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId)
+    public static void deleteSolidFireAccount(SolidFireConnection sfConnection, long lAccountId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -343,7 +776,7 @@ public class SolidFireUtil
 
         String strAccountToRemoveJson = gson.toJson(accountToRemove);
 
-        executeJsonRpc(strAccountToRemoveJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strAccountToRemoveJson);
     }
 
     public static class SolidFireAccount
@@ -353,31 +786,26 @@ public class SolidFireUtil
         private final String _initiatorSecret;
         private final String _targetSecret;
 
-        public SolidFireAccount(long id, String name, String initiatorSecret, String targetSecret)
-        {
+        public SolidFireAccount(long id, String name, String initiatorSecret, String targetSecret) {
             _id = id;
             _name = name;
             _initiatorSecret = initiatorSecret;
             _targetSecret = targetSecret;
         }
 
-        public long getId()
-        {
+        public long getId() {
             return _id;
         }
 
-        public String getName()
-        {
+        public String getName() {
             return _name;
         }
 
-        public String getInitiatorSecret()
-        {
+        public String getInitiatorSecret() {
             return _initiatorSecret;
         }
 
-        public String getTargetSecret()
-        {
+        public String getTargetSecret() {
             return _targetSecret;
         }
 
@@ -413,7 +841,7 @@ public class SolidFireUtil
         }
     }
 
-    public static long createSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strVagName,
+    public static long createSolidFireVag(SolidFireConnection sfConnection, String strVagName,
             String[] iqns, long[] volumeIds)
     {
         final Gson gson = new GsonBuilder().create();
@@ -422,7 +850,7 @@ public class SolidFireUtil
 
         String strVagCreateJson = gson.toJson(vagToCreate);
 
-        String strVagCreateResultJson = executeJsonRpc(strVagCreateJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVagCreateResultJson = executeJsonRpc(sfConnection, strVagCreateJson);
 
         VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class);
 
@@ -431,8 +859,7 @@ public class SolidFireUtil
         return vagCreateResult.result.volumeAccessGroupID;
     }
 
-    public static void modifySolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId,
-            String[] iqns, long[] volumeIds)
+    public static void modifySolidFireVag(SolidFireConnection sfConnection, long lVagId, String[] iqns, long[] volumeIds)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -440,10 +867,10 @@ public class SolidFireUtil
 
         String strVagModifyJson = gson.toJson(vagToModify);
 
-        executeJsonRpc(strVagModifyJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVagModifyJson);
     }
 
-    public static SolidFireVag getSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
+    public static SolidFireVag getSolidFireVag(SolidFireConnection sfConnection, long lVagId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -451,7 +878,7 @@ public class SolidFireUtil
 
         String strVagToGetJson = gson.toJson(vagToGet);
 
-        String strVagGetResultJson = executeJsonRpc(strVagToGetJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strVagGetResultJson = executeJsonRpc(sfConnection, strVagToGetJson);
 
         VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class);
 
@@ -463,7 +890,7 @@ public class SolidFireUtil
         return new SolidFireVag(lVagId, vagIqns, vagVolumeIds);
     }
 
-    public static List<SolidFireVag> getAllSolidFireVags(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
+    public static List<SolidFireVag> getAllSolidFireVags(SolidFireConnection sfConnection)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -471,7 +898,7 @@ public class SolidFireUtil
 
         String strAllVagsJson = gson.toJson(allVags);
 
-        String strAllVagsGetResultJson = executeJsonRpc(strAllVagsJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        String strAllVagsGetResultJson = executeJsonRpc(sfConnection, strAllVagsJson);
 
         VagGetResult allVagsGetResult = gson.fromJson(strAllVagsGetResultJson, VagGetResult.class);
 
@@ -490,7 +917,7 @@ public class SolidFireUtil
         return lstSolidFireVags;
     }
 
-    public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
+    public static void deleteSolidFireVag(SolidFireConnection sfConnection, long lVagId)
     {
         final Gson gson = new GsonBuilder().create();
 
@@ -498,7 +925,7 @@ public class SolidFireUtil
 
         String strVagToDeleteJson = gson.toJson(vagToDelete);
 
-        executeJsonRpc(strVagToDeleteJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
+        executeJsonRpc(sfConnection, strVagToDeleteJson);
     }
 
     public static class SolidFireVag
@@ -550,7 +977,7 @@ public class SolidFireUtil
             }
 
             SolidFireVag sfvag = (SolidFireVag)obj;
-            
+
             if (_id == sfvag._id) {
                 return true;
             }
@@ -560,30 +987,25 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
-    private static final class VolumeToCreate
-    {
+    private static final class VolumeToCreateWithCloudStackVolumeSize {
         private final String method = "CreateVolume";
         private final VolumeToCreateParams params;
 
-        private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize,
-                final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
-        {
-            params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e,
-                    strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
+        private VolumeToCreateWithCloudStackVolumeSize(final String strVolumeName, final long lAccountId, final long lTotalSize,
+                final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+            params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
         }
 
-        private static final class VolumeToCreateParams
-        {
+        private static final class VolumeToCreateParams {
             private final String name;
             private final long accountID;
             private final long totalSize;
             private final boolean enable512e;
-            private final VolumeToCreateParamsQoS qos;
             private final VolumeToCreateParamsAttributes attributes;
+            private final VolumeToCreateParamsQoS qos;
 
-            private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize,
-                    final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
-            {
+            private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
+                    final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
                 name = strVolumeName;
                 accountID = lAccountId;
                 totalSize = lTotalSize;
@@ -593,24 +1015,20 @@ public class SolidFireUtil
                 qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
             }
 
-            private static final class VolumeToCreateParamsAttributes
-            {
+            private static final class VolumeToCreateParamsAttributes {
                 private final String CloudStackVolumeSize;
 
-                private VolumeToCreateParamsAttributes(final String strCloudStackVolumeSize)
-                {
+                private VolumeToCreateParamsAttributes(final String strCloudStackVolumeSize) {
                     CloudStackVolumeSize = strCloudStackVolumeSize;
                 }
             }
 
-            private static final class VolumeToCreateParamsQoS
-            {
+            private static final class VolumeToCreateParamsQoS {
                 private final long minIOPS;
                 private final long maxIOPS;
                 private final long burstIOPS;
 
-                private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
-                {
+                private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
                     minIOPS = lMinIOPS;
                     maxIOPS = lMaxIOPS;
                     burstIOPS = lBurstIOPS;
@@ -620,6 +1038,138 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
+    private static final class VolumeToCreate {
+        private final String method = "CreateVolume";
+        private final VolumeToCreateParams params;
+
+        private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
+                final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+            params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, lMinIOPS, lMaxIOPS, lBurstIOPS);
+        }
+
+        private static final class VolumeToCreateParams {
+            private final String name;
+            private final long accountID;
+            private final long totalSize;
+            private final boolean enable512e;
+            private final VolumeToCreateParamsQoS qos;
+
+            private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e,
+                    final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+                name = strVolumeName;
+                accountID = lAccountId;
+                totalSize = lTotalSize;
+                enable512e = bEnable512e;
+
+                qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
+            }
+
+            private static final class VolumeToCreateParamsQoS {
+                private final long minIOPS;
+                private final long maxIOPS;
+                private final long burstIOPS;
+
+                private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+                    minIOPS = lMinIOPS;
+                    maxIOPS = lMaxIOPS;
+                    burstIOPS = lBurstIOPS;
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static final class VolumeToModifyWithCloudStackVolumeSize
+    {
+        private final String method = "ModifyVolume";
+        private final VolumeToModifyParams params;
+
+        private VolumeToModifyWithCloudStackVolumeSize(final long lVolumeId, final long lTotalSize, final String strCloudStackVolumeSize,
+                final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
+        {
+            params = new VolumeToModifyParams(lVolumeId, lTotalSize, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
+        }
+
+        private static final class VolumeToModifyParams
+        {
+            private final long volumeID;
+            private final long totalSize;
+            private final VolumeToModifyParamsAttributes attributes;
+            private final VolumeToModifyParamsQoS qos;
+
+            private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
+            {
+                volumeID = lVolumeId;
+
+                totalSize = lTotalSize;
+
+                attributes = new VolumeToModifyParamsAttributes(strCloudStackVolumeSize);
+                qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
+            }
+        }
+
+        private static final class VolumeToModifyParamsAttributes {
+            private final String CloudStackVolumeSize;
+
+            private VolumeToModifyParamsAttributes(final String strCloudStackVolumeSize) {
+                CloudStackVolumeSize = strCloudStackVolumeSize;
+            }
+        }
+
+        private static final class VolumeToModifyParamsQoS {
+            private final long minIOPS;
+            private final long maxIOPS;
+            private final long burstIOPS;
+
+            private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+                minIOPS = lMinIOPS;
+                maxIOPS = lMaxIOPS;
+                burstIOPS = lBurstIOPS;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static final class VolumeToModify
+    {
+        private final String method = "ModifyVolume";
+        private final VolumeToModifyParams params;
+
+        private VolumeToModify(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
+        {
+            params = new VolumeToModifyParams(lVolumeId, lTotalSize, lMinIOPS, lMaxIOPS, lBurstIOPS);
+        }
+
+        private static final class VolumeToModifyParams
+        {
+            private final long volumeID;
+            private final long totalSize;
+            private final VolumeToModifyParamsQoS qos;
+
+            private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS)
+            {
+                volumeID = lVolumeId;
+
+                totalSize = lTotalSize;
+
+                qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS);
+            }
+        }
+
+        private static final class VolumeToModifyParamsQoS {
+            private final long minIOPS;
+            private final long maxIOPS;
+            private final long burstIOPS;
+
+            private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) {
+                minIOPS = lMinIOPS;
+                maxIOPS = lMaxIOPS;
+                burstIOPS = lBurstIOPS;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
     private static final class VolumeToGet
     {
         private final String method = "ListActiveVolumes";
@@ -676,17 +1226,14 @@ public class SolidFireUtil
         private final String method = "DeleteVolume";
         private final VolumeToDeleteParams params;
 
-        private VolumeToDelete(final long lVolumeId)
-        {
+        private VolumeToDelete(final long lVolumeId) {
             params = new VolumeToDeleteParams(lVolumeId);
         }
 
-        private static final class VolumeToDeleteParams
-        {
+        private static final class VolumeToDeleteParams {
             private long volumeID;
 
-            private VolumeToDeleteParams(final long lVolumeId)
-            {
+            private VolumeToDeleteParams(final long lVolumeId) {
                 volumeID = lVolumeId;
             }
         }
@@ -698,23 +1245,79 @@ public class SolidFireUtil
         private final String method = "PurgeDeletedVolume";
         private final VolumeToPurgeParams params;
 
-        private VolumeToPurge(final long lVolumeId)
-        {
+        private VolumeToPurge(final long lVolumeId) {
             params = new VolumeToPurgeParams(lVolumeId);
         }
 
-        private static final class VolumeToPurgeParams
-        {
+        private static final class VolumeToPurgeParams {
             private long volumeID;
 
-            private VolumeToPurgeParams(final long lVolumeId)
-            {
+            private VolumeToPurgeParams(final long lVolumeId) {
                 volumeID = lVolumeId;
             }
         }
     }
 
     @SuppressWarnings("unused")
+    private static final class SnapshotToCreate {
+        private final String method = "CreateSnapshot";
+        private final SnapshotToCreateParams params;
+
+        private SnapshotToCreate(final long lVolumeId, final String snapshotName) {
+            params = new SnapshotToCreateParams(lVolumeId, snapshotName);
+        }
+
+        private static final class SnapshotToCreateParams {
+            private long volumeID;
+            private String name;
+
+            private SnapshotToCreateParams(final long lVolumeId, final String snapshotName) {
+                volumeID = lVolumeId;
+                name = snapshotName;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static final class SnapshotToDelete
+    {
+        private final String method = "DeleteSnapshot";
+        private final SnapshotToDeleteParams params;
+
+        private SnapshotToDelete(final long lSnapshotId) {
+            params = new SnapshotToDeleteParams(lSnapshotId);
+        }
+
+        private static final class SnapshotToDeleteParams {
+            private long snapshotID;
+
+            private SnapshotToDeleteParams(final long lSnapshotId) {
+                snapshotID = lSnapshotId;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private static final class CloneToCreate {
+        private final String method = "CloneVolume";
+        private final CloneToCreateParams params;
+
+        private CloneToCreate(final long lVolumeId, final String cloneName) {
+            params = new CloneToCreateParams(lVolumeId, cloneName);
+        }
+
+        private static final class CloneToCreateParams {
+            private long volumeID;
+            private String name;
+
+            private CloneToCreateParams(final long lVolumeId, final String cloneName) {
+                volumeID = lVolumeId;
+                name = cloneName;
+            }
+        }
+    }
+
+    @SuppressWarnings("unused")
     private static final class AccountToAdd
     {
         private final String method = "AddAccount";
@@ -781,22 +1384,18 @@ public class SolidFireUtil
     }
 
     @SuppressWarnings("unused")
-    private static final class AccountToRemove
-    {
+    private static final class AccountToRemove {
         private final String method = "RemoveAccount";
         private final AccountToRemoveParams params;
 
-        private AccountToRemove(final long lAccountId)
-        {
+        private AccountToRemove(final long lAccountId) {
             params = new AccountToRemoveParams(lAccountId);
         }
 
-        private static final class AccountToRemoveParams
-        {
+        private static final class AccountToRemoveParams {
             private long accountID;
 
-            private AccountToRemoveParams(final long lAccountId)
-            {
+            private AccountToRemoveParams(final long lAccountId) {
                 accountID = lAccountId;
             }
         }
@@ -898,42 +1497,34 @@ public class SolidFireUtil
         private final String method = "DeleteVolumeAccessGroup";
         private final VagToDeleteParams params;
 
-        private VagToDelete(final long lVagId)
-        {
+        private VagToDelete(final long lVagId) {
             params = new VagToDeleteParams(lVagId);
         }
 
-        private static final class VagToDeleteParams
-        {
+        private static final class VagToDeleteParams {
             private long volumeAccessGroupID;
 
-            private VagToDeleteParams(final long lVagId)
-            {
+            private VagToDeleteParams(final long lVagId) {
                 volumeAccessGroupID = lVagId;
             }
         }
     }
 
-    private static final class VolumeCreateResult
-    {
+    private static final class VolumeCreateResult {
         private Result result;
 
-        private static final class Result
-        {
+        private static final class Result {
             private long volumeID;
         }
     }
 
-    private static final class VolumeGetResult
-    {
+    private static final class VolumeGetResult {
         private Result result;
 
-        private static final class Result
-        {
+        private static final class Result {
             private Volume[] volumes;
 
-            private static final class Volume
-            {
+            private static final class Volume {
                 private long volumeID;
                 private String name;
                 private String iqn;
@@ -944,26 +1535,37 @@ public class SolidFireUtil
         }
     }
 
-    private static final class AccountAddResult
-    {
+    private static final class SnapshotCreateResult {
         private Result result;
 
-        private static final class Result
-        {
+        private static final class Result {
+            private long snapshotID;
+        }
+    }
+
+    private static final class CloneCreateResult {
+        private Result result;
+
+        private static final class Result {
+            private long cloneID;
+        }
+    }
+
+    private static final class AccountAddResult {
+        private Result result;
+
+        private static final class Result {
             private long accountID;
         }
     }
 
-    private static final class AccountGetResult
-    {
+    private static final class AccountGetResult {
         private Result result;
 
-        private static final class Result
-        {
+        private static final class Result {
             private Account account;
 
-            private static final class Account
-            {
+            private static final class Account {
                 private long accountID;
                 private String username;
                 private String initiatorSecret;
@@ -972,12 +1574,10 @@ public class SolidFireUtil
         }
     }
 
-    private static final class VagCreateResult
-    {
+    private static final class VagCreateResult {
         private Result result;
 
-        private static final class Result
-        {
+        private static final class Result {
             private long volumeAccessGroupID;
         }
     }
@@ -1003,8 +1603,7 @@ public class SolidFireUtil
     {
         private Error error;
 
-        private static final class Error
-        {
+        private static final class Error {
             private String message;
         }
     }
@@ -1013,18 +1612,21 @@ public class SolidFireUtil
         try {
             SSLContext sslContext = SSLContext.getInstance("SSL");
             X509TrustManager tm = new X509TrustManager() {
+                @Override
                 public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                 }
 
+                @Override
                 public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                 }
 
+                @Override
                 public X509Certificate[] getAcceptedIssuers() {
                     return null;
                 }
             };
 
-            sslContext.init(null, new TrustManager[] { tm }, new SecureRandom());
+            sslContext.init(null, new TrustManager[] {tm}, new SecureRandom());
 
             SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
             SchemeRegistry registry = new SchemeRegistry();
@@ -1035,32 +1637,27 @@ public class SolidFireUtil
             DefaultHttpClient client = new DefaultHttpClient();
 
             return new DefaultHttpClient(mgr, client.getParams());
-        }
-        catch (NoSuchAlgorithmException ex) {
+        } catch (NoSuchAlgorithmException ex) {
             throw new CloudRuntimeException(ex.getMessage());
-        }
-        catch (KeyManagementException ex) {
+        } catch (KeyManagementException ex) {
             throw new CloudRuntimeException(ex.getMessage());
         }
     }
 
-    private static String executeJsonRpc(String strJsonToExecute, String strMvip, int iPort,
-            String strAdmin, String strPassword)
-    {
+    private static String executeJsonRpc(SolidFireConnection sfConnection, String strJsonToExecute) {
         DefaultHttpClient httpClient = null;
         StringBuilder sb = new StringBuilder();
 
-        try
-        {
+        try {
             StringEntity input = new StringEntity(strJsonToExecute);
 
             input.setContentType("application/json");
 
-            httpClient = getHttpClient(iPort);
+            httpClient = getHttpClient(sfConnection.getManagementPort());
 
-            URI uri = new URI("https://" + strMvip + ":" + iPort + "/json-rpc/5.0");
+            URI uri = new URI("https://" + sfConnection.getManagementVip() + ":" + sfConnection.getManagementPort() + "/json-rpc/6.0");
             AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort(), AuthScope.ANY_SCHEME);
-            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(strAdmin, strPassword);
+            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword());
 
             httpClient.getCredentialsProvider().setCredentials(authScope, credentials);
 
@@ -1070,8 +1667,7 @@ public class SolidFireUtil
 
             HttpResponse response = httpClient.execute(postRequest);
 
-            if (!isSuccess(response.getStatusLine().getStatusCode()))
-            {
+            if (!isSuccess(response.getStatusLine().getStatusCode())) {
                 throw new CloudRuntimeException("Failed on JSON-RPC API call. HTTP error code = " + response.getStatusLine().getStatusCode());
             }
 
@@ -1079,28 +1675,23 @@ public class SolidFireUtil
 
             String strOutput;
 
-            while ((strOutput = br.readLine()) != null)
-            {
+            while ((strOutput = br.readLine()) != null) {
                 sb.append(strOutput);
             }
-        }
-        catch (UnsupportedEncodingException ex) {
+        } catch (UnsupportedEncodingException ex) {
             throw new CloudRuntimeException(ex.getMessage());
-        }
-        catch (ClientProtocolException ex) {
+        } catch (ClientProtocolException ex) {
             throw new CloudRuntimeException(ex.getMessage());
-        }
-        catch (IOException ex) {
+        } catch (IOException ex) {
             throw new CloudRuntimeException(ex.getMessage());
-        }
-        catch (URISyntaxException ex) {
+        } catch (URISyntaxException ex) {
             throw new CloudRuntimeException(ex.getMessage());
-        }
-        finally {
+        } finally {
             if (httpClient != null) {
                 try {
                     httpClient.getConnectionManager().shutdown();
-                } catch (Exception t) {}
+                } catch (Exception t) {
+                }
             }
         }
 
@@ -1111,61 +1702,46 @@ public class SolidFireUtil
         return iCode >= 200 && iCode < 300;
     }
 
-    private static void verifyResult(Object obj, String strJson, Gson gson) throws IllegalStateException
-    {
-        if (obj != null)
-        {
+    private static void verifyResult(Object result, String strJson, Gson gson) throws IllegalStateException {
+        if (result != null) {
             return;
         }
 
         JsonError jsonError = gson.fromJson(strJson, JsonError.class);
 
-        if (jsonError != null)
-        {
+        if (jsonError != null) {
             throw new IllegalStateException(jsonError.error.message);
         }
 
         throw new IllegalStateException("Problem with the following JSON: " + strJson);
     }
 
-    private static String getVolumeName(VolumeGetResult volumeGetResult, long lVolumeId)
-    {
-        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
-            volumeGetResult.result.volumes[0].volumeID == lVolumeId)
-        {
+    private static String getVolumeName(VolumeGetResult volumeGetResult, long lVolumeId) {
+        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
             return volumeGetResult.result.volumes[0].name;
         }
 
         throw new CloudRuntimeException("Could not determine the name of the volume for volume ID of " + lVolumeId + ".");
     }
 
-    private static String getVolumeIqn(VolumeGetResult volumeGetResult, long lVolumeId)
-    {
-        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
-            volumeGetResult.result.volumes[0].volumeID == lVolumeId)
-        {
+    private static String getVolumeIqn(VolumeGetResult volumeGetResult, long lVolumeId) {
+        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
             return volumeGetResult.result.volumes[0].iqn;
         }
 
         throw new CloudRuntimeException("Could not determine the IQN of the volume for volume ID of " + lVolumeId + ".");
     }
 
-    private static long getVolumeAccountId(VolumeGetResult volumeGetResult, long lVolumeId)
-    {
-        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
-            volumeGetResult.result.volumes[0].volumeID == lVolumeId)
-        {
+    private static long getVolumeAccountId(VolumeGetResult volumeGetResult, long lVolumeId) {
+        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
             return volumeGetResult.result.volumes[0].accountID;
         }
 
         throw new CloudRuntimeException("Could not determine the account ID of the volume for volume ID of " + lVolumeId + ".");
     }
 
-    private static String getVolumeStatus(VolumeGetResult volumeGetResult, long lVolumeId)
-    {
-        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 &&
-            volumeGetResult.result.volumes[0].volumeID == lVolumeId)
-        {
+    private static String getVolumeStatus(VolumeGetResult volumeGetResult, long lVolumeId) {
+        if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && volumeGetResult.result.volumes[0].volumeID == lVolumeId) {
             return volumeGetResult.result.volumes[0].status;
         }
 
@@ -1204,4 +1780,119 @@ public class SolidFireUtil
 
         throw new CloudRuntimeException("Could not determine the volume IDs of the volume access group for volume access group ID of " + lVagId + ".");
     }
+
+    // used to parse the "url" parameter when creating primary storage that's based on the SolidFire plug-in with the
+    // name SolidFireUtil.PROVIDER_NAME (as opposed to the SolidFire plug-in with the name SolidFireUtil.SHARED_PROVIDER_NAME)
+    // return a String instance that contains at most the MVIP and SVIP info
+    public static String getModifiedUrl(String originalUrl) {
+        StringBuilder sb = new StringBuilder();
+
+        String delimiter = ";";
+
+        StringTokenizer st = new StringTokenizer(originalUrl, delimiter);
+
+        while (st.hasMoreElements()) {
+            String token = st.nextElement().toString().toUpperCase();
+
+            if (token.startsWith(SolidFireUtil.MANAGEMENT_VIP.toUpperCase()) || token.startsWith(SolidFireUtil.STORAGE_VIP.toUpperCase())) {
+                sb.append(token).append(delimiter);
+            }
+        }
+
+        String modifiedUrl = sb.toString();
+        int lastIndexOf = modifiedUrl.lastIndexOf(delimiter);
+
+        if (lastIndexOf == (modifiedUrl.length() - delimiter.length())) {
+            return modifiedUrl.substring(0, lastIndexOf);
+        }
+
+        return modifiedUrl;
+    }
+
+    public static String getManagementVip(String url) {
+        return getVip(SolidFireUtil.MANAGEMENT_VIP, url);
+    }
+
+    public static String getStorageVip(String url) {
+        return getVip(SolidFireUtil.STORAGE_VIP, url);
+    }
+
+    public static int getManagementPort(String url) {
+        return getPort(SolidFireUtil.MANAGEMENT_VIP, url, DEFAULT_MANAGEMENT_PORT);
+    }
+
+    public static int getStoragePort(String url) {
+        return getPort(SolidFireUtil.STORAGE_VIP, url, DEFAULT_STORAGE_PORT);
+    }
+
+    private static String getVip(String keyToMatch, String url) {
+        String delimiter = ":";
+
+        String storageVip = getValue(keyToMatch, url);
+
+        int index = storageVip.indexOf(delimiter);
+
+        if (index != -1) {
+            return storageVip.substring(0, index);
+        }
+
+        return storageVip;
+    }
+
+    private static int getPort(String keyToMatch, String url, int defaultPortNumber) {
+        String delimiter = ":";
+
+        String storageVip = getValue(keyToMatch, url);
+
+        int index = storageVip.indexOf(delimiter);
+
+        int portNumber = defaultPortNumber;
+
+        if (index != -1) {
+            String port = storageVip.substring(index + delimiter.length());
+
+            try {
+                portNumber = Integer.parseInt(port);
+            } catch (NumberFormatException ex) {
+                throw new IllegalArgumentException("Invalid URL format (port is not an integer)");
+            }
+        }
+
+        return portNumber;
+    }
+
+    public static String getValue(String keyToMatch, String url) {
+        return getValue(keyToMatch, url, true);
+    }
+
+    public static String getValue(String keyToMatch, String url, boolean throwExceptionIfNotFound) {
+        String delimiter1 = ";";
+        String delimiter2 = "=";
+
+        StringTokenizer st = new StringTokenizer(url, delimiter1);
+
+        while (st.hasMoreElements()) {
+            String token = st.nextElement().toString();
+
+            int index = token.indexOf(delimiter2);
+
+            if (index == -1) {
+                throw new RuntimeException("Invalid URL format");
+            }
+
+            String key = token.substring(0, index);
+
+            if (key.equalsIgnoreCase(keyToMatch)) {
+                String valueToReturn = token.substring(index + delimiter2.length());
+
+                return valueToReturn;
+            }
+        }
+
+        if (throwExceptionIfNotFound) {
+            throw new RuntimeException("Key not found in URL");
+        }
+
+        return null;
+    }
 }


Mime
View raw message