diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml index f9060809873..0a7c1755588 100644 --- a/plugins/storage/volume/solidfire/pom.xml +++ b/plugins/storage/volume/solidfire/pom.xml @@ -20,6 +20,11 @@ ../../../pom.xml + + com.solidfire + solidfire-sdk-java + 1.2.0.29 + org.apache.cloudstack cloud-plugin-storage-volume-default diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java index 4b02e0ed2d4..bd93abb8d68 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java @@ -133,9 +133,9 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { } private SolidFireUtil.SolidFireAccount createSolidFireAccount(SolidFireUtil.SolidFireConnection sfConnection, String sfAccountName) { - long accountNumber = SolidFireUtil.createSolidFireAccount(sfConnection, sfAccountName); + long accountNumber = SolidFireUtil.createAccount(sfConnection, sfAccountName); - return SolidFireUtil.getSolidFireAccountById(sfConnection, accountNumber); + return SolidFireUtil.getAccountById(sfConnection, accountNumber); } @Override @@ -189,11 +189,11 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); if (vagId != null) { - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); + SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } else { SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, clusterDetailsDao); @@ -241,11 +241,11 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { if (vagId != null) { SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); + SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } } finally { @@ -370,10 +370,10 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { final Iops iops = getIops(minIops, maxIops, storagePoolId); - long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccountId, + long sfVolumeId = SolidFireUtil.createVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccountId, volumeSize, true, mapAttributes, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); - return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); + return SolidFireUtil.getVolume(sfConnection, sfVolumeId); } private Iops getIops(Long minIops, Long maxIops, long storagePoolId) { @@ -415,7 +415,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { try { long lVolumeId = Long.parseLong(volume.getFolder()); - SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, lVolumeId); + SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getVolume(sfConnection, lVolumeId); long volumeSize = sfVolume.getTotalSize(); @@ -626,7 +626,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { if (accountDetail == null || accountDetail.getValue() == null) { AccountVO account = accountDao.findById(csAccountId); String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId()); - SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName); + SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getAccount(sfConnection, sfAccountName); if (sfAccount == null) { sfAccount = createSolidFireAccount(sfConnection, sfAccountName); @@ -778,14 +778,14 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { " and data-object type: " + dataObjectType); } - final long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfNewVolumeName, + final long newSfVolumeId = SolidFireUtil.createClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfNewVolumeName, getVolumeAttributes(volumeInfo)); final Iops iops = getIops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), storagePoolId); - SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + SolidFireUtil.modifyVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); - return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId); + return SolidFireUtil.getVolume(sfConnection, newSfVolumeId); } private Map getVolumeAttributes(VolumeInfo volumeInfo) { @@ -824,9 +824,9 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { long sfSnapshotId = Long.parseLong(snapshotDetails.getValue()); - SolidFireUtil.SolidFireSnapshot sfSnapshot = SolidFireUtil.getSolidFireSnapshot(sfConnection, sfVolumeId, sfSnapshotId); + SolidFireUtil.SolidFireSnapshot sfSnapshot = SolidFireUtil.getSnapshot(sfConnection, sfVolumeId, sfSnapshotId); - long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfSnapshot.getName(), null); + long newSfVolumeId = SolidFireUtil.createClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfSnapshot.getName(), null); snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.STORAGE_POOL_ID); @@ -834,9 +834,9 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { final Iops iops = getIops(MIN_IOPS_FOR_TEMP_VOLUME, MAX_IOPS_FOR_TEMP_VOLUME, storagePoolId); - SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + SolidFireUtil.modifyVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); - return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId); + return SolidFireUtil.getVolume(sfConnection, newSfVolumeId); } private void updateVolumeDetails(long volumeId, long sfVolumeSize) { @@ -900,7 +900,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); - SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); + SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getVolume(sfConnection, sfVolumeId); StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); @@ -928,7 +928,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { String sfNewSnapshotName = volumeInfo.getName() + "-" + snapshotInfo.getUuid(); - long sfNewSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, sfNewSnapshotName, getSnapshotAttributes(snapshotInfo)); + long sfNewSnapshotId = SolidFireUtil.createSnapshot(sfConnection, sfVolumeId, sfNewSnapshotName, getSnapshotAttributes(snapshotInfo)); updateSnapshotDetails(snapshotInfo.getId(), sfVolumeId, sfNewSnapshotId, storagePoolId, sfVolumeSize); @@ -941,10 +941,10 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { final Iops iops = getIops(MIN_IOPS_FOR_SNAPSHOT_VOLUME, MAX_IOPS_FOR_SNAPSHOT_VOLUME, storagePoolId); - long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, sfNewVolumeName, sfVolume.getAccountId(), sfVolumeSize, + long sfNewVolumeId = SolidFireUtil.createVolume(sfConnection, sfNewVolumeName, sfVolume.getAccountId(), sfVolumeSize, sfVolume.isEnable512e(), getSnapshotAttributes(snapshotInfo), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); - SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId); + SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getVolume(sfConnection, sfNewVolumeId); updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn()); @@ -1080,11 +1080,11 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { if (volumeSize > sfVolume.getTotalSize()) { // Expand the volume to include HSR. - SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolume.getId(), volumeSize, getVolumeAttributes(volumeInfo), + SolidFireUtil.modifyVolume(sfConnection, sfVolume.getId(), volumeSize, getVolumeAttributes(volumeInfo), sfVolume.getMinIops(), sfVolume.getMaxIops(), sfVolume.getBurstIops()); // Get the SolidFire volume from the SAN again because we just updated its size. - sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolume.getId()); + sfVolume = SolidFireUtil.getVolume(sfConnection, sfVolume.getId()); } } else { @@ -1143,7 +1143,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { else if (snapshotDetails != null && snapshotDetails.getValue() != null && snapshotDetails.getValue().equalsIgnoreCase("delete")) { snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); - SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(snapshotDetails.getValue())); + SolidFireUtil.deleteVolume(sfConnection, Long.parseLong(snapshotDetails.getValue())); removeTempVolumeId(csSnapshotId); @@ -1200,7 +1200,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { VolumeVO volumeVO = volumeDao.findById(volumeId); - SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(volumeVO.getFolder())); + SolidFireUtil.deleteVolume(sfConnection, Long.parseLong(volumeVO.getFolder())); volumeVO.setFolder(String.valueOf(sfVolumeId)); volumeVO.set_iScsiName(iqn); @@ -1217,7 +1217,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { Preconditions.checkNotNull(sfVolumeId, "'sfVolumeId' should not be 'null'."); - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + SolidFireUtil.deleteVolume(sfConnection, sfVolumeId); volumeDetailsDao.removeDetail(volumeId, BASIC_SF_ID); volumeDetailsDao.removeDetail(volumeId, BASIC_IQN); @@ -1279,7 +1279,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { long sfVolumeId = Long.parseLong(snapshotDetails.getValue()); - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + SolidFireUtil.deleteVolume(sfConnection, sfVolumeId); } snapshotDetailsDao.removeDetails(csSnapshotId); @@ -1306,7 +1306,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { long sfTemplateVolumeId = getVolumeIdFrom_iScsiPath(template.getInstallPath()); - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId); + SolidFireUtil.deleteVolume(sfConnection, sfTemplateVolumeId); VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, template.getId()); @@ -1346,7 +1346,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { ResizeVolumePayload payload = (ResizeVolumePayload)volumeInfo.getpayload(); SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); - SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); + SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getVolume(sfConnection, sfVolumeId); verifySufficientIopsForStoragePool(storagePoolId, volumeInfo.getId(), payload.newMinIops); verifySufficientBytesForStoragePool(storagePoolId, volumeInfo.getId(), payload.newSize, payload.newHypervisorSnapshotReserve); @@ -1375,7 +1375,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId())); mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(payload.newSize)); - SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfNewVolumeSize, mapAttributes, + SolidFireUtil.modifyVolume(sfConnection, sfVolumeId, sfNewVolumeSize, mapAttributes, payload.newMinIops, payload.newMaxIops, getDefaultBurstIops(storagePoolId, payload.newMaxIops)); VolumeVO volume = volumeDao.findById(volumeInfo.getId()); @@ -1481,12 +1481,12 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { } if (deleteVolume) { - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + SolidFireUtil.deleteVolume(sfConnection, sfVolumeId); } } private void deleteSolidFireSnapshot(SolidFireUtil.SolidFireConnection sfConnection, long csSnapshotId, long sfSnapshotId) { - SolidFireUtil.deleteSolidFireSnapshot(sfConnection, sfSnapshotId); + SolidFireUtil.deleteSnapshot(sfConnection, sfSnapshotId); SnapshotVO snapshot = snapshotDao.findById(csSnapshotId); VolumeVO volume = volumeDao.findById(snapshot.getVolumeId()); @@ -1513,7 +1513,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { if (lstSnapshots2.isEmpty()) { volume = volumeDao.findByIdIncludingRemoved(snapshot.getVolumeId()); - SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(volume.getFolder())); + SolidFireUtil.deleteVolume(sfConnection, Long.parseLong(volume.getFolder())); } } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java index 5b620532da8..42fe0256876 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java @@ -261,7 +261,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); long sfTemplateVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath()); - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId); + SolidFireUtil.deleteVolume(sfConnection, sfTemplateVolumeId); } catch (Exception ex) { s_logger.error(ex.getMessage() != null ? ex.getMessage() : "Error deleting SolidFire template volume"); diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java index 6921e4f4872..a1ea9d0006c 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java @@ -343,17 +343,17 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor String sfAccountName = SolidFireUtil.getSolidFireAccountName(accountVo.getUuid(), csAccountId); - SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName); + SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getAccount(sfConnection, sfAccountName); if (sfAccount == null) { - long sfAccountNumber = SolidFireUtil.createSolidFireAccount(sfConnection, sfAccountName); + long sfAccountNumber = SolidFireUtil.createAccount(sfConnection, sfAccountName); - sfAccount = SolidFireUtil.getSolidFireAccountById(sfConnection, sfAccountNumber); + sfAccount = SolidFireUtil.getAccountById(sfConnection, sfAccountNumber); } - long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccount.getId(), volumeSize, + long sfVolumeId = SolidFireUtil.createVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccount.getId(), volumeSize, true, null, minIops, maxIops, burstIops); - SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); + SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getVolume(sfConnection, sfVolumeId); return new SolidFireCreateVolume(sfVolume, sfAccount); } catch (Throwable e) { @@ -596,11 +596,11 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor if (vagId != null) { SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); + SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } } @@ -609,7 +609,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor long sfVolumeId = getVolumeId(storagePoolId); - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + SolidFireUtil.deleteVolume(sfConnection, sfVolumeId); } private long getVolumeId(long storagePoolId) { @@ -691,7 +691,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor } } - SolidFireUtil.modifySolidFireVolume(sfConnection, getVolumeId(storagePool.getId()), size, null, minIops, maxIops, burstIops); + SolidFireUtil.modifyVolume(sfConnection, getVolumeId(storagePool.getId()), size, null, minIops, maxIops, burstIops); SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), _primaryDataStoreDao, _storagePoolDetailsDao, minIops, maxIops, burstIops); } 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 a9c12271206..2caca72794f 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 @@ -16,53 +16,21 @@ // under the License. package org.apache.cloudstack.storage.datastore.util; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; 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.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.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; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.BasicClientConnectionManager; import org.apache.log4j.Logger; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; - import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.utils.security.SSLUtils; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; @@ -76,8 +44,38 @@ import com.cloud.user.AccountDetailsDao; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.primitives.Longs; + +import com.solidfire.client.ElementFactory; +import com.solidfire.element.api.Account; +import com.solidfire.element.api.AddAccountRequest; +import com.solidfire.element.api.CloneVolumeRequest; +import com.solidfire.element.api.CloneVolumeResult; +import com.solidfire.element.api.CreateSnapshotRequest; +import com.solidfire.element.api.CreateVolumeAccessGroupRequest; +import com.solidfire.element.api.CreateVolumeRequest; +import com.solidfire.element.api.DeleteSnapshotRequest; +import com.solidfire.element.api.DeleteVolumeRequest; +import com.solidfire.element.api.GetAccountByIDRequest; +import com.solidfire.element.api.GetAccountByNameRequest; +import com.solidfire.element.api.GetAsyncResultRequest; +import com.solidfire.element.api.ListSnapshotsRequest; +import com.solidfire.element.api.ListVolumeAccessGroupsRequest; +import com.solidfire.element.api.ListVolumesRequest; +import com.solidfire.element.api.ModifyVolumeAccessGroupRequest; +import com.solidfire.element.api.ModifyVolumeRequest; +import com.solidfire.element.api.QoS; +import com.solidfire.element.api.Snapshot; +import com.solidfire.element.api.SolidFireElement; +import com.solidfire.element.api.Volume; +import com.solidfire.element.api.VolumeAccessGroup; +import com.solidfire.jsvcgen.javautil.Optional; + +import static org.apache.commons.lang.ArrayUtils.toPrimitive; + public class SolidFireUtil { private static final Logger s_logger = Logger.getLogger(SolidFireUtil.class); + public static final String PROVIDER_NAME = "SolidFire"; public static final String SHARED_PROVIDER_NAME = "SolidFireShared"; @@ -104,7 +102,8 @@ public class SolidFireUtil { public static final String MAX_IOPS = "maxIops"; public static final String BURST_IOPS = "burstIops"; - public static final String ACCOUNT_ID = "accountId"; + private static final String ACCOUNT_ID = "accountId"; + public static final String VOLUME_ID = "volumeId"; public static final String TEMP_VOLUME_ID = "tempVolumeId"; public static final String SNAPSHOT_ID = "snapshotId"; @@ -120,12 +119,6 @@ public class SolidFireUtil { public static final String STORAGE_POOL_ID = "sfStoragePoolId"; - public static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername"; - public static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret"; - - public static final String CHAP_TARGET_USERNAME = "chapTargetUsername"; - public static final String CHAP_TARGET_SECRET = "chapTargetSecret"; - public static final String DATACENTER = "datacenter"; public static final String DATASTORE_NAME = "datastoreName"; @@ -165,19 +158,19 @@ public class SolidFireUtil { _clusterAdminPassword = clusterAdminPassword; } - public String getManagementVip() { + String getManagementVip() { return _managementVip; } - public int getManagementPort() { + int getManagementPort() { return _managementPort; } - public String getClusterAdminUsername() { + String getClusterAdminUsername() { return _clusterAdminUsername; } - public String getClusterAdminPassword() { + private String getClusterAdminPassword() { return _clusterAdminPassword; } @@ -218,16 +211,97 @@ public class SolidFireUtil { return new SolidFireConnection(mVip, mPort, clusterAdminUsername, clusterAdminPassword); } + private static SolidFireElement getSolidFireElement(SolidFireConnection sfConnection) { + return ElementFactory.create(sfConnection.getManagementVip(), sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword()); + } + + // 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); + } + + 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)) { + return token.substring(index + delimiter2.length()); + } + } + + if (throwExceptionIfNotFound) { + throw new RuntimeException("Key not found in URL"); + } + + return null; + } + 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) { + public static void updateCsDbWithSolidFireIopsInfo(long storagePoolId, PrimaryDataStoreDao primaryDataStoreDao, + StoragePoolDetailsDao storagePoolDetailsDao, long minIops, long maxIops, long burstIops) { Map existingDetails = storagePoolDetailsDao.listDetailsKeyPairs(storagePoolId); Set existingKeys = existingDetails.keySet(); - Map existingDetailsToKeep = new HashMap(); + Map existingDetailsToKeep = new HashMap<>(); for (String existingKey : existingKeys) { String existingValue = existingDetails.get(existingKey); @@ -247,50 +321,25 @@ public class SolidFireUtil { } public static void updateCsDbWithSolidFireAccountInfo(long csAccountId, SolidFireUtil.SolidFireAccount sfAccount, - long storagePoolId, AccountDetailsDao accountDetailsDao) { + 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) { + public static SolidFireAccount getAccount(SolidFireConnection sfConnection, String sfAccountName) { try { - return getSolidFireAccountByName(sfConnection, sfAccountName); + return getAccountByName(sfConnection, sfAccountName); } catch (Exception ex) { return null; } } public static void hostAddedToOrRemovedFromCluster(long hostId, long clusterId, boolean added, String storageProvider, - ClusterDao clusterDao, ClusterDetailsDao clusterDetailsDao, PrimaryDataStoreDao storagePoolDao, StoragePoolDetailsDao storagePoolDetailsDao, HostDao hostDao) { + ClusterDao clusterDao, ClusterDetailsDao clusterDetailsDao, PrimaryDataStoreDao storagePoolDao, + StoragePoolDetailsDao storagePoolDetailsDao, HostDao hostDao) { ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); @@ -307,7 +356,7 @@ public class SolidFireUtil { List storagePools = storagePoolDao.findPoolsByProvider(storageProvider); if (storagePools != null && storagePools.size() > 0) { - List sfConnections = new ArrayList(); + List sfConnections = new ArrayList<>(); for (StoragePoolVO storagePool : storagePools) { ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePool.getId())); @@ -320,7 +369,7 @@ public class SolidFireUtil { if (!sfConnections.contains(sfConnection)) { sfConnections.add(sfConnection); - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); List hostsToAddOrRemove = new ArrayList<>(); HostVO hostToAddOrRemove = hostDao.findByIdIncludingRemoved(hostId); @@ -329,7 +378,7 @@ public class SolidFireUtil { String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hostsToAddOrRemove), added); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, sfVag.getVolumeIds()); + SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), hostIqns, sfVag.getVolumeIds()); } } } @@ -342,7 +391,7 @@ public class SolidFireUtil { } public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId, - String vagUuid, List hosts, ClusterDetailsDao clusterDetailsDao) { + String vagUuid, List hosts, ClusterDetailsDao clusterDetailsDao) { if (hosts == null || hosts.isEmpty()) { throw new CloudRuntimeException("There must be at least one host in the cluster."); } @@ -350,7 +399,7 @@ public class SolidFireUtil { long lVagId; try { - lVagId = SolidFireUtil.createSolidFireVag(sfConnection, "CloudStack-" + vagUuid, + lVagId = SolidFireUtil.createVag(sfConnection, "CloudStack-" + vagUuid, SolidFireUtil.getIqnsFromHosts(hosts), new long[] { sfVolumeId }); } catch (Exception ex) { @@ -367,7 +416,7 @@ public class SolidFireUtil { long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection, lVagId, sfVag.getInitiators(), volumeIds); + SolidFireUtil.modifyVag(sfConnection, lVagId, sfVag.getInitiators(), volumeIds); } ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId)); @@ -391,40 +440,6 @@ public class SolidFireUtil { return true; } - public static String[] getNewHostIqns(String[] iqns, String[] iqnsToAddOrRemove, boolean add) { - if (add) { - return getNewHostIqnsAdd(iqns, iqnsToAddOrRemove); - } - - return getNewHostIqnsRemove(iqns, iqnsToAddOrRemove); - } - - private static String[] getNewHostIqnsAdd(String[] iqns, String[] iqnsToAdd) { - List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); - - if (iqnsToAdd != null) { - for (String iqnToAdd : iqnsToAdd) { - if (!lstIqns.contains(iqnToAdd)) { - lstIqns.add(iqnToAdd); - } - } - } - - return lstIqns.toArray(new String[0]); - } - - private static String[] getNewHostIqnsRemove(String[] iqns, String[] iqnsToRemove) { - List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); - - if (iqnsToRemove != null) { - for (String iqnToRemove : iqnsToRemove) { - lstIqns.remove(iqnToRemove); - } - } - - return lstIqns.toArray(new String[0]); - } - public static long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) { if (add) { return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove); @@ -433,54 +448,6 @@ public class SolidFireUtil { return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove); } - private static long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) { - List lstVolumeIds = new ArrayList(); - - 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 lstVolumeIds = new ArrayList(); - - if (volumeIds != null) { - for (long volumeId : volumeIds) { - lstVolumeIds.add(volumeId); - } - } - - lstVolumeIds.remove(volumeIdToRemove); - - return convertArray(lstVolumeIds); - } - - private static long[] convertArray(List 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; } @@ -499,61 +466,6 @@ public class SolidFireUtil { return accountDetail; } - public static String[] getIqnsFromHosts(List hosts) { - if (hosts == null || hosts.size() == 0) { - throw new CloudRuntimeException("There do not appear to be any hosts in this cluster."); - } - - List lstIqns = new ArrayList(); - - 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 hosts) { - List sfVags = SolidFireUtil.getAllSolidFireVags(sfConnection); - - if (sfVags != null) { - List hostIqns = new ArrayList(); - - // 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 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 getStringArrayAsLowerCaseStringList(String[] aString) { - List lstLowerCaseString = new ArrayList(); - - 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 = "-"; @@ -572,204 +484,50 @@ public class SolidFireUtil { return strSolidFireVolumeName.toString(); } - public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize, - boolean bEnable512e, Map mapAttributes, long minIops, long maxIops, long burstIops) - { - JsonObject volumeToCreate = new JsonObject(); + public static long createVolume(SolidFireConnection sfConnection, String volumeName, long accountId, long totalSize, + boolean enable512e, Map mapAttributes, long minIops, long maxIops, long burstIops) { + CreateVolumeRequest request = CreateVolumeRequest.builder() + .name(volumeName) + .accountID(accountId) + .totalSize(totalSize) + .enable512e(enable512e) + .optionalAttributes(convertMap(mapAttributes)) + .optionalQos(new QoS(Optional.of(minIops), Optional.of(maxIops), Optional.of(burstIops), Optional.EMPTY_LONG)) + .build(); - volumeToCreate.addProperty("method", "CreateVolume"); - - JsonObject params = new JsonObject(); - - volumeToCreate.add("params", params); - - params.addProperty("name", strSfVolumeName); - params.addProperty("accountID", lSfAccountId); - params.addProperty("totalSize", lTotalSize); - params.addProperty("enable512e", bEnable512e); - - JsonObject qos = new JsonObject(); - - params.add("qos", qos); - - qos.addProperty("minIOPS", minIops); - qos.addProperty("maxIOPS", maxIops); - qos.addProperty("burstIOPS", burstIops); - - if (mapAttributes != null && mapAttributes.size() > 0) { - JsonObject attributes = new JsonObject(); - - params.add("attributes", attributes); - - Iterator> itr = mapAttributes.entrySet().iterator(); - - while (itr.hasNext()) { - Map.Entry pair = itr.next(); - - attributes.addProperty(pair.getKey(), pair.getValue()); - } - } - - final Gson gson = new GsonBuilder().create(); - - String strVolumeToCreateJson = gson.toJson(volumeToCreate); - - String strVolumeCreateResultJson = executeJsonRpc(sfConnection, strVolumeToCreateJson); - - VolumeCreateResult volumeCreateResult = gson.fromJson(strVolumeCreateResultJson, VolumeCreateResult.class); - - verifyResult(volumeCreateResult.result, strVolumeCreateResultJson, gson); - - return volumeCreateResult.result.volumeID; + return getSolidFireElement(sfConnection).createVolume(request).getVolumeID(); } - public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, Long totalSize, Map mapAttributes, - long minIops, long maxIops, long burstIops) - { - JsonObject volumeToModify = new JsonObject(); + public static void modifyVolume(SolidFireConnection sfConnection, long volumeId, Long totalSize, Map mapAttributes, + long minIops, long maxIops, long burstIops) { + ModifyVolumeRequest request = ModifyVolumeRequest.builder() + .volumeID(volumeId) + .optionalTotalSize(totalSize) + .optionalAttributes(convertMap(mapAttributes)) + .optionalQos(new QoS(Optional.of(minIops), Optional.of(maxIops), Optional.of(burstIops), Optional.EMPTY_LONG)) + .build(); - volumeToModify.addProperty("method", "ModifyVolume"); - - JsonObject params = new JsonObject(); - - volumeToModify.add("params", params); - - params.addProperty("volumeID", volumeId); - - if (totalSize != null) { - params.addProperty("totalSize", totalSize); - } - - JsonObject qos = new JsonObject(); - - params.add("qos", qos); - - qos.addProperty("minIOPS", minIops); - qos.addProperty("maxIOPS", maxIops); - qos.addProperty("burstIOPS", burstIops); - - if (mapAttributes != null && mapAttributes.size() > 0) { - JsonObject attributes = new JsonObject(); - - params.add("attributes", attributes); - - Iterator> itr = mapAttributes.entrySet().iterator(); - - while (itr.hasNext()) { - Map.Entry pair = itr.next(); - - attributes.addProperty(pair.getKey(), pair.getValue()); - } - } - - final Gson gson = new GsonBuilder().create(); - - 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); - } + getSolidFireElement(sfConnection).modifyVolume(request); } - public static SolidFireVolume getSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) - { - final Gson gson = new GsonBuilder().create(); + public static SolidFireVolume getVolume(SolidFireConnection sfConnection, long volumeId) { + ListVolumesRequest request = ListVolumesRequest.builder() + .optionalStartVolumeID(volumeId) + .optionalLimit(1L) + .build(); - VolumeToGet volumeToGet = new VolumeToGet(lVolumeId); + Volume volume = getSolidFireElement(sfConnection).listVolumes(request).getVolumes()[0]; - String strVolumeToGetJson = gson.toJson(volumeToGet); - - String strVolumeGetResultJson = executeJsonRpc(sfConnection, strVolumeToGetJson); - - VolumeGetResult volumeGetResult = gson.fromJson(strVolumeGetResultJson, VolumeGetResult.class); - - verifyResult(volumeGetResult.result, strVolumeGetResultJson, gson); - - String strVolumeName = getVolumeName(volumeGetResult, lVolumeId); - String strVolumeIqn = getVolumeIqn(volumeGetResult, lVolumeId); - long lAccountId = getVolumeAccountId(volumeGetResult, lVolumeId); - String strVolumeStatus = getVolumeStatus(volumeGetResult, lVolumeId); - boolean enable512e = getVolumeEnable512e(volumeGetResult, lVolumeId); - long lMinIops = getVolumeMinIops(volumeGetResult, lVolumeId); - long lMaxIops = getVolumeMaxIops(volumeGetResult, lVolumeId); - long lBurstIops = getVolumeBurstIops(volumeGetResult, lVolumeId); - long lTotalSize = getVolumeTotalSize(volumeGetResult, lVolumeId); - - return new SolidFireVolume(lVolumeId, strVolumeName, strVolumeIqn, lAccountId, strVolumeStatus, enable512e, - lMinIops, lMaxIops, lBurstIops, lTotalSize); + return new SolidFireVolume(volume.getVolumeID(), volume.getName(), volume.getIqn(), volume.getAccountID(), volume.getStatus(), + volume.getEnable512e(), volume.getQos().getMinIOPS(), volume.getQos().getMaxIOPS(), volume.getQos().getBurstIOPS(), volume.getTotalSize()); } - public static List getSolidFireVolumesForAccountId(SolidFireConnection sfConnection, long lAccountId) { - final Gson gson = new GsonBuilder().create(); + public static void deleteVolume(SolidFireConnection sfConnection, long volumeId) { + DeleteVolumeRequest request = DeleteVolumeRequest.builder() + .volumeID(volumeId) + .build(); - VolumesToGetForAccount volumesToGetForAccount = new VolumesToGetForAccount(lAccountId); - - String strVolumesToGetForAccountJson = gson.toJson(volumesToGetForAccount); - - String strVolumesGetForAccountResultJson = executeJsonRpc(sfConnection, strVolumesToGetForAccountJson); - - VolumeGetResult volumeGetResult = gson.fromJson(strVolumesGetForAccountResultJson, VolumeGetResult.class); - - verifyResult(volumeGetResult.result, strVolumesGetForAccountResultJson, gson); - - List sfVolumes = new ArrayList(); - - for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) { - sfVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.enable512e, - volume.qos.minIOPS, volume.qos.maxIOPS, volume.qos.burstIOPS, volume.totalSize)); - } - - return sfVolumes; - } - - public static List getDeletedVolumes(SolidFireConnection sfConnection) - { - final Gson gson = new GsonBuilder().create(); - - ListDeletedVolumes listDeletedVolumes = new ListDeletedVolumes(); - - String strListDeletedVolumesJson = gson.toJson(listDeletedVolumes); - - String strListDeletedVolumesResultJson = executeJsonRpc(sfConnection, strListDeletedVolumesJson); - - VolumeGetResult volumeGetResult = gson.fromJson(strListDeletedVolumesResultJson, VolumeGetResult.class); - - verifyResult(volumeGetResult.result, strListDeletedVolumesResultJson, gson); - - List deletedVolumes = new ArrayList (); - - for (VolumeGetResult.Result.Volume volume : volumeGetResult.result.volumes) { - deletedVolumes.add(new SolidFireVolume(volume.volumeID, volume.name, volume.iqn, volume.accountID, volume.status, volume.enable512e, - volume.qos.minIOPS, volume.qos.maxIOPS, volume.qos.burstIOPS, volume.totalSize)); - } - - return deletedVolumes; - } - - public static void deleteSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) - { - final Gson gson = new GsonBuilder().create(); - - VolumeToDelete volumeToDelete = new VolumeToDelete(lVolumeId); - - String strVolumeToDeleteJson = gson.toJson(volumeToDelete); - - executeJsonRpc(sfConnection, strVolumeToDeleteJson); - } - - public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) - { - final Gson gson = new GsonBuilder().create(); - - VolumeToPurge volumeToPurge = new VolumeToPurge(lVolumeId); - - String strVolumeToPurgeJson = gson.toJson(volumeToPurge); - - executeJsonRpc(sfConnection, strVolumeToPurgeJson); + getSolidFireElement(sfConnection).deleteVolume(request); } private static final String ACTIVE = "active"; @@ -786,10 +544,8 @@ public class SolidFireUtil { private final long _burstIops; private final long _totalSize; - public SolidFireVolume(long id, String name, String iqn, - long accountId, String status, boolean enable512e, - long minIops, long maxIops, long burstIops, long totalSize) - { + SolidFireVolume(long id, String name, String iqn, long accountId, String status, boolean enable512e, + long minIops, long maxIops, long burstIops, long totalSize) { _id = id; _name = name; _iqn = "/" + iqn + "/0"; @@ -864,21 +620,60 @@ public class SolidFireUtil { SolidFireVolume sfv = (SolidFireVolume)obj; - if (_id == sfv._id && _name.equals(sfv._name) && - _iqn.equals(sfv._iqn) && _accountId == sfv._accountId && - isActive() == sfv.isActive() && getTotalSize() == sfv.getTotalSize()) { - return true; - } - - return false; + return _id == sfv._id && _name.equals(sfv._name) && _iqn.equals(sfv._iqn) && _accountId == sfv._accountId && + isActive() == sfv.isActive() && getTotalSize() == sfv.getTotalSize(); } } + public static long createSnapshot(SolidFireConnection sfConnection, long volumeId, String snapshotName, Map mapAttributes) { + CreateSnapshotRequest request = CreateSnapshotRequest.builder() + .volumeID(volumeId) + .optionalName(snapshotName) + .optionalAttributes(convertMap(mapAttributes)) + .build(); + + return getSolidFireElement(sfConnection).createSnapshot(request).getSnapshotID(); + } + + public static SolidFireSnapshot getSnapshot(SolidFireConnection sfConnection, long volumeId, long snapshotId) { + ListSnapshotsRequest request = ListSnapshotsRequest.builder() + .optionalVolumeID(volumeId) + .build(); + + Snapshot[] snapshots = getSolidFireElement(sfConnection).listSnapshots(request).getSnapshots(); + + String snapshotName = null; + + if (snapshots != null) { + for (Snapshot snapshot : snapshots) { + if (snapshot.getSnapshotID() == snapshotId) { + snapshotName = snapshot.getName(); + + break; + } + } + } + + if (snapshotName == null) { + throw new CloudRuntimeException("Could not find SolidFire snapshot ID: " + snapshotId + " for the following SolidFire volume ID: " + volumeId); + } + + return new SolidFireSnapshot(snapshotId, snapshotName); + } + + public static void deleteSnapshot(SolidFireConnection sfConnection, long snapshotId) { + DeleteSnapshotRequest request = DeleteSnapshotRequest.builder() + .snapshotID(snapshotId) + .build(); + + getSolidFireElement(sfConnection).deleteSnapshot(request); + } + public static class SolidFireSnapshot { private final long _id; private final String _name; - public SolidFireSnapshot(long id, String name) { + SolidFireSnapshot(long id, String name) { _id = id; _name = name; } @@ -892,159 +687,28 @@ public class SolidFireUtil { } } - public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName, Map mapAttributes) { - JsonObject snapshotToCreate = new JsonObject(); + public static long createClone(SolidFireConnection sfConnection, long volumeId, long snapshotId, long accountId, + String cloneName, Map mapAttributes) { + CloneVolumeRequest request = CloneVolumeRequest.builder() + .volumeID(volumeId) + .optionalSnapshotID(snapshotId < 1 ? null : snapshotId) + .optionalNewAccountID(accountId) + .name(cloneName) + .optionalAttributes(convertMap(mapAttributes)) + .build(); - snapshotToCreate.addProperty("method", "CreateSnapshot"); - - JsonObject params = new JsonObject(); - - snapshotToCreate.add("params", params); - - params.addProperty("volumeID", lVolumeId); - params.addProperty("name", snapshotName); - - if (mapAttributes != null && mapAttributes.size() > 0) { - JsonObject attributes = new JsonObject(); - - params.add("attributes", attributes); - - Iterator> itr = mapAttributes.entrySet().iterator(); - - while (itr.hasNext()) { - Map.Entry pair = itr.next(); - - attributes.addProperty(pair.getKey(), pair.getValue()); - } - } - - final Gson gson = new GsonBuilder().create(); - - 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 SolidFireSnapshot getSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId) { - final Gson gson = new GsonBuilder().create(); - - SnapshotsToGet snapshotsToGet = new SnapshotsToGet(lVolumeId); - - String strSnapshotsToGetJson = gson.toJson(snapshotsToGet); - - String strSnapshotsGetResultJson = executeJsonRpc(sfConnection, strSnapshotsToGetJson); - - SnapshotsGetResult snapshotsGetResult = gson.fromJson(strSnapshotsGetResultJson, SnapshotsGetResult.class); - - verifyResult(snapshotsGetResult.result, strSnapshotsGetResultJson, gson); - - String snapshotName = null; - - if (snapshotsGetResult.result.snapshots != null) { - for (SnapshotsGetResult.Result.Snapshot snapshot : snapshotsGetResult.result.snapshots) { - if (snapshot.snapshotID == lSnapshotId) { - snapshotName = snapshot.name; - - break; - } - } - } - - if (snapshotName == null) { - throw new CloudRuntimeException("Could not find SolidFire snapshot ID: " + lSnapshotId + " for the following SolidFire volume ID: " + lVolumeId); - } - - return new SolidFireSnapshot(lSnapshotId, snapshotName); - } - - 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 void rollBackVolumeToSnapshot(SolidFireConnection sfConnection, long volumeId, long snapshotId) { - final Gson gson = new GsonBuilder().create(); - - RollbackToInitiate rollbackToInitiate = new RollbackToInitiate(volumeId, snapshotId); - - String strRollbackToInitiateJson = gson.toJson(rollbackToInitiate); - - String strRollbackInitiatedResultJson = executeJsonRpc(sfConnection, strRollbackToInitiateJson); - - RollbackInitiatedResult rollbackInitiatedResult = gson.fromJson(strRollbackInitiatedResultJson, RollbackInitiatedResult.class); - - verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson); - } - - public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, long sfAccountId, - String cloneName, Map mapAttributes) { - JsonObject cloneToCreate = new JsonObject(); - - cloneToCreate.addProperty("method", "CloneVolume"); - - JsonObject params = new JsonObject(); - - cloneToCreate.add("params", params); - - params.addProperty("volumeID", lVolumeId); - - if (lSnapshotId > 0) { - params.addProperty("snapshotID", lSnapshotId); - } - - params.addProperty("newAccountID", sfAccountId); - params.addProperty("name", cloneName); - - if (mapAttributes != null && mapAttributes.size() > 0) { - JsonObject attributes = new JsonObject(); - - params.add("attributes", attributes); - - Iterator> itr = mapAttributes.entrySet().iterator(); - - while (itr.hasNext()) { - Map.Entry pair = itr.next(); - - attributes.addProperty(pair.getKey(), pair.getValue()); - } - } - - final Gson gson = new GsonBuilder().create(); - - String strCloneToCreateJson = gson.toJson(cloneToCreate); - - String strCloneCreateResultJson = executeJsonRpc(sfConnection, strCloneToCreateJson); - - CloneCreateResult cloneCreateResult = gson.fromJson(strCloneCreateResultJson, CloneCreateResult.class); - - verifyResult(cloneCreateResult.result, strCloneCreateResultJson, gson); + CloneVolumeResult result = getSolidFireElement(sfConnection).cloneVolume(request); // Clone is an async operation. Poll until we get data. - AsyncJobToPoll asyncJobToPoll = new AsyncJobToPoll(cloneCreateResult.result.asyncHandle); - - String strAsyncJobToPollJson = gson.toJson(asyncJobToPoll); + GetAsyncResultRequest asyncResultRequest = GetAsyncResultRequest.builder() + .asyncHandle(result.getAsyncHandle()) + .build(); do { - String strAsyncJobResultJson = executeJsonRpc(sfConnection, strAsyncJobToPollJson); + String status = getSolidFireElement(sfConnection).getAsyncResult(asyncResultRequest).getStatus(); - AsyncJobResult asyncJobResult = gson.fromJson(strAsyncJobResultJson, AsyncJobResult.class); - - verifyResult(asyncJobResult.result, strAsyncJobResultJson, gson); - - if (asyncJobResult.result.status.equals("complete")) { + if (status.equals("complete")) { break; } @@ -1057,87 +721,52 @@ public class SolidFireUtil { } while (true); - return cloneCreateResult.result.volumeID; + return result.getVolumeID(); } - public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName) - { - final Gson gson = new GsonBuilder().create(); + public static long createAccount(SolidFireConnection sfConnection, String accountName) { + AddAccountRequest request = AddAccountRequest.builder() + .username(accountName) + .build(); - AccountToAdd accountToAdd = new AccountToAdd(strAccountName); - - String strAccountAddJson = gson.toJson(accountToAdd); - - String strAccountAddResultJson = executeJsonRpc(sfConnection, strAccountAddJson); - - AccountAddResult accountAddResult = gson.fromJson(strAccountAddResultJson, AccountAddResult.class); - - verifyResult(accountAddResult.result, strAccountAddResultJson, gson); - - return accountAddResult.result.accountID; + return getSolidFireElement(sfConnection).addAccount(request).getAccountID(); } - public static SolidFireAccount getSolidFireAccountById(SolidFireConnection sfConnection, long lSfAccountId) - { - final Gson gson = new GsonBuilder().create(); + public static SolidFireAccount getAccountById(SolidFireConnection sfConnection, long accountId) { + GetAccountByIDRequest request = GetAccountByIDRequest.builder() + .accountID(accountId) + .build(); - AccountToGetById accountToGetById = new AccountToGetById(lSfAccountId); + Account sfAccount = getSolidFireElement(sfConnection).getAccountByID(request).getAccount(); - String strAccountToGetByIdJson = gson.toJson(accountToGetById); + String sfAccountName = sfAccount.getUsername(); + String sfAccountInitiatorSecret = sfAccount.getInitiatorSecret().isPresent() ? sfAccount.getInitiatorSecret().get().toString() : ""; + String sfAccountTargetSecret = sfAccount.getTargetSecret().isPresent() ? sfAccount.getTargetSecret().get().toString() : ""; - String strAccountGetByIdResultJson = executeJsonRpc(sfConnection, strAccountToGetByIdJson); - - AccountGetResult accountGetByIdResult = gson.fromJson(strAccountGetByIdResultJson, AccountGetResult.class); - - verifyResult(accountGetByIdResult.result, strAccountGetByIdResultJson, gson); - - String strSfAccountName = accountGetByIdResult.result.account.username; - String strSfAccountInitiatorSecret = accountGetByIdResult.result.account.initiatorSecret; - String strSfAccountTargetSecret = accountGetByIdResult.result.account.targetSecret; - - return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret); + return new SolidFireAccount(accountId, sfAccountName, sfAccountInitiatorSecret, sfAccountTargetSecret); } - public static SolidFireAccount getSolidFireAccountByName(SolidFireConnection sfConnection, String strSfAccountName) - { - final Gson gson = new GsonBuilder().create(); + private static SolidFireAccount getAccountByName(SolidFireConnection sfConnection, String accountName) { + GetAccountByNameRequest request = GetAccountByNameRequest.builder() + .username(accountName) + .build(); - AccountToGetByName accountToGetByName = new AccountToGetByName(strSfAccountName); + Account sfAccount = getSolidFireElement(sfConnection).getAccountByName(request).getAccount(); - String strAccountToGetByNameJson = gson.toJson(accountToGetByName); + long sfAccountId = sfAccount.getAccountID(); + String sfAccountInitiatorSecret = sfAccount.getInitiatorSecret().isPresent() ? sfAccount.getInitiatorSecret().get().toString() : ""; + String sfAccountTargetSecret = sfAccount.getTargetSecret().isPresent() ? sfAccount.getTargetSecret().get().toString() : ""; - String strAccountGetByNameResultJson = executeJsonRpc(sfConnection, strAccountToGetByNameJson); - - AccountGetResult accountGetByNameResult = gson.fromJson(strAccountGetByNameResultJson, AccountGetResult.class); - - verifyResult(accountGetByNameResult.result, strAccountGetByNameResultJson, gson); - - long lSfAccountId = accountGetByNameResult.result.account.accountID; - String strSfAccountInitiatorSecret = accountGetByNameResult.result.account.initiatorSecret; - String strSfAccountTargetSecret = accountGetByNameResult.result.account.targetSecret; - - return new SolidFireAccount(lSfAccountId, strSfAccountName, strSfAccountInitiatorSecret, strSfAccountTargetSecret); + return new SolidFireAccount(sfAccountId, accountName, sfAccountInitiatorSecret, sfAccountTargetSecret); } - public static void deleteSolidFireAccount(SolidFireConnection sfConnection, long lAccountId) - { - final Gson gson = new GsonBuilder().create(); - - AccountToRemove accountToRemove = new AccountToRemove(lAccountId); - - String strAccountToRemoveJson = gson.toJson(accountToRemove); - - executeJsonRpc(sfConnection, strAccountToRemoveJson); - } - - public static class SolidFireAccount - { + public static class SolidFireAccount { private final long _id; private final String _name; private final String _initiatorSecret; private final String _targetSecret; - public SolidFireAccount(long id, String name, String initiatorSecret, String targetSecret) { + SolidFireAccount(long id, String name, String initiatorSecret, String targetSecret) { _id = id; _name = name; _initiatorSecret = initiatorSecret; @@ -1152,14 +781,6 @@ public class SolidFireUtil { return _name; } - public String getInitiatorSecret() { - return _initiatorSecret; - } - - public String getTargetSecret() { - return _targetSecret; - } - @Override public int hashCode() { return (_id + _name).hashCode(); @@ -1182,84 +803,58 @@ public class SolidFireUtil { SolidFireAccount sfa = (SolidFireAccount)obj; - if (_id == sfa._id && _name.equals(sfa._name) && - _initiatorSecret.equals(sfa._initiatorSecret) && - _targetSecret.equals(sfa._targetSecret)) { - return true; - } - - return false; + return _id == sfa._id && _name.equals(sfa._name) && + _initiatorSecret.equals(sfa._initiatorSecret) && + _targetSecret.equals(sfa._targetSecret); } } - public static long createSolidFireVag(SolidFireConnection sfConnection, String strVagName, - String[] iqns, long[] volumeIds) - { - final Gson gson = new GsonBuilder().create(); + private static long createVag(SolidFireConnection sfConnection, String vagName, String[] iqns, long[] volumeIds) { + CreateVolumeAccessGroupRequest request = CreateVolumeAccessGroupRequest.builder() + .name(vagName) + .optionalInitiators(iqns) + .optionalVolumes(Longs.asList(volumeIds).toArray(new Long[volumeIds.length])) + .build(); - VagToCreate vagToCreate = new VagToCreate(strVagName, iqns, volumeIds); - - String strVagCreateJson = gson.toJson(vagToCreate); - - String strVagCreateResultJson = executeJsonRpc(sfConnection, strVagCreateJson); - - VagCreateResult vagCreateResult = gson.fromJson(strVagCreateResultJson, VagCreateResult.class); - - verifyResult(vagCreateResult.result, strVagCreateResultJson, gson); - - return vagCreateResult.result.volumeAccessGroupID; + return getSolidFireElement(sfConnection).createVolumeAccessGroup(request).getVolumeAccessGroupID(); } - public static void modifySolidFireVag(SolidFireConnection sfConnection, long lVagId, String[] iqns, long[] volumeIds) - { - final Gson gson = new GsonBuilder().create(); + public static void modifyVag(SolidFireConnection sfConnection, long vagId, String[] iqns, long[] volumeIds) { + ModifyVolumeAccessGroupRequest request = ModifyVolumeAccessGroupRequest.builder() + .volumeAccessGroupID(vagId) + .optionalInitiators(iqns) + .optionalVolumes(Longs.asList(volumeIds).toArray(new Long[volumeIds.length])) + .build(); - VagToModify vagToModify = new VagToModify(lVagId, iqns, volumeIds); - - String strVagModifyJson = gson.toJson(vagToModify); - - executeJsonRpc(sfConnection, strVagModifyJson); + getSolidFireElement(sfConnection).modifyVolumeAccessGroup(request); } - public static SolidFireVag getSolidFireVag(SolidFireConnection sfConnection, long lVagId) + public static SolidFireVag getVag(SolidFireConnection sfConnection, long vagId) { - final Gson gson = new GsonBuilder().create(); + ListVolumeAccessGroupsRequest request = ListVolumeAccessGroupsRequest.builder() + .optionalStartVolumeAccessGroupID(vagId) + .optionalLimit(1L) + .build(); - VagToGet vagToGet = new VagToGet(lVagId); + VolumeAccessGroup vag = getSolidFireElement(sfConnection).listVolumeAccessGroups(request).getVolumeAccessGroups()[0]; - String strVagToGetJson = gson.toJson(vagToGet); + String[] vagIqns = vag.getInitiators(); + long[] vagVolumeIds = toPrimitive(vag.getVolumes()); - String strVagGetResultJson = executeJsonRpc(sfConnection, strVagToGetJson); - - VagGetResult vagGetResult = gson.fromJson(strVagGetResultJson, VagGetResult.class); - - verifyResult(vagGetResult.result, strVagGetResultJson, gson); - - String[] vagIqns = getVagIqns(vagGetResult, lVagId); - long[] vagVolumeIds = getVagVolumeIds(vagGetResult, lVagId); - - return new SolidFireVag(lVagId, vagIqns, vagVolumeIds); + return new SolidFireVag(vagId, vagIqns, vagVolumeIds); } - public static List getAllSolidFireVags(SolidFireConnection sfConnection) + private static List getAllVags(SolidFireConnection sfConnection) { - final Gson gson = new GsonBuilder().create(); + ListVolumeAccessGroupsRequest request = ListVolumeAccessGroupsRequest.builder().build(); - AllVags allVags = new AllVags(); + VolumeAccessGroup[] vags = getSolidFireElement(sfConnection).listVolumeAccessGroups(request).getVolumeAccessGroups(); - String strAllVagsJson = gson.toJson(allVags); + List lstSolidFireVags = new ArrayList<>(); - String strAllVagsGetResultJson = executeJsonRpc(sfConnection, strAllVagsJson); - - VagGetResult allVagsGetResult = gson.fromJson(strAllVagsGetResultJson, VagGetResult.class); - - verifyResult(allVagsGetResult.result, strAllVagsGetResultJson, gson); - - List lstSolidFireVags = new ArrayList(); - - if (allVagsGetResult.result.volumeAccessGroups != null ) { - for (VagGetResult.Result.Vag vag : allVagsGetResult.result.volumeAccessGroups) { - SolidFireVag sfVag = new SolidFireVag(vag.volumeAccessGroupID, vag.initiators, vag.volumes); + if (vags != null) { + for (VolumeAccessGroup vag : vags) { + SolidFireVag sfVag = new SolidFireVag(vag.getVolumeAccessGroupID(), vag.getInitiators(), toPrimitive(vag.getVolumes())); lstSolidFireVags.add(sfVag); } @@ -1268,42 +863,26 @@ public class SolidFireUtil { return lstSolidFireVags; } - public static void deleteSolidFireVag(SolidFireConnection sfConnection, long lVagId) - { - final Gson gson = new GsonBuilder().create(); - - VagToDelete vagToDelete = new VagToDelete(lVagId); - - String strVagToDeleteJson = gson.toJson(vagToDelete); - - executeJsonRpc(sfConnection, strVagToDeleteJson); - } - - public static class SolidFireVag - { + public static class SolidFireVag { private final long _id; private final String[] _initiators; private final long[] _volumeIds; - public SolidFireVag(long id, String[] initiators, long[] volumeIds) - { + SolidFireVag(long id, String[] initiators, long[] volumeIds) { _id = id; _initiators = initiators; _volumeIds = volumeIds; } - public long getId() - { + public long getId() { return _id; } - public String[] getInitiators() - { + public String[] getInitiators() { return _initiators; } - public long[] getVolumeIds() - { + public long[] getVolumeIds() { return _volumeIds; } @@ -1327,780 +906,12 @@ public class SolidFireUtil { return false; } - SolidFireVag sfvag = (SolidFireVag)obj; + SolidFireVag sfVag = (SolidFireVag)obj; - if (_id == sfvag._id) { - return true; - } - - return false; + return _id == sfVag._id; } } - @SuppressWarnings("unused") - private static final class VolumeToGet - { - private final String method = "ListActiveVolumes"; - private final VolumeToGetParams params; - - private VolumeToGet(final long lVolumeId) - { - params = new VolumeToGetParams(lVolumeId); - } - - private static final class VolumeToGetParams - { - private final long startVolumeID; - private final long limit = 1; - - private VolumeToGetParams(final long lVolumeId) - { - startVolumeID = lVolumeId; - } - } - } - - @SuppressWarnings("unused") - private static final class VolumesToGetForAccount - { - private final String method = "ListVolumesForAccount"; - private final VolumesToGetForAccountParams params; - - private VolumesToGetForAccount(final long lAccountId) - { - params = new VolumesToGetForAccountParams(lAccountId); - } - - private static final class VolumesToGetForAccountParams - { - private final long accountID; - - private VolumesToGetForAccountParams(final long lAccountId) - { - accountID = lAccountId; - } - } - } - - @SuppressWarnings("unused") - private static final class ListDeletedVolumes - { - private final String method = "ListDeletedVolumes"; - } - - @SuppressWarnings("unused") - private static final class VolumeToDelete - { - private final String method = "DeleteVolume"; - private final VolumeToDeleteParams params; - - private VolumeToDelete(final long lVolumeId) { - params = new VolumeToDeleteParams(lVolumeId); - } - - private static final class VolumeToDeleteParams { - private final long volumeID; - - private VolumeToDeleteParams(final long lVolumeId) { - volumeID = lVolumeId; - } - } - } - - @SuppressWarnings("unused") - private static final class VolumeToPurge - { - private final String method = "PurgeDeletedVolume"; - private final VolumeToPurgeParams params; - - private VolumeToPurge(final long lVolumeId) { - params = new VolumeToPurgeParams(lVolumeId); - } - - private static final class VolumeToPurgeParams { - private final long volumeID; - - private VolumeToPurgeParams(final long lVolumeId) { - volumeID = lVolumeId; - } - } - } - - @SuppressWarnings("unused") - private static final class SnapshotsToGet - { - private final String method = "ListSnapshots"; - private final SnapshotsToGetParams params; - - private SnapshotsToGet(final long lVolumeId) { - params = new SnapshotsToGetParams(lVolumeId); - } - - private static final class SnapshotsToGetParams { - private final long volumeID; - - private SnapshotsToGetParams(final long lVolumeId) { - volumeID = lVolumeId; - } - } - } - - @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 final long snapshotID; - - private SnapshotToDeleteParams(final long lSnapshotId) { - snapshotID = lSnapshotId; - } - } - } - - @SuppressWarnings("unused") - private static final class RollbackToInitiate { - private final String method = "RollbackToSnapshot"; - private final RollbackToInitiateParams params; - - private RollbackToInitiate(final long lVolumeId, final long lSnapshotId) { - params = new RollbackToInitiateParams(lVolumeId, lSnapshotId); - } - - private static final class RollbackToInitiateParams { - private final long volumeID; - private final long snapshotID; - - private RollbackToInitiateParams(final long lVolumeId, final long lSnapshotId) { - volumeID = lVolumeId; - snapshotID = lSnapshotId; - } - } - } - - @SuppressWarnings("unused") - private static final class AccountToAdd - { - private final String method = "AddAccount"; - private final AccountToAddParams params; - - private AccountToAdd(final String strAccountName) - { - params = new AccountToAddParams(strAccountName); - } - - private static final class AccountToAddParams - { - private final String username; - - private AccountToAddParams(final String strAccountName) - { - username = strAccountName; - } - } - } - - @SuppressWarnings("unused") - private static final class AccountToGetById - { - private final String method = "GetAccountByID"; - private final AccountToGetByIdParams params; - - private AccountToGetById(final long lAccountId) - { - params = new AccountToGetByIdParams(lAccountId); - } - - private static final class AccountToGetByIdParams - { - private final long accountID; - - private AccountToGetByIdParams(final long lAccountId) - { - accountID = lAccountId; - } - } - } - - @SuppressWarnings("unused") - private static final class AccountToGetByName - { - private final String method = "GetAccountByName"; - private final AccountToGetByNameParams params; - - private AccountToGetByName(final String strUsername) - { - params = new AccountToGetByNameParams(strUsername); - } - - private static final class AccountToGetByNameParams - { - private final String username; - - private AccountToGetByNameParams(final String strUsername) - { - username = strUsername; - } - } - } - - @SuppressWarnings("unused") - private static final class AccountToRemove { - private final String method = "RemoveAccount"; - private final AccountToRemoveParams params; - - private AccountToRemove(final long lAccountId) { - params = new AccountToRemoveParams(lAccountId); - } - - private static final class AccountToRemoveParams { - private final long accountID; - - private AccountToRemoveParams(final long lAccountId) { - accountID = lAccountId; - } - } - } - - @SuppressWarnings("unused") - private static final class VagToCreate - { - private final String method = "CreateVolumeAccessGroup"; - private final VagToCreateParams params; - - private VagToCreate(final String strVagName, final String[] iqns, final long[] volumeIds) - { - params = new VagToCreateParams(strVagName, iqns, volumeIds); - } - - private static final class VagToCreateParams - { - private final String name; - private final String[] initiators; - private final long[] volumes; - - private VagToCreateParams(final String strVagName, final String[] iqns, final long[] volumeIds) - { - name = strVagName; - initiators = iqns; - volumes = volumeIds; - } - } - } - - @SuppressWarnings("unused") - private static final class VagToModify - { - private final String method = "ModifyVolumeAccessGroup"; - private final VagToModifyParams params; - - private VagToModify(final long lVagName, final String[] iqns, final long[] volumeIds) - { - params = new VagToModifyParams(lVagName, iqns, volumeIds); - } - - private static final class VagToModifyParams - { - private final long volumeAccessGroupID; - private final String[] initiators; - private final long[] volumes; - - private VagToModifyParams(final long lVagName, final String[] iqns, final long[] volumeIds) - { - volumeAccessGroupID = lVagName; - initiators = iqns; - volumes = volumeIds; - } - } - } - - @SuppressWarnings("unused") - private static final class VagToGet - { - private final String method = "ListVolumeAccessGroups"; - private final VagToGetParams params; - - private VagToGet(final long lVagId) - { - params = new VagToGetParams(lVagId); - } - - private static final class VagToGetParams - { - private final long startVolumeAccessGroupID; - private final long limit = 1; - - private VagToGetParams(final long lVagId) - { - startVolumeAccessGroupID = lVagId; - } - } - } - - @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 - { - private final String method = "DeleteVolumeAccessGroup"; - private final VagToDeleteParams params; - - private VagToDelete(final long lVagId) { - params = new VagToDeleteParams(lVagId); - } - - private static final class VagToDeleteParams { - private final long volumeAccessGroupID; - - private VagToDeleteParams(final long lVagId) { - volumeAccessGroupID = lVagId; - } - } - } - - @SuppressWarnings("unused") - private static final class AsyncJobToPoll - { - private final String method = "GetAsyncResult"; - private final AsyncJobToPollParams params; - - private AsyncJobToPoll(final long asyncHandle) - { - params = new AsyncJobToPollParams(asyncHandle); - } - - private static final class AsyncJobToPollParams - { - private final long asyncHandle; - - private AsyncJobToPollParams(final long asyncHandle) - { - this.asyncHandle = asyncHandle; - } - } - } - - private static final class VolumeCreateResult { - private Result result; - - private static final class Result { - private long volumeID; - } - } - - private static final class VolumeGetResult { - private Result result; - - private static final class Result { - private Volume[] volumes; - - private static final class Volume { - private long volumeID; - private String name; - private String iqn; - private long accountID; - private String status; - private boolean enable512e; - private Qos qos; - private long totalSize; - - private static final class Qos { - private long minIOPS; - private long maxIOPS; - private long burstIOPS; - } - } - } - } - - private static final class SnapshotCreateResult { - private Result result; - - private static final class Result { - private long snapshotID; - } - } - - private static final class SnapshotsGetResult { - private Result result; - - private static final class Result { - private Snapshot[] snapshots; - - private static final class Snapshot { - private long snapshotID; - private String name; - } - } - } - - @SuppressWarnings("unused") - private static final class RollbackInitiatedResult { - private Result result; - - private static final class Result { - private long snapshotID; - } - } - - private static final class CloneCreateResult { - private Result result; - - private static final class Result { - private long volumeID; - private long asyncHandle; - } - } - - private static final class AccountAddResult { - private Result result; - - private static final class Result { - private long accountID; - } - } - - private static final class AccountGetResult { - private Result result; - - private static final class Result { - private Account account; - - private static final class Account { - private long accountID; - private String username; - private String initiatorSecret; - private String targetSecret; - } - } - } - - private static final class VagCreateResult { - private Result result; - - private static final class Result { - private long volumeAccessGroupID; - } - } - - private static final class VagGetResult - { - private Result result; - - private static final class Result - { - private Vag[] volumeAccessGroups; - - private static final class Vag - { - private long volumeAccessGroupID; - private String[] initiators; - private long[] volumes; - } - } - } - - private static final class AsyncJobResult { - private AsyncResult result; - - private static final class AsyncResult - { - private String status; - } - } - - private static final class JsonError - { - private Error error; - - private static final class Error { - private String message; - } - } - - private static DefaultHttpClient getHttpClient(int iPort) { - try { - SSLContext sslContext = SSLUtils.getSSLContext(); - 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()); - - SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - SchemeRegistry registry = new SchemeRegistry(); - - registry.register(new Scheme("https", iPort, socketFactory)); - - BasicClientConnectionManager mgr = new BasicClientConnectionManager(registry); - DefaultHttpClient client = new DefaultHttpClient(); - - return new DefaultHttpClient(mgr, client.getParams()); - } catch (NoSuchAlgorithmException ex) { - throw new CloudRuntimeException(ex.getMessage()); - } catch (KeyManagementException ex) { - throw new CloudRuntimeException(ex.getMessage()); - } - } - - private static String executeJsonRpc(SolidFireConnection sfConnection, String strJsonToExecute) { - DefaultHttpClient httpClient = null; - StringBuilder sb = new StringBuilder(); - - try { - StringEntity input = new StringEntity(strJsonToExecute); - - input.setContentType("application/json"); - - httpClient = getHttpClient(sfConnection.getManagementPort()); - - 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(sfConnection.getClusterAdminUsername(), sfConnection.getClusterAdminPassword()); - - httpClient.getCredentialsProvider().setCredentials(authScope, credentials); - - HttpPost postRequest = new HttpPost(uri); - - postRequest.setEntity(input); - - HttpResponse response = httpClient.execute(postRequest); - - if (!isSuccess(response.getStatusLine().getStatusCode())) { - throw new CloudRuntimeException("Failed on JSON-RPC API call. HTTP error code = " + response.getStatusLine().getStatusCode()); - } - - try(BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));) { - String strOutput; - while ((strOutput = br.readLine()) != null) { - sb.append(strOutput); - } - }catch (IOException ex) { - throw new CloudRuntimeException(ex.getMessage()); - } - } catch (UnsupportedEncodingException ex) { - throw new CloudRuntimeException(ex.getMessage()); - } catch (ClientProtocolException ex) { - throw new CloudRuntimeException(ex.getMessage()); - } catch (IOException ex) { - throw new CloudRuntimeException(ex.getMessage()); - } catch (URISyntaxException ex) { - throw new CloudRuntimeException(ex.getMessage()); - } finally { - if (httpClient != null) { - try { - httpClient.getConnectionManager().shutdown(); - } catch (Exception t) { - s_logger.info("[ignored]" - + "error shutting down http client: " + t.getLocalizedMessage()); - } - } - } - - return sb.toString(); - } - - private static boolean isSuccess(int iCode) { - return iCode >= 200 && iCode < 300; - } - - 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) { - 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) { - 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) { - 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) { - 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) { - return volumeGetResult.result.volumes[0].status; - } - - throw new CloudRuntimeException("Could not determine the status of the volume for volume ID of " + lVolumeId + "."); - } - - private static boolean getVolumeEnable512e(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].enable512e; - } - - throw new CloudRuntimeException("Could not determine the enable 512 emulation of the volume for volume ID of " + lVolumeId + "."); - } - - private static long getVolumeMinIops(VolumeGetResult volumeGetResult, long lVolumeId) - { - if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && - volumeGetResult.result.volumes[0].volumeID == lVolumeId && volumeGetResult.result.volumes[0].qos != null) - { - return volumeGetResult.result.volumes[0].qos.minIOPS; - } - - throw new CloudRuntimeException("Could not determine the min IOPS of the volume for volume ID of " + lVolumeId + "."); - } - - private static long getVolumeMaxIops(VolumeGetResult volumeGetResult, long lVolumeId) - { - if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && - volumeGetResult.result.volumes[0].volumeID == lVolumeId && volumeGetResult.result.volumes[0].qos != null) - { - return volumeGetResult.result.volumes[0].qos.maxIOPS; - } - - throw new CloudRuntimeException("Could not determine the max IOPS of the volume for volume ID of " + lVolumeId + "."); - } - - private static long getVolumeBurstIops(VolumeGetResult volumeGetResult, long lVolumeId) - { - if (volumeGetResult.result.volumes != null && volumeGetResult.result.volumes.length == 1 && - volumeGetResult.result.volumes[0].volumeID == lVolumeId && volumeGetResult.result.volumes[0].qos != null) - { - return volumeGetResult.result.volumes[0].qos.burstIOPS; - } - - throw new CloudRuntimeException("Could not determine the burst IOPS of the volume for volume ID of " + lVolumeId + "."); - } - - private static long getVolumeTotalSize(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].totalSize; - } - - throw new CloudRuntimeException("Could not determine the total size of the volume for volume ID of " + lVolumeId + "."); - } - - private static String[] getVagIqns(VagGetResult vagGetResult, long lVagId) - { - if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 && - vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId) - { - return vagGetResult.result.volumeAccessGroups[0].initiators; - } - - throw new CloudRuntimeException("Could not determine the IQNs of the volume access group for volume access group ID of " + lVagId + "."); - } - - private static long[] getVagVolumeIds(VagGetResult vagGetResult, long lVagId) - { - if (vagGetResult.result.volumeAccessGroups != null && vagGetResult.result.volumeAccessGroups.length == 1 && - vagGetResult.result.volumeAccessGroups[0].volumeAccessGroupID == lVagId) - { - return vagGetResult.result.volumeAccessGroups[0].volumes; - } - - 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 = ":"; @@ -2137,38 +948,136 @@ public class SolidFireUtil { return portNumber; } - public static String getValue(String keyToMatch, String url) { - return getValue(keyToMatch, url, true); + private static String[] getNewHostIqns(String[] iqns, String[] iqnsToAddOrRemove, boolean add) { + if (add) { + return getNewHostIqnsAdd(iqns, iqnsToAddOrRemove); + } + + return getNewHostIqnsRemove(iqns, iqnsToAddOrRemove); } - public static String getValue(String keyToMatch, String url, boolean throwExceptionIfNotFound) { - String delimiter1 = ";"; - String delimiter2 = "="; + private static String[] getNewHostIqnsAdd(String[] iqns, String[] iqnsToAdd) { + List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); - 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 (iqnsToAdd != null) { + for (String iqnToAdd : iqnsToAdd) { + if (!lstIqns.contains(iqnToAdd)) { + lstIqns.add(iqnToAdd); + } } } - if (throwExceptionIfNotFound) { - throw new RuntimeException("Key not found in URL"); + return lstIqns.toArray(new String[0]); + } + + private static String[] getNewHostIqnsRemove(String[] iqns, String[] iqnsToRemove) { + List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); + + if (iqnsToRemove != null) { + for (String iqnToRemove : iqnsToRemove) { + lstIqns.remove(iqnToRemove); + } } - return null; + return lstIqns.toArray(new String[0]); + } + + private static long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) { + List lstVolumeIds = new ArrayList<>(); + + if (volumeIds != null) { + for (long volumeId : volumeIds) { + lstVolumeIds.add(volumeId); + } + } + + if (lstVolumeIds.contains(volumeIdToAdd)) { + return volumeIds; + } + + lstVolumeIds.add(volumeIdToAdd); + + return toPrimitive(lstVolumeIds.toArray(new Long[lstVolumeIds.size()])); + } + + private static long[] getNewVolumeIdsRemove(long[] volumeIds, long volumeIdToRemove) { + List lstVolumeIds = new ArrayList<>(); + + if (volumeIds != null) { + for (long volumeId : volumeIds) { + lstVolumeIds.add(volumeId); + } + } + + lstVolumeIds.remove(volumeIdToRemove); + + return toPrimitive(lstVolumeIds.toArray(new Long[lstVolumeIds.size()])); + } + + private static String[] getIqnsFromHosts(List hosts) { + if (hosts == null || hosts.size() == 0) { + throw new CloudRuntimeException("There do not appear to be any hosts in this cluster."); + } + + List lstIqns = new ArrayList<>(); + + 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 hosts) { + List sfVags = SolidFireUtil.getAllVags(sfConnection); + + if (sfVags != null) { + List hostIqns = new ArrayList<>(); + + // 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 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 getStringArrayAsLowerCaseStringList(String[] aString) { + List lstLowerCaseString = new ArrayList<>(); + + if (aString != null) { + for (String str : aString) { + if (str != null) { + lstLowerCaseString.add(str.toLowerCase()); + } + } + } + + return lstLowerCaseString; + } + + private static Map convertMap(Map map) { + if (map == null) { + return null; + } + + Map convertedMap = new HashMap<>(); + + convertedMap.putAll(map); + + return convertedMap; } } diff --git a/test/integration/plugins/solidfire/TestAddRemoveHosts.py b/test/integration/plugins/solidfire/TestAddRemoveHosts.py index 4c3d261f6e1..366c127f9ae 100644 --- a/test/integration/plugins/solidfire/TestAddRemoveHosts.py +++ b/test/integration/plugins/solidfire/TestAddRemoveHosts.py @@ -42,14 +42,19 @@ from marvin.lib.utils import cleanup_resources # Prerequisites: # Only one zone # Only one pod -# Only one cluster (two hosts with another added/removed during the tests) +# Only one cluster (two hosts for XenServer / one host for KVM with another added/removed during the tests) # # Running the tests: -# Set a breakpoint on each test after the first one. When the breakpoint is hit, reset the third +# Change the "hypervisor_type" variable to control which hypervisor type to test. +# If using XenServer, set a breakpoint on each test after the first one. When the breakpoint is hit, reset the added/removed # host to a snapshot state and re-start it. Once it's up and running, run the test code. +# Check that ip_address_of_new_xenserver_host / ip_address_of_new_kvm_host is correct. +# If using XenServer, verify the "xen_server_master_hostname" variable is correct. +# If using KVM, verify the "kvm_1_ip_address" variable is correct. class TestData: + #constants account = "account" capacityBytes = "capacitybytes" capacityIops = "capacityiops" @@ -59,9 +64,11 @@ class TestData: diskSize = "disksize" domainId = "domainId" hypervisor = "hypervisor" + kvm = "kvm" mvip = "mvip" name = "name" - newHost = "newHost" + newXenServerHost = "newXenServerHost" + newKvmHost = "newKvmHost" newHostDisplayName = "newHostDisplayName" password = "password" podId = "podid" @@ -75,7 +82,6 @@ class TestData: storageTag2 = "SolidFire_Volume_1" tags = "tags" url = "url" - urlOfNewHost = "urlOfNewHost" user = "user" username = "username" virtualMachine = "virtualmachine" @@ -83,6 +89,13 @@ class TestData: xenServer = "xenserver" zoneId = "zoneid" + # modify to control which hypervisor type to test + hypervisor_type = xenServer + xen_server_master_hostname = "XenServer-6.5-1" + kvm_1_ip_address = "192.168.129.84" + ip_address_of_new_xenserver_host = "192.168.129.243" + ip_address_of_new_kvm_host = "192.168.129.3" + def __init__(self): self.testdata = { TestData.solidFire: { @@ -92,11 +105,14 @@ class TestData: TestData.port: 443, TestData.url: "https://192.168.139.112:443" }, + TestData.kvm: { + TestData.username: "root", + TestData.password: "solidfire" + }, TestData.xenServer: { TestData.username: "root", TestData.password: "solidfire" }, - TestData.urlOfNewHost: "https://192.168.129.243", TestData.account: { "email": "test@test.com", "firstname": "John", @@ -111,10 +127,17 @@ class TestData: TestData.username: "testuser", TestData.password: "password" }, - TestData.newHost: { + TestData.newXenServerHost: { TestData.username: "root", TestData.password: "solidfire", - TestData.url: "http://192.168.129.243", + TestData.url: "http://" + TestData.ip_address_of_new_xenserver_host, + TestData.podId : "1", + TestData.zoneId: "1" + }, + TestData.newKvmHost: { + TestData.username: "root", + TestData.password: "solidfire", + TestData.url: "http://" + TestData.ip_address_of_new_kvm_host, TestData.podId : "1", TestData.zoneId: "1" }, @@ -164,9 +187,6 @@ class TestData: TestData.volume_1: { "diskname": "testvolume", }, - "volume2": { - "diskname": "testvolume2", - }, TestData.newHostDisplayName: "XenServer-6.5-3", TestData.zoneId: 1, TestData.clusterId: 1, @@ -190,16 +210,10 @@ class TestAddRemoveHosts(cloudstackTestCase): cls.testdata = TestData().testdata - cls.xs_pool_master_ip = list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress + if TestData.hypervisor_type == TestData.xenServer: + cls.xs_pool_master_ip = list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name=TestData.xen_server_master_hostname)[0].ipaddress - # Set up XenAPI connection - host_ip = "https://" + cls.xs_pool_master_ip - - cls.xen_session = XenAPI.Session(host_ip) - - xenserver = cls.testdata[TestData.xenServer] - - cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + cls._connect_to_hypervisor() # Set up SolidFire connection solidfire = cls.testdata[TestData.solidFire] @@ -296,13 +310,20 @@ class TestAddRemoveHosts(cloudstackTestCase): startvm=True ) - root_volume = self._get_root_volume(self.virtual_machine) + if TestData.hypervisor_type == TestData.xenServer: + root_volume = self._get_root_volume(self.virtual_machine) - sf_iscsi_name = sf_util.get_iqn(self.cs_api, root_volume, self) - - self._perform_add_remove_host(primary_storage.id, sf_iscsi_name) + sf_iscsi_name = sf_util.get_iqn(self.cs_api, root_volume, self) + self._perform_add_remove_xenserver_host(primary_storage.id, sf_iscsi_name) + elif TestData.hypervisor_type == TestData.kvm: + self._perform_add_remove_kvm_host(primary_storage.id) + else: + self.assertTrue(False, "Invalid hypervisor type") def test_add_remove_host_with_solidfire_plugin_2(self): + if TestData.hypervisor_type != TestData.xenServer: + return + primarystorage2 = self.testdata[TestData.primaryStorage2] primary_storage_2 = StoragePool.create( @@ -322,9 +343,12 @@ class TestAddRemoveHosts(cloudstackTestCase): sf_iscsi_name = self._get_iqn_2(primary_storage_2) - self._perform_add_remove_host(primary_storage_2.id, sf_iscsi_name) + self._perform_add_remove_xenserver_host(primary_storage_2.id, sf_iscsi_name) def test_add_remove_host_with_solidfire_plugin_3(self): + if TestData.hypervisor_type != TestData.xenServer: + return + primarystorage = self.testdata[TestData.primaryStorage] primary_storage = StoragePool.create( @@ -373,9 +397,12 @@ class TestAddRemoveHosts(cloudstackTestCase): self.cleanup.append(primary_storage_2) - self._perform_add_remove_host(primary_storage.id, sf_iscsi_name) + self._perform_add_remove_xenserver_host(primary_storage.id, sf_iscsi_name) def test_add_remove_host_with_solidfire_plugin_4(self): + if TestData.hypervisor_type != TestData.xenServer: + return + primarystorage2 = self.testdata[TestData.primaryStorage2] primary_storage_2 = StoragePool.create( @@ -422,9 +449,9 @@ class TestAddRemoveHosts(cloudstackTestCase): startvm=True ) - self._perform_add_remove_host(primary_storage_2.id, sf_iscsi_name) + self._perform_add_remove_xenserver_host(primary_storage_2.id, sf_iscsi_name) - def _perform_add_remove_host(self, primary_storage_id, sr_name): + def _perform_add_remove_xenserver_host(self, primary_storage_id, sr_name): xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sr_name)[0] pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr) @@ -435,7 +462,7 @@ class TestAddRemoveHosts(cloudstackTestCase): sf_vag_id = self._get_sf_vag_id(self.cluster.id, primary_storage_id) - host_iscsi_iqns = self._get_host_iscsi_iqns() + host_iscsi_iqns = self._get_xenserver_host_iscsi_iqns() sf_vag = self._get_sf_vag(sf_vag_id) @@ -445,7 +472,7 @@ class TestAddRemoveHosts(cloudstackTestCase): sf_vag_initiators_len_orig = len(sf_vag_initiators) - xen_session = XenAPI.Session(self.testdata[TestData.urlOfNewHost]) + xen_session = XenAPI.Session("https://" + TestData.ip_address_of_new_xenserver_host) xenserver = self.testdata[TestData.xenServer] @@ -482,7 +509,7 @@ class TestAddRemoveHosts(cloudstackTestCase): host = Host.create( self.apiClient, self.cluster, - self.testdata[TestData.newHost], + self.testdata[TestData.newXenServerHost], hypervisor="XenServer" ) @@ -501,7 +528,7 @@ class TestAddRemoveHosts(cloudstackTestCase): self._verify_all_pbds_attached(pbds) - host_iscsi_iqns = self._get_host_iscsi_iqns() + host_iscsi_iqns = self._get_xenserver_host_iscsi_iqns() sf_vag = self._get_sf_vag(sf_vag_id) @@ -529,7 +556,7 @@ class TestAddRemoveHosts(cloudstackTestCase): self._verify_all_pbds_attached(pbds) - host_iscsi_iqns = self._get_host_iscsi_iqns() + host_iscsi_iqns = self._get_xenserver_host_iscsi_iqns() sf_vag = self._get_sf_vag(sf_vag_id) @@ -557,7 +584,81 @@ class TestAddRemoveHosts(cloudstackTestCase): self._verify_all_pbds_attached(pbds) - host_iscsi_iqns = self._get_host_iscsi_iqns() + host_iscsi_iqns = self._get_xenserver_host_iscsi_iqns() + + sf_vag = self._get_sf_vag(sf_vag_id) + + sf_vag_initiators = self._get_sf_vag_initiators(sf_vag) + + self._verifyVag(host_iscsi_iqns, sf_vag_initiators) + + sf_vag_initiators_len_new = len(sf_vag_initiators) + + self.assertEqual( + sf_vag_initiators_len_new, + sf_vag_initiators_len_orig, + "sf_vag_initiators_len_new' != sf_vag_initiators_len_orig" + ) + + def _perform_add_remove_kvm_host(self, primary_storage_id): + sf_vag_id = self._get_sf_vag_id(self.cluster.id, primary_storage_id) + + kvm_login = self.testdata[TestData.kvm] + + kvm_hosts = [] + + kvm_hosts.append(TestData.kvm_1_ip_address) + + host_iscsi_iqns = self._get_kvm_host_iscsi_iqns(kvm_hosts, kvm_login[TestData.username], kvm_login[TestData.password]) + + sf_vag = self._get_sf_vag(sf_vag_id) + + sf_vag_initiators = self._get_sf_vag_initiators(sf_vag) + + self._verifyVag(host_iscsi_iqns, sf_vag_initiators) + + sf_vag_initiators_len_orig = len(sf_vag_initiators) + + host = Host.create( + self.apiClient, + self.cluster, + self.testdata[TestData.newKvmHost], + hypervisor="KVM" + ) + + self.assertTrue( + isinstance(host, Host), + "'host' is not a 'Host'." + ) + + kvm_hosts = [] + + kvm_hosts.append(TestData.kvm_1_ip_address) + kvm_hosts.append(TestData.ip_address_of_new_kvm_host) + + host_iscsi_iqns = self._get_kvm_host_iscsi_iqns(kvm_hosts, kvm_login[TestData.username], kvm_login[TestData.password]) + + sf_vag = self._get_sf_vag(sf_vag_id) + + sf_vag_initiators = self._get_sf_vag_initiators(sf_vag) + + self._verifyVag(host_iscsi_iqns, sf_vag_initiators) + + sf_vag_initiators_len_new = len(sf_vag_initiators) + + self.assertEqual( + sf_vag_initiators_len_new, + sf_vag_initiators_len_orig + 1, + "sf_vag_initiators_len_new' != sf_vag_initiators_len_orig + 1" + ) + + host.delete(self.apiClient) + + kvm_hosts = [] + + kvm_hosts.append(TestData.kvm_1_ip_address) + + host_iscsi_iqns = self._get_kvm_host_iscsi_iqns(kvm_hosts, kvm_login[TestData.username], kvm_login[TestData.password]) sf_vag = self._get_sf_vag(sf_vag_id) @@ -616,7 +717,7 @@ class TestAddRemoveHosts(cloudstackTestCase): return sql_result[0][0] - def _get_host_iscsi_iqns(self): + def _get_xenserver_host_iscsi_iqns(self): hosts = self.xen_session.xenapi.host.get_all() self.assertEqual( @@ -628,15 +729,41 @@ class TestAddRemoveHosts(cloudstackTestCase): host_iscsi_iqns = [] for host in hosts: - host_iscsi_iqns.append(self._get_host_iscsi_iqn(host)) + host_iscsi_iqns.append(self._get_xenserver_host_iscsi_iqn(host)) return host_iscsi_iqns - def _get_host_iscsi_iqn(self, host): + def _get_xenserver_host_iscsi_iqn(self, host): other_config = self.xen_session.xenapi.host.get_other_config(host) return other_config["iscsi_iqn"] + def _get_kvm_host_iscsi_iqns(self, kvm_ip_addresses, common_username, common_password): + host_iscsi_iqns = [] + + for kvm_ip_address in kvm_ip_addresses: + host_iscsi_iqn = self._get_kvm_iqn(kvm_ip_address, common_username, common_password) + + host_iscsi_iqns.append(host_iscsi_iqn) + + return host_iscsi_iqns + + def _get_kvm_iqn(self, ip_address, username, password): + ssh_connection = sf_util.get_ssh_connection(ip_address, username, password) + + searchFor = "InitiatorName=" + + stdin, stdout, stderr = ssh_connection.exec_command("sudo grep " + searchFor + " /etc/iscsi/initiatorname.iscsi") + + result = stdout.read() + + ssh_connection.close() + + self.assertFalse(result is None, "Unable to locate the IQN of the KVM host (None)") + self.assertFalse(len(result.strip()) == 0, "Unable to locate the IQN of the KVM host (Zero-length string)") + + return result[len(searchFor):].strip() + def _get_sf_vag_id(self, cluster_id, primary_storage_id): # Get SF Volume Access Group ID sf_vag_id_request = {'clusterid': cluster_id, 'storageid': primary_storage_id} @@ -679,3 +806,18 @@ class TestAddRemoveHosts(cloudstackTestCase): for host_iscsi_iqn in host_iscsi_iqns: # an error should occur if host_iscsi_iqn is not in sf_vag_initiators sf_vag_initiators.index(host_iscsi_iqn) + + @classmethod + def _connect_to_hypervisor(cls): + if TestData.hypervisor_type == TestData.kvm: + pass + elif TestData.hypervisor_type == TestData.xenServer: + host_ip = "https://" + \ + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name=TestData.xen_server_master_hostname)[0].ipaddress + + cls.xen_session = XenAPI.Session(host_ip) + + xen_server = cls.testdata[TestData.xenServer] + + cls.xen_session.xenapi.login_with_password(xen_server[TestData.username], xen_server[TestData.password]) + diff --git a/test/integration/plugins/solidfire/TestManagedSystemVMs.py b/test/integration/plugins/solidfire/TestManagedSystemVMs.py index 7e3facaab27..a3343c745f1 100644 --- a/test/integration/plugins/solidfire/TestManagedSystemVMs.py +++ b/test/integration/plugins/solidfire/TestManagedSystemVMs.py @@ -29,8 +29,6 @@ from marvin.cloudstackAPI import destroySystemVm # All tests inherit from cloudstackTestCase from marvin.cloudstackTestCase import cloudstackTestCase -from nose.plugins.attrib import attr - # Import Integration Libraries # base - contains all resources as entities and defines create, delete, list operations on them @@ -50,12 +48,17 @@ from marvin.lib.utils import cleanup_resources, wait_until # * Only one secondary storage VM and one console proxy VM running on NFS (no virtual router or user VMs exist) # * Only one pod # * Only one cluster -# * Set storage.cleanup.enabled to true -# * Set storage.cleanup.interval to 150 -# * Set storage.cleanup.delay to 60 +# +# Running the tests: +# Change the "hypervisor_type" variable to control which hypervisor type to test. +# If using XenServer, verify the "xen_server_hostname" variable is correct. +# Set the Global Setting "storage.cleanup.enabled" to true. +# Set the Global Setting "storage.cleanup.interval" to 150. +# Set the Global Setting "storage.cleanup.delay" to 60. class TestData(): + # constants account = "account" capacityBytes = "capacitybytes" capacityIops = "capacityiops" @@ -66,6 +69,7 @@ class TestData(): email = "email" firstname = "firstname" hypervisor = "hypervisor" + kvm = "kvm" lastname = "lastname" max_iops = "maxiops" min_iops = "miniops" @@ -88,6 +92,10 @@ class TestData(): xenServer = "xenserver" zoneId = "zoneid" + # modify to control which hypervisor type to test + hypervisor_type = kvm + xen_server_hostname = "XenServer-6.5-1" + def __init__(self): self.testdata = { TestData.solidFire: { @@ -97,6 +105,10 @@ class TestData(): TestData.port: 443, TestData.url: "https://192.168.139.112:443" }, + TestData.kvm: { + TestData.username: "root", + TestData.password: "solidfire" + }, TestData.xenServer: { TestData.username: "root", TestData.password: "solidfire" @@ -203,16 +215,7 @@ class TestManagedSystemVMs(cloudstackTestCase): cls.testdata = TestData().testdata - # Set up xenAPI connection - host_ip = "https://" + \ - list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress - - # Set up XenAPI connection - cls.xen_session = XenAPI.Session(host_ip) - - xenserver = cls.testdata[TestData.xenServer] - - cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + cls._connect_to_hypervisor() # Set up SolidFire connection solidfire = cls.testdata[TestData.solidFire] @@ -306,7 +309,6 @@ class TestManagedSystemVMs(cloudstackTestCase): except Exception as e: logging.debug("Exception in tearDownClass(self): %s" % e) - @attr(hypervisor='XenServer') def test_01_create_system_vms_on_managed_storage(self): self._disable_zone_and_delete_system_vms(None, False) @@ -387,7 +389,6 @@ class TestManagedSystemVMs(cloudstackTestCase): self._wait_for_and_get_running_system_vms(2) - @attr(hypervisor='XenServer') def test_02_failure_to_create_service_offering_with_customized_iops(self): try: ServiceOffering.create( @@ -477,9 +478,19 @@ class TestManagedSystemVMs(cloudstackTestCase): "The volume should not be in a volume access group." ) - sr_name = sf_util.format_iqn(sf_root_volume.iqn) + if TestData.hypervisor_type == TestData.xenServer: + sr_name = sf_util.format_iqn(sf_root_volume.iqn) - sf_util.check_xen_sr(sr_name, self.xen_session, self, False) + sf_util.check_xen_sr(sr_name, self.xen_session, self, False) + elif TestData.hypervisor_type == TestData.kvm: + list_hosts_response = list_hosts( + self.apiClient, + type="Routing" + ) + + sf_util.check_kvm_access_to_volume(sf_root_volume.iqn, list_hosts_response, self.testdata[TestData.kvm], self, False) + else: + self.assertTrue(False, "Invalid hypervisor type") def _wait_for_and_get_running_system_vms(self, expected_number_of_system_vms): retry_interval = 60 @@ -523,9 +534,19 @@ class TestManagedSystemVMs(cloudstackTestCase): sf_util.check_vag(sf_root_volume, sf_vag_id, self) - sr_name = sf_util.format_iqn(sf_root_volume.iqn) + if TestData.hypervisor_type == TestData.xenServer: + sr_name = sf_util.format_iqn(sf_root_volume.iqn) - sf_util.check_xen_sr(sr_name, self.xen_session, self) + sf_util.check_xen_sr(sr_name, self.xen_session, self) + elif TestData.hypervisor_type == TestData.kvm: + list_hosts_response = list_hosts( + self.apiClient, + type="Routing" + ) + + sf_util.check_kvm_access_to_volume(sf_root_volume.iqn, list_hosts_response, self.testdata[TestData.kvm], self) + else: + self.assertTrue(False, "Invalid hypervisor type") def _check_iops_against_iops_of_system_offering(self, cs_volume, system_offering): self.assertEqual( @@ -586,3 +607,17 @@ class TestManagedSystemVMs(cloudstackTestCase): # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench self.dbConnection.execute(sql_query) + @classmethod + def _connect_to_hypervisor(cls): + if TestData.hypervisor_type == TestData.kvm: + pass + elif TestData.hypervisor_type == TestData.xenServer: + host_ip = "https://" + \ + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name=TestData.xen_server_hostname)[0].ipaddress + + cls.xen_session = XenAPI.Session(host_ip) + + xen_server = cls.testdata[TestData.xenServer] + + cls.xen_session.xenapi.login_with_password(xen_server[TestData.username], xen_server[TestData.password]) + diff --git a/test/integration/plugins/solidfire/TestSnapshots.py b/test/integration/plugins/solidfire/TestSnapshots.py index df45c6134d1..e1b9aafc10c 100644 --- a/test/integration/plugins/solidfire/TestSnapshots.py +++ b/test/integration/plugins/solidfire/TestSnapshots.py @@ -45,9 +45,14 @@ from marvin.lib.utils import cleanup_resources, wait_until # Only one zone # Only one pod # Only one cluster +# +# Running the tests: +# Change the "hypervisor_type" variable to control which hypervisor type to test. +# If using KVM, set the Global Setting "kvm.snapshot.enabled" equal to true. class TestData(): + # constants account = "account" capacityBytes = "capacitybytes" capacityIops = "capacityiops" @@ -57,6 +62,7 @@ class TestData(): diskOffering = "diskoffering" domainId = "domainId" hypervisor = "hypervisor" + kvm = "kvm" mvip = "mvip" password = "password" port = "port" @@ -75,6 +81,9 @@ class TestData(): xenServer = "xenserver" zoneId = "zoneId" + # modify to control which hypervisor type to test + hypervisor_type = xenServer + def __init__(self): self.testdata = { TestData.solidFire: { @@ -84,31 +93,6 @@ class TestData(): TestData.port: 443, TestData.url: "https://192.168.139.112:443" }, - TestData.xenServer: { - TestData.username: "root", - TestData.password: "solidfire" - }, - TestData.account: { - "email": "test@test.com", - "firstname": "John", - "lastname": "Doe", - "username": "test", - "password": "test" - }, - "testaccount": { - "email": "test2@test2.com", - "firstname": "Jane", - "lastname": "Doe", - TestData.username: "test2", - TestData.password: "test" - }, - TestData.user: { - "email": "user@test.com", - "firstname": "Jane", - "lastname": "Doe", - TestData.username: "testuser", - TestData.password: "password" - }, TestData.primaryStorage: { "name": "SolidFire-%d" % random.randint(0, 100), TestData.scope: "ZONE", @@ -122,6 +106,20 @@ class TestData(): TestData.capacityBytes: 2251799813685248, TestData.hypervisor: "Any" }, + TestData.account: { + "email": "test@test.com", + "firstname": "John", + "lastname": "Doe", + "username": "test", + "password": "test" + }, + TestData.user: { + "email": "user@test.com", + "firstname": "Jane", + "lastname": "Doe", + TestData.username: "testuser", + TestData.password: "password" + }, TestData.virtualMachine: { "name": "TestVM", "displayname": "Test VM" @@ -150,71 +148,6 @@ class TestData(): TestData.tags: TestData.storageTag, "storagetype": "shared" }, - "testdiskofferings": { - "customiopsdo": { - "name": "SF_Custom_Iops_DO", - "displaytext": "Customized Iops DO", - "disksize": 128, - "customizediops": True, - "miniops": 500, - "maxiops": 1000, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "customsizedo": { - "name": "SF_Custom_Size_DO", - "displaytext": "Customized Size DO", - "disksize": 175, - "customizediops": False, - "miniops": 500, - "maxiops": 1000, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "customsizeandiopsdo": { - "name": "SF_Custom_Iops_Size_DO", - "displaytext": "Customized Size and Iops DO", - "disksize": 200, - "customizediops": True, - "miniops": 400, - "maxiops": 800, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "newiopsdo": { - "name": "SF_New_Iops_DO", - "displaytext": "New Iops (min=350, max = 700)", - "disksize": 128, - "miniops": 350, - "maxiops": 700, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "newsizedo": { - "name": "SF_New_Size_DO", - "displaytext": "New Size: 175", - "disksize": 175, - "miniops": 400, - "maxiops": 800, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - }, - "newsizeandiopsdo": { - "name": "SF_New_Size_Iops_DO", - "displaytext": "New Size and Iops", - "disksize": 200, - "miniops": 200, - "maxiops": 400, - "hypervisorsnapshotreserve": 200, - TestData.tags: TestData.storageTag, - "storagetype": "shared" - } - }, TestData.volume_1: { TestData.diskName: "test-volume", }, @@ -256,17 +189,6 @@ class TestSnapshots(cloudstackTestCase): cls.testdata = TestData().testdata - # Set up xenAPI connection - host_ip = "https://" + \ - list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress - - # Set up XenAPI connection - cls.xen_session = XenAPI.Session(host_ip) - - xenserver = cls.testdata[TestData.xenServer] - - cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) - # Set up SolidFire connection solidfire = cls.testdata[TestData.solidFire] @@ -349,9 +271,9 @@ class TestSnapshots(cloudstackTestCase): def tearDown(self): cleanup_resources(self.apiClient, self.cleanup) - @attr(hypervisor='XenServer') def test_01_create_volume_snapshot_using_sf_snapshot(self): - sf_util.set_supports_resign(True, self.dbConnection) + if TestData.hypervisor_type == TestData.xenServer: + sf_util.set_supports_resign(True, self.dbConnection) virtual_machine = VirtualMachine.create( self.apiClient, @@ -599,6 +521,9 @@ class TestSnapshots(cloudstackTestCase): @attr(hypervisor='XenServer') def test_02_create_volume_snapshot_using_sf_volume(self): + if TestData.hypervisor_type != TestData.xenServer: + return + sf_util.set_supports_resign(False, self.dbConnection) virtual_machine = VirtualMachine.create( @@ -955,6 +880,9 @@ class TestSnapshots(cloudstackTestCase): @attr(hypervisor='XenServer') def test_03_create_volume_snapshot_using_sf_volume_and_sf_snapshot(self): + if TestData.hypervisor_type != TestData.xenServer: + return + sf_util.set_supports_resign(False, self.dbConnection) virtual_machine = VirtualMachine.create( @@ -1185,6 +1113,9 @@ class TestSnapshots(cloudstackTestCase): @attr(hypervisor='XenServer') def test_04_create_volume_snapshot_using_sf_snapshot_and_archiving(self): + if TestData.hypervisor_type != TestData.xenServer: + return + sf_util.set_supports_resign(True, self.dbConnection) virtual_machine = VirtualMachine.create( @@ -1439,6 +1370,72 @@ class TestSnapshots(cloudstackTestCase): sf_util.check_list(sf_volumes, 0, self, TestSnapshots._should_be_zero_volumes_in_list_err_msg) + @attr(hypervisor='KVM') + def test_05_create_volume_snapshot_using_sf_snapshot_and_revert_volume_to_snapshot(self): + if TestData.hypervisor_type != TestData.kvm: + return + + virtual_machine = VirtualMachine.create( + self.apiClient, + self.testdata[TestData.virtualMachine], + accountid=self.account.name, + zoneid=self.zone.id, + serviceofferingid=self.compute_offering.id, + templateid=self.template.id, + domainid=self.domain.id, + startvm=True + ) + + list_volumes_response = list_volumes( + self.apiClient, + virtualmachineid=virtual_machine.id, + listall=True + ) + + sf_util.check_list(list_volumes_response, 1, self, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + vm_1_root_volume = list_volumes_response[0] + vm_1_root_volume_name = vm_1_root_volume.name + + sf_account_id = sf_util.get_sf_account_id(self.cs_api, self.account.id, self.primary_storage.id, self, TestSnapshots._sf_account_id_should_be_non_zero_int_err_msg) + + # Get volume information from SolidFire cluster + sf_volumes = sf_util.get_active_sf_volumes(self.sfe, sf_account_id) + + sf_util.check_list(sf_volumes, 1, self, TestSnapshots._should_only_be_one_volume_in_list_err_msg) + + sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name) + + # Get snapshot information for volume from SolidFire cluster + sf_snapshots = self.sfe.list_snapshots(volume_id=sf_volume.volume_id).snapshots + + sf_util.check_list(sf_snapshots, 0, self, TestSnapshots._should_be_zero_snapshots_in_list_err_msg) + + primary_storage_db_id = self._get_cs_storage_pool_db_id(self.primary_storage) + + vol_snap_1 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg) + + vol_snap_2 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg) + + virtual_machine.stop(self.apiClient, False) + + Volume.revertToSnapshot(self.apiClient, vol_snap_1.id) + + virtual_machine.start(self.apiClient) + + try: + Volume.revertToSnapshot(self.apiClient, vol_snap_1.id) + + self.assertTrue(False, "An exception should have been thrown when trying to revert a volume to a snapshot and the volume is attached to a running VM.") + except: + pass + + self._delete_and_test_snapshot(vol_snap_2) + + self._delete_and_test_snapshot(vol_snap_1) + + virtual_machine.delete(self.apiClient, True) + def _check_list_not_empty(self, in_list): self.assertEqual( isinstance(in_list, list), @@ -1636,7 +1633,7 @@ class TestSnapshots(cloudstackTestCase): vol_snap = Snapshot.create( self.apiClient, volume_id=volume_id_for_snapshot, - locationtype=2 + locationtype="secondary" ) self._wait_for_snapshot_state(vol_snap.id, Snapshot.BACKED_UP) @@ -1745,3 +1742,4 @@ class TestSnapshots(cloudstackTestCase): sf_volumes = sf_util.get_active_sf_volumes(self.sfe, sf_account_id) sf_util.check_list(sf_volumes, expected_num_volumes, self, volume_err_msg) + diff --git a/test/integration/plugins/solidfire/TestVolumes.py b/test/integration/plugins/solidfire/TestVolumes.py index b70ac915bee..add5ed165e3 100644 --- a/test/integration/plugins/solidfire/TestVolumes.py +++ b/test/integration/plugins/solidfire/TestVolumes.py @@ -18,6 +18,7 @@ import logging import random import SignedAPICall +import time import XenAPI from solidfire.factory import ElementFactory @@ -27,8 +28,6 @@ from util import sf_util # All tests inherit from cloudstackTestCase from marvin.cloudstackTestCase import cloudstackTestCase -from nose.plugins.attrib import attr - # Import Integration Libraries # base - contains all resources as entities and defines create, delete, list operations on them @@ -36,7 +35,7 @@ from marvin.lib.base import Account, DiskOffering, ServiceOffering, StoragePool, # common - commonly used methods for all tests are listed here from marvin.lib.common import get_domain, get_template, get_zone, list_clusters, list_hosts, list_virtual_machines, \ - list_volumes + list_volumes, list_hosts # utils - utility classes for common cleanup, external library wrappers, etc. from marvin.lib.utils import cleanup_resources @@ -47,10 +46,13 @@ from marvin.lib.utils import cleanup_resources # Only one cluster # # Running the tests: -# Change the "supports_resign" variable to True or False as desired. +# Change the "hypervisor_type" variable to control which hypervisor type to test. +# If using XenServer, verify the "xen_server_hostname" variable is correct. +# If using XenServer, change the "supports_cloning" variable to True or False as desired. class TestData(): + # constants account = "account" capacityBytes = "capacitybytes" capacityIops = "capacityiops" @@ -60,6 +62,7 @@ class TestData(): diskOffering = "diskoffering" domainId = "domainId" hypervisor = "hypervisor" + kvm = "kvm" login = "login" mvip = "mvip" password = "password" @@ -70,7 +73,8 @@ class TestData(): solidFire = "solidfire" storageTag = "SolidFire_SAN_1" tags = "tags" - templateCacheName = "centos56-x86-64-xen" + templateCacheNameKvm = "centos55-x86-64" + templateCacheNameXenServer = "centos56-x86-64-xen" testAccount = "testaccount" url = "url" user = "user" @@ -82,6 +86,10 @@ class TestData(): xenServer = "xenserver" zoneId = "zoneId" + # modify to control which hypervisor type to test + hypervisor_type = xenServer + xen_server_hostname = "XenServer-6.5-1" + def __init__(self): self.testdata = { TestData.solidFire: { @@ -91,6 +99,10 @@ class TestData(): TestData.port: 443, TestData.url: "https://192.168.139.112:443" }, + TestData.kvm: { + TestData.username: "root", + TestData.password: "solidfire" + }, TestData.xenServer: { TestData.username: "root", TestData.password: "solidfire" @@ -177,6 +189,7 @@ class TestData(): class TestVolumes(cloudstackTestCase): _should_only_be_one_vm_in_list_err_msg = "There should only be one VM in this list." _should_only_be_one_volume_in_list_err_msg = "There should only be one volume in this list." + _should_only_be_one_host_in_list_err_msg = "There should only be one host in this list." _sf_account_id_should_be_non_zero_int_err_msg = "The SolidFire account ID should be a non-zero integer." _volume_size_should_be_non_zero_int_err_msg = "The SolidFire volume size should be a non-zero integer." _volume_vm_id_and_vm_id_do_not_match_err_msg = "The volume's VM ID and the VM's ID do not match." @@ -189,26 +202,16 @@ class TestVolumes(cloudstackTestCase): def setUpClass(cls): # Set up API client testclient = super(TestVolumes, cls).getClsTestClient() + cls.apiClient = testclient.getApiClient() cls.configData = testclient.getParsedTestDataConfig() cls.dbConnection = testclient.getDbConnection() cls.testdata = TestData().testdata - cls.supports_resign = True + cls._handle_supports_cloning() - sf_util.set_supports_resign(cls.supports_resign, cls.dbConnection) - - # Set up xenAPI connection - host_ip = "https://" + \ - list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress - - # Set up XenAPI connection - cls.xen_session = XenAPI.Session(host_ip) - - xenserver = cls.testdata[TestData.xenServer] - - cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password]) + cls._connect_to_hypervisor() # Set up SolidFire connection solidfire = cls.testdata[TestData.solidFire] @@ -276,9 +279,11 @@ class TestVolumes(cloudstackTestCase): serviceofferingid=cls.compute_offering.id, templateid=cls.template.id, domainid=cls.domain.id, - startvm=True + startvm=False ) + TestVolumes._start_vm(cls.virtual_machine) + cls.volume = Volume.create( cls.apiClient, cls.testdata[TestData.volume_1], @@ -319,14 +324,13 @@ class TestVolumes(cloudstackTestCase): cleanup_resources(self.apiClient, self.cleanup) - @attr(hypervisor='XenServer') def test_00_check_template_cache(self): - if self.supports_resign == False: + if self._supports_cloning == False: return sf_volumes = self._get_active_sf_volumes() - sf_volume = sf_util.check_and_get_sf_volume(sf_volumes, TestData.templateCacheName, self) + sf_volume = sf_util.check_and_get_sf_volume(sf_volumes, self._get_template_cache_name(), self) self.assertEqual( len(sf_volume.volume_access_groups), @@ -346,7 +350,6 @@ class TestVolumes(cloudstackTestCase): "The template cache volume's account does not end with '_1'." ) - @attr(hypervisor='XenServer') def test_01_attach_new_volume_to_stopped_VM(self): '''Attach a volume to a stopped virtual machine, then start VM''' @@ -372,7 +375,7 @@ class TestVolumes(cloudstackTestCase): newvolume = self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName]) - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) vm = self._get_vm(self.virtual_machine.id) @@ -406,7 +409,7 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) # Detach volume new_volume = self.virtual_machine.detach_volume( @@ -414,11 +417,10 @@ class TestVolumes(cloudstackTestCase): new_volume ) - @attr(hypervisor='XenServer') def test_02_attach_detach_attach_volume(self): '''Attach, detach, and attach volume to a running VM''' - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) sf_account_id = sf_util.get_sf_account_id(self.cs_api, self.account.id, self.primary_storage.id, self, TestVolumes._sf_account_id_should_be_non_zero_int_err_msg) @@ -469,7 +471,7 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) ######################################### ######################################### @@ -510,7 +512,7 @@ class TestVolumes(cloudstackTestCase): "The volume should not be in a VAG." ) - self._check_xen_sr(sf_iscsi_name, False) + self._check_host_side(sf_iscsi_name, vm.hostid, False) ####################################### ####################################### @@ -547,13 +549,12 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) - @attr(hypervisor='XenServer') def test_03_attached_volume_reboot_VM(self): '''Attach volume to running VM, then reboot.''' - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) sf_account_id = sf_util.get_sf_account_id(self.cs_api, self.account.id, self.primary_storage.id, self, TestVolumes._sf_account_id_should_be_non_zero_int_err_msg) @@ -604,14 +605,14 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) ####################################### ####################################### # STEP 2: Reboot VM with attached vol # ####################################### ####################################### - self.virtual_machine.reboot(self.apiClient) + TestVolumes._reboot_vm(self.virtual_machine) vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) @@ -631,13 +632,12 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) - @attr(hypervisor='XenServer') def test_04_detach_volume_reboot(self): '''Detach volume from a running VM, then reboot.''' - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) sf_account_id = sf_util.get_sf_account_id(self.cs_api, self.account.id, self.primary_storage.id, self, TestVolumes._sf_account_id_should_be_non_zero_int_err_msg) @@ -688,7 +688,7 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) ######################################### ######################################### @@ -729,7 +729,7 @@ class TestVolumes(cloudstackTestCase): TestVolumes._volume_should_not_be_in_a_vag ) - self._check_xen_sr(sf_iscsi_name, False) + self._check_host_side(sf_iscsi_name, vm.hostid, False) ####################################### ####################################### @@ -753,13 +753,12 @@ class TestVolumes(cloudstackTestCase): TestVolumes._volume_should_not_be_in_a_vag ) - self._check_xen_sr(sf_iscsi_name, False) + self._check_host_side(sf_iscsi_name, vm.hostid, False) - @attr(hypervisor='XenServer') def test_05_detach_vol_stopped_VM_start(self): '''Detach volume from a stopped VM, then start.''' - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) sf_account_id = sf_util.get_sf_account_id(self.cs_api, self.account.id, self.primary_storage.id, self, TestVolumes._sf_account_id_should_be_non_zero_int_err_msg) @@ -810,7 +809,9 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) + + hostid = vm.hostid ######################################### ######################################### @@ -853,7 +854,7 @@ class TestVolumes(cloudstackTestCase): TestVolumes._volume_should_not_be_in_a_vag ) - self._check_xen_sr(sf_iscsi_name, False) + self._check_host_side(sf_iscsi_name, hostid, False) ####################################### ####################################### @@ -861,7 +862,7 @@ class TestVolumes(cloudstackTestCase): ####################################### ####################################### - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) @@ -877,9 +878,8 @@ class TestVolumes(cloudstackTestCase): TestVolumes._volume_should_not_be_in_a_vag ) - self._check_xen_sr(sf_iscsi_name, False) + self._check_host_side(sf_iscsi_name, vm.hostid, False) - @attr(hypervisor='XenServer') def test_06_attach_volume_to_stopped_VM(self): '''Attach a volume to a stopped virtual machine, then start VM''' @@ -934,9 +934,12 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + if TestData.hypervisor_type == TestData.kvm: + self._check_host_side(sf_iscsi_name, None, False) + elif TestData.hypervisor_type == TestData.xenServer: + self._check_host_side(sf_iscsi_name) - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName]) @@ -968,9 +971,8 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) - @attr(hypervisor='XenServer') def test_07_destroy_expunge_VM_with_volume(self): '''Destroy and expunge VM with attached volume''' @@ -988,9 +990,11 @@ class TestVolumes(cloudstackTestCase): serviceofferingid=self.compute_offering.id, templateid=self.template.id, domainid=self.domain.id, - startvm=True + startvm=False ) + TestVolumes._start_vm(test_virtual_machine) + self.volume = test_virtual_machine.attach_volume( self.apiClient, self.volume @@ -1032,7 +1036,9 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) + + hostid = vm.hostid ####################################### ####################################### @@ -1081,13 +1087,12 @@ class TestVolumes(cloudstackTestCase): TestVolumes._volume_should_not_be_in_a_vag ) - self._check_xen_sr(sf_iscsi_name, False) + self._check_host_side(sf_iscsi_name, hostid, False) - @attr(hypervisor='XenServer') def test_08_delete_volume_was_attached(self): '''Delete volume that was attached to a VM and is detached now''' - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) ####################################### ####################################### @@ -1147,7 +1152,7 @@ class TestVolumes(cloudstackTestCase): sf_util.check_vag(sf_volume, sf_vag_id, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) ####################################### ####################################### @@ -1188,7 +1193,7 @@ class TestVolumes(cloudstackTestCase): TestVolumes._volume_should_not_be_in_a_vag ) - self._check_xen_sr(sf_iscsi_name, False) + self._check_host_side(sf_iscsi_name, vm.hostid, False) volume_to_delete_later.delete(self.apiClient) @@ -1207,11 +1212,10 @@ class TestVolumes(cloudstackTestCase): sf_util.check_and_get_sf_volume(sf_volumes, vol.name, self, False) - @attr(hypervisor='XenServer') def test_09_attach_volumes_multiple_accounts(self): '''Attach a data disk to a VM in one account and attach another data disk to a VM in another account''' - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) ####################################### ####################################### @@ -1235,9 +1239,11 @@ class TestVolumes(cloudstackTestCase): serviceofferingid=self.compute_offering.id, templateid=self.template.id, domainid=self.domain.id, - startvm=True + startvm=False ) + TestVolumes._start_vm(test_virtual_machine) + test_volume = Volume.create( self.apiClient, self.testdata[TestData.volume_2], @@ -1315,7 +1321,7 @@ class TestVolumes(cloudstackTestCase): sf_iscsi_name = sf_util.get_iqn(self.cs_api, self.volume, self) - self._check_xen_sr(sf_iscsi_name) + self._check_host_side(sf_iscsi_name, vm.hostid) sf_util.check_vag(sf_volume, sf_vag_id, self) @@ -1333,15 +1339,14 @@ class TestVolumes(cloudstackTestCase): sf_test_iscsi_name = sf_util.get_iqn(self.cs_api, test_volume, self) - self._check_xen_sr(sf_test_iscsi_name) + self._check_host_side(sf_test_iscsi_name, test_vm.hostid) sf_util.check_vag(sf_test_volume, sf_vag_id, self) - @attr(hypervisor='XenServer') def test_10_attach_more_than_one_disk_to_VM(self): '''Attach more than one disk to a VM''' - self.virtual_machine.start(self.apiClient) + TestVolumes._start_vm(self.virtual_machine) volume_2 = Volume.create( self.apiClient, @@ -1398,7 +1403,9 @@ class TestVolumes(cloudstackTestCase): sf_iscsi_name = sf_util.get_iqn(self.cs_api, self.volume, self) - self._check_xen_sr(sf_iscsi_name) + vm = self._get_vm(self.virtual_machine.id) + + self._check_host_side(sf_iscsi_name, vm.hostid) sf_util.check_vag(sf_volume, sf_vag_id, self) @@ -1408,20 +1415,12 @@ class TestVolumes(cloudstackTestCase): sf_iscsi_name_2 = sf_util.get_iqn(self.cs_api, volume_2, self) - self._check_xen_sr(sf_iscsi_name_2) + self._check_host_side(sf_iscsi_name_2, vm.hostid) sf_util.check_vag(sf_volume_2, sf_vag_id, self) self.virtual_machine.detach_volume(self.apiClient, volume_2) - ''' - @attr(hypervisor = 'XenServer') - def test_11_attach_disk_to_running_vm_change_iops(self): - Attach a disk to a running VM, then change iops - self.custom_iops_disk_offering = DiskOffering.create( - - )''' - def _check_volume(self, volume, volume_name): self.assertTrue( volume.name.startswith(volume_name), @@ -1469,6 +1468,9 @@ class TestVolumes(cloudstackTestCase): ); def _get_cs_volume_size_including_hsr_in_bytes(self, cs_volume_size_in_gb, hsr): + if TestData.hypervisor_type == TestData.kvm: + return self._get_bytes_from_gb(cs_volume_size_in_gb) + lowest_hsr = 10 if hsr < lowest_hsr: @@ -1499,3 +1501,98 @@ class TestVolumes(cloudstackTestCase): ) return sf_volumes + + def _get_template_cache_name(self): + if TestData.hypervisor_type == TestData.kvm: + return TestData.templateCacheNameKvm + elif TestData.hypervisor_type == TestData.xenServer: + return TestData.templateCacheNameXenServer + + self.assert_(False, "Invalid hypervisor type") + + def _get_modified_iscsi_name(self, sf_iscsi_name): + sf_iscsi_name = sf_iscsi_name.replace("/", "") + + return sf_iscsi_name[:-1] + + def _check_host_side(self, sf_iscsi_name, vm_hostid=None, should_exist=True): + if TestData.hypervisor_type == TestData.kvm: + self._check_kvm_host_side(self._get_modified_iscsi_name(sf_iscsi_name), vm_hostid, should_exist) + elif TestData.hypervisor_type == TestData.xenServer: + self._check_xen_sr(sf_iscsi_name, should_exist) + + def _check_kvm_host_side(self, sf_iscsi_name, vm_hostid, should_exist=True): + if vm_hostid is None: + list_hosts_response = list_hosts( + self.apiClient, + type="Routing" + ) + else: + list_hosts_response = list_hosts( + self.apiClient, + id=vm_hostid + ) + + sf_util.check_list(list_hosts_response, 1, self, TestVolumes._should_only_be_one_host_in_list_err_msg) + + kvm_login = self.testdata[TestData.kvm] + + for cs_host in list_hosts_response: + ssh_connection = sf_util.get_ssh_connection(cs_host.ipaddress, kvm_login[TestData.username], kvm_login[TestData.password]) + + stdin, stdout, stderr = ssh_connection.exec_command("ls /dev/disk/by-path | grep " + sf_iscsi_name) + + result = stdout.read() + + ssh_connection.close() + + if should_exist: + self.assertFalse(result is None, "Unable to locate 'by-path' field on the KVM host (None)") + self.assertFalse(len(result.strip()) <= len(sf_iscsi_name), "Unable to locate the 'by-path' field on the KVM host (Zero-length string)") + else: + self.assertTrue(result is None or len(result.strip()) == 0, "Found the 'by-path' field on the KVM host, but did not expect to") + + @classmethod + def _start_vm(cls, vm): + vm.start(cls.apiClient) + + # Libvirt appears to have an issue detaching a volume from a VM while the VM is booting up. + # The XML sent to update the VM seems correct, but it doesn't appear to update the XML that describes the VM. + # For KVM, just give it 90 seconds to boot up. + if TestData.hypervisor_type == TestData.kvm: + time.sleep(90) + + @classmethod + def _reboot_vm(cls, vm): + vm.reboot(cls.apiClient) + + # Libvirt appears to have an issue detaching a volume from a VM while the VM is booting up. + # The XML sent to update the VM seems correct, but it doesn't appear to update the XML that describes the VM. + # For KVM, just give it 90 seconds to boot up. + if TestData.hypervisor_type == TestData.kvm: + time.sleep(90) + + @classmethod + def _handle_supports_cloning(cls): + if TestData.hypervisor_type == TestData.kvm: + cls._supports_cloning = True + elif TestData.hypervisor_type == TestData.xenServer: + # For XenServer, it is OK to set this to True or False depending on what you'd like tested + cls._supports_cloning = True + + sf_util.set_supports_resign(cls._supports_cloning, cls.dbConnection) + + @classmethod + def _connect_to_hypervisor(cls): + if TestData.hypervisor_type == TestData.kvm: + pass + elif TestData.hypervisor_type == TestData.xenServer: + host_ip = "https://" + \ + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name=TestData.xen_server_hostname)[0].ipaddress + + cls.xen_session = XenAPI.Session(host_ip) + + xen_server = cls.testdata[TestData.xenServer] + + cls.xen_session.xenapi.login_with_password(xen_server[TestData.username], xen_server[TestData.password]) + diff --git a/test/integration/plugins/solidfire/util/sf_util.py b/test/integration/plugins/solidfire/util/sf_util.py index 1b451d5639f..f35839f241e 100644 --- a/test/integration/plugins/solidfire/util/sf_util.py +++ b/test/integration/plugins/solidfire/util/sf_util.py @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +import paramiko + def check_list(in_list, expected_size_of_list, obj_assert, err_msg): obj_assert.assertEqual( isinstance(in_list, list), @@ -153,6 +155,26 @@ def check_xen_sr(xen_sr_name, xen_session, obj_assert, should_exist=True): else: check_list(xen_sr, 0, obj_assert, "SR " + xen_sr_name + " exists, but shouldn't.") +def check_kvm_access_to_volume(iscsi_name, kvm_hosts, kvm_login, obj_assert, should_exist=True): + count = 0 + + for kvm_host in kvm_hosts: + ssh_connection = sf_util.get_ssh_connection(kvm_host.ipaddress, kvm_login[TestData.username], kvm_login[TestData.password]) + + stdin, stdout, stderr = ssh_connection.exec_command("ls /dev/disk/by-path | grep " + iscsi_name) + + result = stdout.read() + + ssh_connection.close() + + if result is not None and len(result.strip()) > len(iscsi_name): + count = count + 1 + + if should_exist: + obj_assert.assertTrue(count == 1, "Only one KVM host should be connected to the following IQN: " + iscsi_name) + else: + obj_assert.assertTrue(count == 0, "No KVM host should be connected to the following IQN: " + iscsi_name) + def check_vag(sf_volume, sf_vag_id, obj_assert): obj_assert.assertEqual( len(sf_volume.volume_access_groups), @@ -215,3 +237,13 @@ def get_volume_size_with_hsr(cs_api, cs_volume, obj_assert): ) return sf_volume_size + +def get_ssh_connection(ip_address, username, password): + ssh_client = paramiko.SSHClient() + + ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + ssh_client.connect(ip_address, username=username, password=password) + + return ssh_client +