CLOUDSTACK-4810: Enable hypervisor snapshots for CloudStack-managed storage (for XenServer and VMware)

This commit is contained in:
Mike Tutkowski 2014-01-07 22:52:11 -07:00
parent ce9760f4ce
commit 2efe61ddbc
2 changed files with 141 additions and 21 deletions

View File

@ -133,18 +133,15 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword);
}
private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName,
SolidFireConnection sfConnection) {
private SolidFireUtil.SolidFireAccount createSolidFireAccount(String sfAccountName, SolidFireConnection sfConnection) {
String mVip = sfConnection.getManagementVip();
int mPort = sfConnection.getManagementPort();
String clusterAdminUsername = sfConnection.getClusterAdminUsername();
String clusterAdminPassword = sfConnection.getClusterAdminPassword();
long accountNumber = SolidFireUtil.createSolidFireAccount(mVip, mPort,
clusterAdminUsername, clusterAdminPassword, sfAccountName);
long accountNumber = SolidFireUtil.createSolidFireAccount(mVip, mPort, clusterAdminUsername, clusterAdminPassword, sfAccountName);
return SolidFireUtil.getSolidFireAccountById(mVip, mPort,
clusterAdminUsername, clusterAdminPassword, accountNumber);
return SolidFireUtil.getSolidFireAccountById(mVip, mPort, clusterAdminUsername, clusterAdminPassword, accountNumber);
}
private void updateCsDbWithAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount) {
@ -185,8 +182,7 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
private final String _targetUsername;
private final String _targetSecret;
public ChapInfoImpl(String initiatorUsername, String initiatorSecret,
String targetUsername, String targetSecret) {
public ChapInfoImpl(String initiatorUsername, String initiatorSecret, String targetUsername, String targetSecret) {
_initiatorUsername = initiatorUsername;
_initiatorSecret = initiatorSecret;
_targetUsername = targetUsername;
@ -269,16 +265,39 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId));
String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts));
long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
getIqnsFromHosts(hosts), volumeIds);
hostIqns, volumeIds);
}
else {
long lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(),
getIqnsFromHosts(hosts), new long[] { sfVolumeId });
long lVagId;
try {
lVagId = SolidFireUtil.createSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), "CloudStack-" + UUID.randomUUID().toString(),
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(hosts, sfConnection);
long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true);
SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
sfVag.getInitiators(), volumeIds);
lVagId = sfVag.getId();
}
clusterDetail = new ClusterDetailsVO(clusterId, getVagKey(storagePoolId), String.valueOf(lVagId));
@ -288,6 +307,48 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return true;
}
// this method takes in a collection of hosts and tries to find an existing VAG that has all three 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 SolidFireUtil.SolidFireVag getCompatibleVag(List<HostVO> hosts, SolidFireConnection sfConnection) {
List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword());
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 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;
}
// get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) // might not exist if using CHAP
// if the VAG exists
// remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup)
@ -314,11 +375,12 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), Long.parseLong(vagId));
String[] hostIqns = getNewHostIqns(sfVag.getInitiators(), getIqnsFromHosts(hosts));
long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false);
SolidFireUtil.modifySolidFireVag(sfConnection.getManagementVip(), sfConnection.getManagementPort(),
sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword(), sfVag.getId(),
getIqnsFromHosts(hosts), volumeIds);
hostIqns, volumeIds);
}
}
@ -336,6 +398,26 @@ public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
return true;
}
private 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]);
}
private long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) {
if (add) {
return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove);

View File

@ -276,8 +276,7 @@ public class SolidFireUtil
}
}
public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword,
String strAccountName)
public static long createSolidFireAccount(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strAccountName)
{
final Gson gson = new GsonBuilder().create();
@ -294,8 +293,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(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lSfAccountId)
{
final Gson gson = new GsonBuilder().create();
@ -316,8 +314,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(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, String strSfAccountName)
{
final Gson gson = new GsonBuilder().create();
@ -338,8 +335,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(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lAccountId)
{
final Gson gson = new GsonBuilder().create();
@ -467,6 +463,33 @@ public class SolidFireUtil
return new SolidFireVag(lVagId, vagIqns, vagVolumeIds);
}
public static List<SolidFireVag> getAllSolidFireVags(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword)
{
final Gson gson = new GsonBuilder().create();
AllVags allVags = new AllVags();
String strAllVagsJson = gson.toJson(allVags);
String strAllVagsGetResultJson = executeJsonRpc(strAllVagsJson, strSfMvip, iSfPort, strSfAdmin, strSfPassword);
VagGetResult allVagsGetResult = gson.fromJson(strAllVagsGetResultJson, VagGetResult.class);
verifyResult(allVagsGetResult.result, strAllVagsGetResultJson, gson);
List<SolidFireVag> lstSolidFireVags = new ArrayList<SolidFireVag>();
if (allVagsGetResult.result.volumeAccessGroups != null ) {
for (VagGetResult.Result.Vag vag : allVagsGetResult.result.volumeAccessGroups) {
SolidFireVag sfVag = new SolidFireVag(vag.volumeAccessGroupID, vag.initiators, vag.volumes);
lstSolidFireVags.add(sfVag);
}
}
return lstSolidFireVags;
}
public static void deleteSolidFireVag(String strSfMvip, int iSfPort, String strSfAdmin, String strSfPassword, long lVagId)
{
final Gson gson = new GsonBuilder().create();
@ -854,6 +877,21 @@ public class SolidFireUtil
}
}
@SuppressWarnings("unused")
private static final class AllVags
{
private final String method = "ListVolumeAccessGroups";
private final VagToGetParams params;
private AllVags()
{
params = new VagToGetParams();
}
private static final class VagToGetParams
{}
}
@SuppressWarnings("unused")
private static final class VagToDelete
{