mike-tutkowski closed pull request #2503: Support multiple volume access groups per compute cluster URL: https://github.com/apache/cloudstack/pull/2503
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index 45e951b59a1..8efaebe1c84 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -1654,18 +1654,18 @@ private ModifyTargetsCommand getModifyTargetsCommand(long storagePoolId, String details.put(ModifyTargetsCommand.STORAGE_HOST, storagePool.getHostAddress()); details.put(ModifyTargetsCommand.STORAGE_PORT, String.valueOf(storagePool.getPort())); - ModifyTargetsCommand modifyTargetsCommand = new ModifyTargetsCommand(); + ModifyTargetsCommand cmd = new ModifyTargetsCommand(); List<Map<String, String>> targets = new ArrayList<>(); targets.add(details); - modifyTargetsCommand.setTargets(targets); - modifyTargetsCommand.setApplyToAllHostsInCluster(true); - modifyTargetsCommand.setAdd(add); - modifyTargetsCommand.setTargetTypeToRemove(ModifyTargetsCommand.TargetTypeToRemove.DYNAMIC); + cmd.setTargets(targets); + cmd.setApplyToAllHostsInCluster(true); + cmd.setAdd(add); + cmd.setTargetTypeToRemove(ModifyTargetsCommand.TargetTypeToRemove.DYNAMIC); - return modifyTargetsCommand; + return cmd; } private List<String> sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { diff --git a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdsCmd.java similarity index 79% rename from plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java rename to plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdsCmd.java index 5c15e01a30b..0516b8ebc45 100644 --- a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java +++ b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdsCmd.java @@ -26,16 +26,16 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVolumeAccessGroupIdResponse; +import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVolumeAccessGroupIdsResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; -@APICommand(name = "getSolidFireVolumeAccessGroupId", responseObject = ApiSolidFireVolumeAccessGroupIdResponse.class, description = "Get the SF Volume Access Group ID", +@APICommand(name = "getSolidFireVolumeAccessGroupIds", responseObject = ApiSolidFireVolumeAccessGroupIdsResponse.class, description = "Get the SF Volume Access Group IDs", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class GetSolidFireVolumeAccessGroupIdCmd extends BaseCmd { - private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeAccessGroupIdCmd.class.getName()); - private static final String NAME = "getsolidfirevolumeaccessgroupidresponse"; +public class GetSolidFireVolumeAccessGroupIdsCmd extends BaseCmd { + private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeAccessGroupIdsCmd.class.getName()); + private static final String NAME = "getsolidfirevolumeaccessgroupidsresponse"; @Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.STRING, description = "Cluster UUID", required = true) private String clusterUuid; @@ -67,14 +67,14 @@ public long getEntityOwnerId() { @Override public void execute() { - LOGGER.info("'GetSolidFireVolumeAccessGroupIdCmd.execute' method invoked"); + LOGGER.info("'GetSolidFireVolumeAccessGroupIdsCmd.execute' method invoked"); - long sfVagId = manager.getSolidFireVolumeAccessGroupId(clusterUuid, storagePoolUuid); + long[] sfVagIds = manager.getSolidFireVolumeAccessGroupIds(clusterUuid, storagePoolUuid); - ApiSolidFireVolumeAccessGroupIdResponse response = new ApiSolidFireVolumeAccessGroupIdResponse(sfVagId); + ApiSolidFireVolumeAccessGroupIdsResponse response = new ApiSolidFireVolumeAccessGroupIdsResponse(sfVagIds); response.setResponseName(getCommandName()); - response.setObjectName("apisolidfirevolumeaccessgroupid"); + response.setObjectName("apisolidfirevolumeaccessgroupids"); this.setResponseObject(response); } diff --git a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdsResponse.java similarity index 71% rename from plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java rename to plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdsResponse.java index 202a7e9ebba..a37da406362 100644 --- a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java +++ b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdsResponse.java @@ -22,12 +22,12 @@ import org.apache.cloudstack.api.BaseResponse; -public class ApiSolidFireVolumeAccessGroupIdResponse extends BaseResponse { - @SerializedName("solidFireVolumeAccessGroupId") - @Param(description = "SolidFire Volume Access Group Id") - private long solidFireVolumeAccessGroupId; +public class ApiSolidFireVolumeAccessGroupIdsResponse extends BaseResponse { + @SerializedName("solidFireVolumeAccessGroupIds") + @Param(description = "SolidFire Volume Access Group Ids") + private long[] solidFireVolumeAccessGroupIds; - public ApiSolidFireVolumeAccessGroupIdResponse(long sfVolumeAccessGroupId) { - solidFireVolumeAccessGroupId = sfVolumeAccessGroupId; + public ApiSolidFireVolumeAccessGroupIdsResponse(long[] sfVolumeAccessGroupIds) { + solidFireVolumeAccessGroupIds = sfVolumeAccessGroupIds; } } \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java index 04589038d34..4adcbbe89d8 100644 --- a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java +++ b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java @@ -22,7 +22,7 @@ import org.apache.cloudstack.api.command.admin.solidfire.GetPathForVolumeCmd; // import org.apache.log4j.Logger; import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireAccountIdCmd; -import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeAccessGroupIdCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeAccessGroupIdsCmd; import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeSnapshotDetailsCmd; import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeiScsiNameCmd; import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeSizeCmd; @@ -38,7 +38,7 @@ cmdList.add(GetPathForVolumeCmd.class); cmdList.add(GetSolidFireAccountIdCmd.class); - cmdList.add(GetSolidFireVolumeAccessGroupIdCmd.class); + cmdList.add(GetSolidFireVolumeAccessGroupIdsCmd.class); cmdList.add(GetVolumeiScsiNameCmd.class); cmdList.add(GetSolidFireVolumeSizeCmd.class); cmdList.add(GetVolumeSnapshotDetailsCmd.class); diff --git a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java index bdc11807efe..302a034911f 100644 --- a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java +++ b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java @@ -18,6 +18,6 @@ public interface SolidFireIntegrationTestManager { long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid); - long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid); + long[] getSolidFireVolumeAccessGroupIds(String csClusterUuid, String storagePoolUuid); long getSolidFireVolumeSize(String volumeUuid); } diff --git a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java index 66b92281efa..0339379d116 100644 --- a/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java +++ b/plugins/api/solidfire-intg-test/src/main/java/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java @@ -16,8 +16,8 @@ // under the License. package org.apache.cloudstack.solidfire; -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; @@ -26,18 +26,21 @@ import com.cloud.user.AccountDetailsDao; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; @Component public class SolidFireIntegrationTestManagerImpl implements SolidFireIntegrationTestManager { - @Inject private AccountDetailsDao accountDetailsDao; - @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private HostDao hostDao; @Inject private SolidFireIntegrationTestUtil util; + @Inject private StoragePoolDetailsDao storagePoolDetailsDao; @Inject private VolumeDao volumeDao; @Inject private VolumeDetailsDao volumeDetailsDao; @@ -48,7 +51,7 @@ public long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid) AccountDetailVO accountDetail = accountDetailsDao.findDetail(csAccountId, SolidFireUtil.getAccountKey(storagePoolId)); - if (accountDetail == null){ + if (accountDetail == null) { throw new CloudRuntimeException("Unable to find SF account for storage " + storagePoolUuid + " for CS account " + csAccountUuid); } @@ -58,14 +61,35 @@ public long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid) } @Override - public long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid) { - long csClusterId = util.getClusterIdForClusterUuid(csClusterUuid); + public long[] getSolidFireVolumeAccessGroupIds(String csClusterUuid, String storagePoolUuid) { long storagePoolId = util.getStoragePoolIdForStoragePoolUuid(storagePoolUuid); - ClusterDetailsVO clusterDetails = clusterDetailsDao.findDetail(csClusterId, SolidFireUtil.getVagKey(storagePoolId)); - String sfVagId = clusterDetails.getValue(); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); + + long csClusterId = util.getClusterIdForClusterUuid(csClusterUuid); + List<HostVO> hosts = hostDao.findByClusterId(csClusterId); + + if (hosts == null) { + return new long[0]; + } + + List<Long> vagIds = new ArrayList<>(hosts.size()); + + for (HostVO host : hosts) { + String iqn = host.getStorageUrl(); + + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVolumeAccessGroup(iqn, sfVags); + + if (sfVag != null) { + if (!vagIds.contains(sfVag.getId())) { + vagIds.add(sfVag.getId()); + } + } + } - return Long.parseLong(sfVagId); + return vagIds.stream().mapToLong(l -> l).toArray(); } @Override diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java index 0cea62f18fa..82cd4ca23d3 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -145,6 +145,7 @@ public String getName() { private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); private static final int DEFAULT_NFS_PORT = 2049; + private static final int SECONDS_TO_WAIT_FOR_DATASTORE = 120; private final VmwareHostService hostService; private boolean _fullCloneFlag; @@ -2602,8 +2603,7 @@ private ManagedObjectReference getVmfsDatastore(VmwareContext context, VmwareHyp } private void waitForAllHostsToSeeDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { - long secondsToWait = 120; - long endWaitTime = System.currentTimeMillis() + secondsToWait * 1000; + long endWaitTime = System.currentTimeMillis() + SECONDS_TO_WAIT_FOR_DATASTORE * 1000; boolean isConditionMet = false; @@ -2621,7 +2621,7 @@ private void waitForAllHostsToSeeDatastore(List<Pair<ManagedObjectReference, Str private boolean verifyAllHostsSeeDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { int numHostsChecked = 0; - for (Pair<ManagedObjectReference, String> host: lstHosts) { + for (Pair<ManagedObjectReference, String> host : lstHosts) { ManagedObjectReference morHostToMatch = host.first(); HostMO hostToMatchMO = new HostMO(dsMO.getContext(), morHostToMatch); @@ -2641,8 +2641,7 @@ private boolean verifyAllHostsSeeDatastore(List<Pair<ManagedObjectReference, Str } private void waitForAllHostsToMountDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { - long secondsToWait = 120; - long endWaitTime = System.currentTimeMillis() + secondsToWait * 1000; + long endWaitTime = System.currentTimeMillis() + SECONDS_TO_WAIT_FOR_DATASTORE * 1000; boolean isConditionMet = false; @@ -2657,13 +2656,39 @@ private void waitForAllHostsToMountDatastore(List<Pair<ManagedObjectReference, S } } + private void waitForAllHostsToMountDatastore2(List<HostMO> lstHosts, DatastoreMO dsMO) throws Exception { + long endWaitTime = System.currentTimeMillis() + SECONDS_TO_WAIT_FOR_DATASTORE * 1000; + + boolean isConditionMet = false; + + while (System.currentTimeMillis() < endWaitTime && !isConditionMet) { + Thread.sleep(5000); + + isConditionMet = verifyAllHostsMountedDatastore2(lstHosts, dsMO); + } + + if (!isConditionMet) { + throw new CloudRuntimeException("Not all hosts mounted the datastore"); + } + } + private boolean verifyAllHostsMountedDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { - int numHostsChecked = 0; + List<HostMO> hostMOs = new ArrayList<>(lstHosts.size()); - for (Pair<ManagedObjectReference, String> host: lstHosts) { + for (Pair<ManagedObjectReference, String> host : lstHosts) { ManagedObjectReference morHostToMatch = host.first(); HostMO hostToMatchMO = new HostMO(dsMO.getContext(), morHostToMatch); + hostMOs.add(hostToMatchMO); + } + + return verifyAllHostsMountedDatastore2(hostMOs, dsMO); + } + + private boolean verifyAllHostsMountedDatastore2(List<HostMO> lstHosts, DatastoreMO dsMO) throws Exception { + int numHostsChecked = 0; + + for (HostMO hostToMatchMO : lstHosts) { List<DatastoreHostMount> datastoreHostMounts = dsMO.getHostMounts(); for (DatastoreHostMount datastoreHostMount : datastoreHostMounts) { @@ -2753,6 +2778,16 @@ private void mountVmfsDatastore(DatastoreMO dsMO, List<Pair<ManagedObjectReferen for (Pair<ManagedObjectReference, String> host : hosts) { HostMO hostMO = new HostMO(dsMO.getContext(), host.first()); + List<HostMO> hostMOs = new ArrayList<>(1); + + hostMOs.add(hostMO); + + mountVmfsDatastore2(dsMO, hostMOs); + } + } + + private void mountVmfsDatastore2(DatastoreMO dsMO, List<HostMO> hosts) throws Exception { + for (HostMO hostMO : hosts) { if (!isDatastoreMounted(dsMO, hostMO)) { HostStorageSystemMO hostStorageSystemMO = hostMO.getHostStorageSystemMO(); @@ -2760,11 +2795,15 @@ private void mountVmfsDatastore(DatastoreMO dsMO, List<Pair<ManagedObjectReferen hostStorageSystemMO.mountVmfsVolume(getDatastoreUuid(dsMO, hostMO)); } catch (InvalidStateFaultMsg ex) { - List<Pair<ManagedObjectReference, String>> currentHosts = new ArrayList<>(1); + s_logger.trace("'" + ex.getClass().getName() + "' exception thrown: " + ex.getMessage()); - currentHosts.add(host); + List<HostMO> currentHosts = new ArrayList<>(1); - waitForAllHostsToMountDatastore(currentHosts, dsMO); + currentHosts.add(hostMO); + + s_logger.trace("Waiting for host " + hostMO.getHostName() + " to mount datastore " + dsMO.getName()); + + waitForAllHostsToMountDatastore2(currentHosts, dsMO); } } } @@ -2772,12 +2811,29 @@ private void mountVmfsDatastore(DatastoreMO dsMO, List<Pair<ManagedObjectReferen private void unmountVmfsDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String datastoreName, List<Pair<ManagedObjectReference, String>> hosts) throws Exception { + for (Pair<ManagedObjectReference, String> host : hosts) { + HostMO hostMO = new HostMO(context, host.first()); + + List<HostMO> hostMOs = new ArrayList<>(1); + + hostMOs.add(hostMO); + + unmountVmfsDatastore2(context, hyperHost, datastoreName, hostMOs); + } + } + + private void unmountVmfsDatastore2(VmwareContext context, VmwareHypervisorHost hyperHost, String datastoreName, + List<HostMO> hosts) throws Exception { ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, datastoreName); DatastoreMO dsMO = new DatastoreMO(context, morDs); - for (Pair<ManagedObjectReference, String> host : hosts) { - HostMO hostMO = new HostMO(context, host.first()); + for (HostMO hostMO : hosts) { + unmountVmfsVolume(dsMO, hostMO); + } + } + private void unmountVmfsVolume(DatastoreMO dsMO, HostMO hostMO) throws Exception { + if (isDatastoreMounted(dsMO, hostMO)) { HostStorageSystemMO hostStorageSystemMO = hostMO.getHostStorageSystemMO(); hostStorageSystemMO.unmountVmfsVolume(getDatastoreUuid(dsMO, hostMO)); @@ -2902,6 +2958,20 @@ public void handleTargets(boolean add, ModifyTargetsCommand.TargetTypeToRemove t if (rescan) { rescanAllHosts(hosts, true, false); + + List<HostInternetScsiHbaStaticTarget> targetsToAdd = new ArrayList<>(); + + targetsToAdd.addAll(getTargets(staticTargetsForHost)); + targetsToAdd.addAll(getTargets(dynamicTargetsForHost)); + + for (HostInternetScsiHbaStaticTarget targetToAdd : targetsToAdd) { + HostDatastoreSystemMO hostDatastoreSystemMO = host.getHostDatastoreSystemMO(); + String datastoreName = waitForDatastoreName(hostDatastoreSystemMO, targetToAdd.getIScsiName()); + ManagedObjectReference morDs = hostDatastoreSystemMO.findDatastoreByName(datastoreName); + DatastoreMO datastoreMO = new DatastoreMO(host.getContext(), morDs); + + mountVmfsDatastore2(datastoreMO, hosts); + } } } catch (Exception ex) { @@ -2924,26 +2994,9 @@ public void handleTargets(boolean add, ModifyTargetsCommand.TargetTypeToRemove t if (targetsToRemove.size() > 0) { if (isRemoveAsync) { - new Thread(() -> { - try { - addRemoveInternetScsiTargetsToAllHosts(false, targetsToRemove, hosts); - - rescanAllHosts(hosts, true, false); - } catch (Exception ex) { - s_logger.warn(ex.getMessage()); - } - }).start(); + new Thread(() -> handleRemove(targetsToRemove, host, hosts)).start(); } else { - executorService.submit(new Thread(() -> { - try { - addRemoveInternetScsiTargetsToAllHosts(false, targetsToRemove, hosts); - - rescanAllHosts(hosts, true, false); - } - catch (Exception ex) { - s_logger.warn(ex.getMessage()); - } - })); + executorService.submit(new Thread(() -> handleRemove(targetsToRemove, host, hosts))); } } } @@ -2956,6 +3009,60 @@ public void handleTargets(boolean add, ModifyTargetsCommand.TargetTypeToRemove t } } + private String waitForDatastoreName(HostDatastoreSystemMO hostDatastoreSystemMO, String iqn) throws Exception { + long endWaitTime = System.currentTimeMillis() + SECONDS_TO_WAIT_FOR_DATASTORE * 1000; + + do { + String datastoreName = getDatastoreName(hostDatastoreSystemMO, iqn); + + if (datastoreName != null) { + return datastoreName; + } + + Thread.sleep(5000); + } + while (System.currentTimeMillis() < endWaitTime); + + throw new CloudRuntimeException("Could not find the datastore name"); + } + + private String getDatastoreName(HostDatastoreSystemMO hostDatastoreSystemMO, String iqn) throws Exception { + String datastoreName = "-" + iqn + "-0"; + + ManagedObjectReference morDs = hostDatastoreSystemMO.findDatastoreByName(datastoreName); + + if (morDs != null) { + return datastoreName; + } + + datastoreName = "_" + iqn + "_0"; + + morDs = hostDatastoreSystemMO.findDatastoreByName(datastoreName); + + if (morDs != null) { + return datastoreName; + } + + return null; + } + + private void handleRemove(List<HostInternetScsiHbaStaticTarget> targetsToRemove, HostMO host, List<HostMO> hosts) { + try { + for (HostInternetScsiHbaStaticTarget target : targetsToRemove) { + String datastoreName = waitForDatastoreName(host.getHostDatastoreSystemMO(), target.getIScsiName()); + + unmountVmfsDatastore2(host.getContext(), host, datastoreName, hosts); + } + + addRemoveInternetScsiTargetsToAllHosts(false, targetsToRemove, hosts); + + rescanAllHosts(hosts, true, false); + } + catch (Exception ex) { + s_logger.warn(ex.getMessage()); + } + } + private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List<HostInternetScsiHbaStaticTarget> targets, List<Pair<ManagedObjectReference, String>> hostPairs) throws Exception { List<HostMO> hosts = new ArrayList<>(); diff --git a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java index 3600ea92e61..c95e4c534d9 100644 --- a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java @@ -30,8 +30,6 @@ import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.dc.ClusterVO; -import com.cloud.dc.ClusterDetailsVO; -import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.dao.ClusterDao; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -88,7 +86,6 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { private static final Logger LOGGER = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class); - private static final int LOCK_TIME_IN_SECONDS = 300; private static final int LOWEST_HYPERVISOR_SNAPSHOT_RESERVE = 10; private static final long MIN_IOPS_FOR_TEMPLATE_VOLUME = 100L; private static final long MAX_IOPS_FOR_TEMPLATE_VOLUME = 20000L; @@ -102,7 +99,6 @@ @Inject private AccountDao accountDao; @Inject private AccountDetailsDao accountDetailsDao; @Inject private ClusterDao clusterDao; - @Inject private ClusterDetailsDao clusterDetailsDao; @Inject private DataStoreManager dataStoreMgr; @Inject private HostDao hostDao; @Inject private SnapshotDao snapshotDao; @@ -147,14 +143,8 @@ public ChapInfo getChapInfo(DataObject dataObject) { return null; } - // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) - // if the VAG exists - // update the VAG to contain all IQNs of the hosts (ModifyVolumeAccessGroup) - // if the ID of volumeInfo in not in the VAG, add it (ModifyVolumeAccessGroup) - // if the VAG doesn't exist, create it with the IQNs of the hosts and the ID of volumeInfo (CreateVolumeAccessGroup) @Override - public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) - { + public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) { Preconditions.checkArgument(dataObject != null, "'dataObject' should not be 'null'"); Preconditions.checkArgument(host != null, "'host' should not be 'null'"); Preconditions.checkArgument(dataStore != null, "'dataStore' should not be 'null'"); @@ -167,7 +157,7 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(LOCK_TIME_IN_SECONDS)) { + if (!lock.lock(SolidFireUtil.LOCK_TIME_IN_SECONDS)) { String errMsg = "Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid(); LOGGER.warn(errMsg); @@ -176,32 +166,11 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore } try { - ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); - - String vagId = clusterDetail != null ? clusterDetail.getValue() : null; - List<HostVO> hosts = hostDao.findByClusterId(clusterId); - if (!SolidFireUtil.hostsSupport_iScsi(hosts)) { - String errMsg = "Not all hosts in the compute cluster support iSCSI."; - - LOGGER.warn(errMsg); - - throw new CloudRuntimeException(errMsg); - } - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); - if (vagId != null) { - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); - - long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - - SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); - } - else { - SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, clusterDetailsDao); - } + SolidFireUtil.placeVolumeInVolumeAccessGroups(sfConnection, sfVolumeId, hosts); return true; } @@ -211,9 +180,6 @@ public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore } } - // get the VAG associated with volumeInfo's cluster, if any (ListVolumeAccessGroups) // might not exist if using CHAP - // if the VAG exists - // remove the ID of volumeInfo from the VAG (ModifyVolumeAccessGroup) @Override public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) { @@ -229,27 +195,23 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(LOCK_TIME_IN_SECONDS)) { + if (!lock.lock(SolidFireUtil.LOCK_TIME_IN_SECONDS)) { String errMsg = "Couldn't lock the DB (in revokeAccess) on the following string: " + cluster.getUuid(); - LOGGER.debug(errMsg); + LOGGER.warn(errMsg); throw new CloudRuntimeException(errMsg); } try { - ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); - - String vagId = clusterDetail != null ? clusterDetail.getValue() : null; - - if (vagId != null) { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); - - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); - long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); + List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); - SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); + for (SolidFireUtil.SolidFireVag sfVag : sfVags) { + if (SolidFireUtil.sfVagContains(sfVag, sfVolumeId, clusterId, hostDao)) { + SolidFireUtil.removeVolumeIdsFromSolidFireVag(sfConnection, sfVag.getId(), new Long[] { sfVolumeId }); + } } } finally { @@ -735,11 +697,7 @@ private boolean isBasicRevokeAccess(long volumeId) { private boolean getBooleanValueFromVolumeDetails(long volumeId, String name) { VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volumeId, name); - if (volumeDetail != null && volumeDetail.getValue() != null) { - return Boolean.parseBoolean(volumeDetail.getValue()); - } - - return false; + return volumeDetail != null && volumeDetail.getValue() != null && Boolean.parseBoolean(volumeDetail.getValue()); } private long getCsIdForCloning(long volumeId, String cloneOf) { @@ -755,11 +713,7 @@ private long getCsIdForCloning(long volumeId, String cloneOf) { private boolean shouldTakeSnapshot(long snapshotId) { SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, "takeSnapshot"); - if (snapshotDetails != null && snapshotDetails.getValue() != null) { - return Boolean.parseBoolean(snapshotDetails.getValue()); - } - - return false; + return snapshotDetails != null && snapshotDetails.getValue() != null && Boolean.parseBoolean(snapshotDetails.getValue()); } private SolidFireUtil.SolidFireVolume createClone(SolidFireUtil.SolidFireConnection sfConnection, long dataObjectId, VolumeInfo volumeInfo, long sfAccountId, diff --git a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java index 3172b1af5b4..2ebd69a2d93 100644 --- a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java @@ -49,8 +49,6 @@ import com.cloud.agent.api.DeleteStoragePoolCommand; import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.agent.api.StoragePoolInfo; -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; @@ -75,23 +73,22 @@ import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { - private static final Logger s_logger = Logger.getLogger(SolidFireSharedPrimaryDataStoreLifeCycle.class); - - @Inject private AccountDao _accountDao; - @Inject private AccountDetailsDao _accountDetailsDao; - @Inject private AgentManager _agentMgr; - @Inject private ClusterDao _clusterDao; - @Inject private ClusterDetailsDao _clusterDetailsDao; - @Inject private DataCenterDao _zoneDao; - @Inject private HostDao _hostDao; - @Inject private PrimaryDataStoreDao _primaryDataStoreDao; - @Inject private PrimaryDataStoreHelper _primaryDataStoreHelper; - @Inject private ResourceManager _resourceMgr; - @Inject private StorageManager _storageMgr; - @Inject private StoragePoolAutomation _storagePoolAutomation; - @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; - @Inject private StoragePoolHostDao _storagePoolHostDao; - @Inject private TemplateManager _tmpltMgr; + private static final Logger LOGGER = Logger.getLogger(SolidFireSharedPrimaryDataStoreLifeCycle.class); + + @Inject private AccountDao accountDao; + @Inject private AccountDetailsDao accountDetailsDao; + @Inject private AgentManager agentMgr; + @Inject private ClusterDao clusterDao; + @Inject private DataCenterDao zoneDao; + @Inject private HostDao hostDao; + @Inject private PrimaryDataStoreDao primaryDataStoreDao; + @Inject private PrimaryDataStoreHelper primaryDataStoreHelper; + @Inject private ResourceManager resourceMgr; + @Inject private StorageManager storageMgr; + @Inject private StoragePoolAutomation storagePoolAutomation; + @Inject private StoragePoolDetailsDao storagePoolDetailsDao; + @Inject private StoragePoolHostDao storagePoolHostDao; + @Inject private TemplateManager tmpltMgr; // invoked to add primary storage that is based on the SolidFire plug-in @Override @@ -184,7 +181,7 @@ public DataStore initialize(Map<String, Object> dsInfos) { lMinIops = Long.parseLong(minIops); } } catch (Exception ex) { - s_logger.info("[ignored] error getting Min IOPS: " + ex.getLocalizedMessage()); + LOGGER.info("[ignored] error getting Min IOPS: " + ex.getLocalizedMessage()); } try { @@ -194,7 +191,7 @@ public DataStore initialize(Map<String, Object> dsInfos) { lMaxIops = Long.parseLong(maxIops); } } catch (Exception ex) { - s_logger.info("[ignored] error getting Max IOPS: " + ex.getLocalizedMessage()); + LOGGER.info("[ignored] error getting Max IOPS: " + ex.getLocalizedMessage()); } try { @@ -204,7 +201,7 @@ public DataStore initialize(Map<String, Object> dsInfos) { lBurstIops = Long.parseLong(burstIops); } } catch (Exception ex) { - s_logger.info("[ignored] error getting Burst IOPS: " + ex.getLocalizedMessage()); + LOGGER.info("[ignored] error getting Burst IOPS: " + ex.getLocalizedMessage()); } if (lMinIops > lMaxIops) { @@ -266,14 +263,14 @@ public DataStore initialize(Map<String, Object> dsInfos) { parameters.setPath(iqn); } - ClusterVO cluster = _clusterDao.findById(clusterId); + ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + if (!lock.lock(SolidFireUtil.LOCK_TIME_IN_SECONDS)) { String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); - s_logger.debug(errMsg); + LOGGER.debug(errMsg); throw new CloudRuntimeException(errMsg); } @@ -282,21 +279,21 @@ public DataStore initialize(Map<String, Object> dsInfos) { try { // this adds a row in the cloud.storage_pool table for this SolidFire volume - dataStore = _primaryDataStoreHelper.createPrimaryDataStore(parameters); + dataStore = primaryDataStoreHelper.createPrimaryDataStore(parameters); // now that we have a DataStore (we need the id from the DataStore instance), we can create a Volume Access Group, if need be, and // place the newly created volume in the Volume Access Group - List<HostVO> hosts = _hostDao.findByClusterId(clusterId); + List<HostVO> hosts = hostDao.findByClusterId(clusterId); - SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolume.getId(), dataStore.getId(), cluster.getUuid(), hosts, _clusterDetailsDao); + SolidFireUtil.placeVolumeInVolumeAccessGroups(sfConnection, sfVolume.getId(), hosts); SolidFireUtil.SolidFireAccount sfAccount = sfCreateVolume.getAccount(); Account csAccount = CallContext.current().getCallingAccount(); - SolidFireUtil.updateCsDbWithSolidFireAccountInfo(csAccount.getId(), sfAccount, dataStore.getId(), _accountDetailsDao); + SolidFireUtil.updateCsDbWithSolidFireAccountInfo(csAccount.getId(), sfAccount, dataStore.getId(), accountDetailsDao); } catch (Exception ex) { if (dataStore != null) { - _primaryDataStoreDao.expunge(dataStore.getId()); + primaryDataStoreDao.expunge(dataStore.getId()); } throw new CloudRuntimeException(ex.getMessage()); @@ -310,7 +307,7 @@ public DataStore initialize(Map<String, Object> dsInfos) { } private HypervisorType getHypervisorTypeForCluster(long clusterId) { - ClusterVO cluster = _clusterDao.findById(clusterId); + ClusterVO cluster = clusterDao.findById(clusterId); if (cluster == null) { throw new CloudRuntimeException("Cluster ID '" + clusterId + "' was not found in the database."); @@ -354,7 +351,7 @@ private SolidFireCreateVolume createSolidFireVolume(SolidFireUtil.SolidFireConne try { Account csAccount = CallContext.current().getCallingAccount(); long csAccountId = csAccount.getId(); - AccountVO accountVo = _accountDao.findById(csAccountId); + AccountVO accountVo = accountDao.findById(csAccountId); String sfAccountName = SolidFireUtil.getSolidFireAccountName(accountVo.getUuid(), csAccountId); @@ -386,11 +383,11 @@ public boolean attachCluster(DataStore store, ClusterScope scope) { PrimaryDataStoreInfo primaryDataStoreInfo = (PrimaryDataStoreInfo)store; // check if there is at least one host up in this cluster - List<HostVO> allHosts = _resourceMgr.listAllUpHosts(Host.Type.Routing, primaryDataStoreInfo.getClusterId(), + List<HostVO> allHosts = resourceMgr.listAllUpHosts(Host.Type.Routing, primaryDataStoreInfo.getClusterId(), primaryDataStoreInfo.getPodId(), primaryDataStoreInfo.getDataCenterId()); if (allHosts.isEmpty()) { - _primaryDataStoreDao.expunge(primaryDataStoreInfo.getId()); + primaryDataStoreDao.expunge(primaryDataStoreInfo.getId()); throw new CloudRuntimeException("No host up to associate a storage pool with in cluster " + primaryDataStoreInfo.getClusterId()); } @@ -413,23 +410,23 @@ public boolean attachCluster(DataStore store, ClusterScope scope) { for (HostVO host : allHosts) { try { - _storageMgr.connectHostToSharedPool(host.getId(), primaryDataStoreInfo.getId()); + storageMgr.connectHostToSharedPool(host.getId(), primaryDataStoreInfo.getId()); poolHosts.add(host); } catch (Exception e) { - s_logger.warn("Unable to establish a connection between " + host + " and " + primaryDataStoreInfo, e); + LOGGER.warn("Unable to establish a connection between " + host + " and " + primaryDataStoreInfo, e); } } if (poolHosts.isEmpty()) { - s_logger.warn("No host can access storage pool '" + primaryDataStoreInfo + "' on cluster '" + primaryDataStoreInfo.getClusterId() + "'."); + LOGGER.warn("No host can access storage pool '" + primaryDataStoreInfo + "' on cluster '" + primaryDataStoreInfo.getClusterId() + "'."); - _primaryDataStoreDao.expunge(primaryDataStoreInfo.getId()); + primaryDataStoreDao.expunge(primaryDataStoreInfo.getId()); throw new CloudRuntimeException("Failed to access storage pool"); } - _primaryDataStoreHelper.attachCluster(store); + primaryDataStoreHelper.attachCluster(store); return true; } @@ -444,31 +441,31 @@ private boolean createStoragePool(HostVO host, StoragePool storagePool) { Map<String, String> details = new HashMap<>(); - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME); details.put(CreateStoragePoolCommand.DATASTORE_NAME, storagePoolDetail.getValue()); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN); details.put(CreateStoragePoolCommand.IQN, storagePoolDetail.getValue()); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP); details.put(CreateStoragePoolCommand.STORAGE_HOST, storagePoolDetail.getValue()); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT); details.put(CreateStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue()); cmd.setDetails(details); } - Answer answer = _agentMgr.easySend(hostId, cmd); + Answer answer = agentMgr.easySend(hostId, cmd); if (answer != null && answer.getResult()) { return true; } else { - _primaryDataStoreDao.expunge(storagePool.getId()); + primaryDataStoreDao.expunge(storagePool.getId()); final String msg; @@ -478,7 +475,7 @@ private boolean createStoragePool(HostVO host, StoragePool storagePool) { msg = "Cannot create storage pool through host '" + hostId + "' due to CreateStoragePoolCommand returns null"; } - s_logger.warn(msg); + LOGGER.warn(msg); throw new CloudRuntimeException(msg); } @@ -491,16 +488,16 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType h @Override public boolean maintain(DataStore dataStore) { - _storagePoolAutomation.maintain(dataStore); - _primaryDataStoreHelper.maintain(dataStore); + storagePoolAutomation.maintain(dataStore); + primaryDataStoreHelper.maintain(dataStore); return true; } @Override public boolean cancelMaintain(DataStore store) { - _primaryDataStoreHelper.cancelMaintain(store); - _storagePoolAutomation.cancelMaintain(store); + primaryDataStoreHelper.cancelMaintain(store); + storagePoolAutomation.cancelMaintain(store); return true; } @@ -508,7 +505,7 @@ public boolean cancelMaintain(DataStore store) { // invoked to delete primary storage that is based on the SolidFire plug-in @Override public boolean deleteDataStore(DataStore dataStore) { - List<StoragePoolHostVO> hostPoolRecords = _storagePoolHostDao.listByPoolId(dataStore.getId()); + List<StoragePoolHostVO> hostPoolRecords = storagePoolHostDao.listByPoolId(dataStore.getId()); HypervisorType hypervisorType = null; @@ -521,11 +518,11 @@ public boolean deleteDataStore(DataStore dataStore) { } StoragePool storagePool = (StoragePool)dataStore; - StoragePoolVO storagePoolVO = _primaryDataStoreDao.findById(storagePool.getId()); - List<VMTemplateStoragePoolVO> unusedTemplatesInPool = _tmpltMgr.getUnusedTemplatesInPool(storagePoolVO); + StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId()); + List<VMTemplateStoragePoolVO> unusedTemplatesInPool = tmpltMgr.getUnusedTemplatesInPool(storagePoolVO); for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) { - _tmpltMgr.evictTemplateFromStoragePool(templatePoolVO); + tmpltMgr.evictTemplateFromStoragePool(templatePoolVO); } Long clusterId = null; @@ -539,31 +536,31 @@ public boolean deleteDataStore(DataStore dataStore) { Map<String, String> details = new HashMap<>(); - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.DATASTORE_NAME); details.put(DeleteStoragePoolCommand.DATASTORE_NAME, storagePoolDetail.getValue()); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.IQN); details.put(DeleteStoragePoolCommand.IQN, storagePoolDetail.getValue()); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_VIP); details.put(DeleteStoragePoolCommand.STORAGE_HOST, storagePoolDetail.getValue()); - storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT); + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePool.getId(), SolidFireUtil.STORAGE_PORT); details.put(DeleteStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue()); deleteCmd.setDetails(details); } - final Answer answer = _agentMgr.easySend(host.getHostId(), deleteCmd); + final Answer answer = agentMgr.easySend(host.getHostId(), deleteCmd); if (answer != null && answer.getResult()) { - s_logger.info("Successfully deleted storage pool using Host ID " + host.getHostId()); + LOGGER.info("Successfully deleted storage pool using Host ID " + host.getHostId()); - HostVO hostVO = _hostDao.findById(host.getHostId()); + HostVO hostVO = hostDao.findById(host.getHostId()); if (hostVO != null) { clusterId = hostVO.getClusterId(); @@ -574,29 +571,39 @@ public boolean deleteDataStore(DataStore dataStore) { } else { if (answer != null) { - s_logger.error("Failed to delete storage pool using Host ID " + host.getHostId() + ": " + answer.getResult()); + LOGGER.error("Failed to delete storage pool using Host ID " + host.getHostId() + ": " + answer.getResult()); } else { - s_logger.error("Failed to delete storage pool using Host ID " + host.getHostId()); + LOGGER.error("Failed to delete storage pool using Host ID " + host.getHostId()); } } } if (clusterId != null) { - ClusterVO cluster = _clusterDao.findById(clusterId); + ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + if (!lock.lock(SolidFireUtil.LOCK_TIME_IN_SECONDS)) { String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); - s_logger.debug(errMsg); + LOGGER.debug(errMsg); throw new CloudRuntimeException(errMsg); } try { - removeVolumeFromVag(storagePool.getId(), clusterId); + long sfVolumeId = getVolumeId(storagePool.getId()); + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); + + List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); + + for (SolidFireUtil.SolidFireVag sfVag : sfVags) { + if (SolidFireUtil.sfVagContains(sfVag, sfVolumeId, clusterId, hostDao)) { + SolidFireUtil.removeVolumeIdsFromSolidFireVag(sfConnection, sfVag.getId(), new Long[] { sfVolumeId }); + } + } } finally { lock.unlock(); @@ -610,16 +617,16 @@ public boolean deleteDataStore(DataStore dataStore) { deleteSolidFireVolume(storagePool.getId()); - return _primaryDataStoreHelper.deletePrimaryDataStore(dataStore); + return primaryDataStoreHelper.deletePrimaryDataStore(dataStore); } private void handleTargetsForVMware(long hostId, long storagePoolId) { - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); if (host.getHypervisorType() == HypervisorType.VMware) { - String storageAddress = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP).getValue(); - int storagePort = Integer.parseInt(_storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT).getValue()); - String iqn = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN).getValue(); + String storageAddress = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP).getValue(); + int storagePort = Integer.parseInt(storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT).getValue()); + String iqn = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN).getValue(); ModifyTargetsCommand cmd = new ModifyTargetsCommand(); @@ -644,39 +651,22 @@ private void handleTargetsForVMware(long hostId, long storagePoolId) { } private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { - Answer answer = _agentMgr.easySend(hostId, cmd); + Answer answer = agentMgr.easySend(hostId, cmd); if (answer == null) { String msg = "Unable to get an answer to the modify targets command"; - s_logger.warn(msg); + LOGGER.warn(msg); } else if (!answer.getResult()) { String msg = "Unable to modify target on the following host: " + hostId; - s_logger.warn(msg); - } - } - - private void removeVolumeFromVag(long storagePoolId, long clusterId) { - long sfVolumeId = getVolumeId(storagePoolId); - ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); - - String vagId = clusterDetail != null ? clusterDetail.getValue() : null; - - if (vagId != null) { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); - - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); - - long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - - SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); + LOGGER.warn(msg); } } private void deleteSolidFireVolume(long storagePoolId) { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); long sfVolumeId = getVolumeId(storagePoolId); @@ -684,7 +674,7 @@ private void deleteSolidFireVolume(long storagePoolId) { } private long getVolumeId(long storagePoolId) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.VOLUME_ID); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.VOLUME_ID); String volumeId = storagePoolDetail.getValue(); @@ -692,7 +682,7 @@ private long getVolumeId(long storagePoolId) { } private long getIopsValue(long storagePoolId, String iopsKey) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, iopsKey); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, iopsKey); String iops = storagePoolDetail.getValue(); @@ -704,7 +694,7 @@ private static boolean isSupportedHypervisorType(HypervisorType hypervisorType) } private HypervisorType getHypervisorType(long hostId) { - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); if (host != null) { return host.getHypervisorType(); @@ -729,7 +719,7 @@ public void updateStoragePool(StoragePool storagePool, Map<String, String> detai Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null; Long capacityIops = strCapacityIops != null ? Long.parseLong(strCapacityIops) : null; - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); long size = capacityBytes != null ? capacityBytes : storagePool.getCapacityBytes(); @@ -764,16 +754,16 @@ public void updateStoragePool(StoragePool storagePool, Map<String, String> detai SolidFireUtil.modifyVolume(sfConnection, getVolumeId(storagePool.getId()), size, null, minIops, maxIops, burstIops); - SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), _primaryDataStoreDao, _storagePoolDetailsDao, minIops, maxIops, burstIops); + SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), primaryDataStoreDao, storagePoolDetailsDao, minIops, maxIops, burstIops); } @Override public void enableStoragePool(DataStore dataStore) { - _primaryDataStoreHelper.enable(dataStore); + primaryDataStoreHelper.enable(dataStore); } @Override public void disableStoragePool(DataStore dataStore) { - _primaryDataStoreHelper.disable(dataStore); + primaryDataStoreHelper.disable(dataStore); } } diff --git a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java index f2a4b79cf78..4fffb702274 100644 --- a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java +++ b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java @@ -40,7 +40,6 @@ import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.alert.AlertManager; -import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.dao.ClusterDao; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; @@ -56,31 +55,31 @@ import com.cloud.vm.dao.VMInstanceDao; public class SolidFireHostListener implements HypervisorHostListener { - private static final Logger s_logger = Logger.getLogger(SolidFireHostListener.class); - - @Inject private AgentManager _agentMgr; - @Inject private AlertManager _alertMgr; - @Inject private ClusterDao _clusterDao; - @Inject private ClusterDetailsDao _clusterDetailsDao; - @Inject private DataStoreManager _dataStoreMgr; - @Inject private HostDao _hostDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; - @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + private static final Logger LOGGER = Logger.getLogger(SolidFireHostListener.class); + + @Inject private AgentManager agentMgr; + @Inject private AlertManager alertMgr; + @Inject private ClusterDao clusterDao; + @Inject private DataStoreManager dataStoreMgr; + @Inject private HostDao hostDao; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private StoragePoolDetailsDao storagePoolDetailsDao; @Inject private StoragePoolHostDao storagePoolHostDao; - @Inject private VMInstanceDao _vmDao; - @Inject private VolumeDao _volumeDao; + @Inject private VMInstanceDao vmDao; + @Inject private VolumeDao volumeDao; @Override public boolean hostAdded(long hostId) { - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); if (host == null) { - s_logger.error("Failed to add host by SolidFireHostListener as host was not found with id=" + hostId); + LOGGER.error("Failed to add host by SolidFireHostListener as host was not found with id = " + hostId); + return false; } - SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.PROVIDER_NAME, - _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + SolidFireUtil.hostAddedToCluster(hostId, host.getClusterId(), SolidFireUtil.PROVIDER_NAME, + clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); handleVMware(host, true, ModifyTargetsCommand.TargetTypeToRemove.NEITHER); @@ -89,7 +88,7 @@ public boolean hostAdded(long hostId) { @Override public boolean hostConnect(long hostId, long storagePoolId) { - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); @@ -122,25 +121,25 @@ public boolean hostDisconnected(long hostId, long storagePoolId) { @Override public boolean hostAboutToBeRemoved(long hostId) { + HostVO host = hostDao.findById(hostId); + + SolidFireUtil.hostRemovedFromCluster(hostId, host.getClusterId(), SolidFireUtil.PROVIDER_NAME, + clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); + + handleVMware(host, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); + return true; } @Override public boolean hostRemoved(long hostId, long clusterId) { - SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.PROVIDER_NAME, - _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); - - HostVO host = _hostDao.findById(hostId); - - handleVMware(host, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); - return true; } private void handleXenServer(long clusterId, long hostId, long storagePoolId) { List<String> storagePaths = getStoragePaths(clusterId, storagePoolId); - StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + StoragePool storagePool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); for (String storagePath : storagePaths) { ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); @@ -153,7 +152,7 @@ private void handleXenServer(long clusterId, long hostId, long storagePoolId) { private void handleVMware(HostVO host, boolean add, ModifyTargetsCommand.TargetTypeToRemove targetTypeToRemove) { if (host != null && HypervisorType.VMware.equals(host.getHypervisorType())) { - List<StoragePoolVO> storagePools = _storagePoolDao.findPoolsByProvider(SolidFireUtil.PROVIDER_NAME); + List<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.PROVIDER_NAME); if (storagePools != null && storagePools.size() > 0) { List<Map<String, String>> targets = new ArrayList<>(); @@ -169,6 +168,7 @@ private void handleVMware(HostVO host, boolean add, ModifyTargetsCommand.TargetT cmd.setTargets(targets); cmd.setAdd(add); cmd.setTargetTypeToRemove(targetTypeToRemove); + cmd.setRemoveAsync(true); sendModifyTargetsCommand(cmd, host.getId()); } @@ -176,7 +176,7 @@ private void handleVMware(HostVO host, boolean add, ModifyTargetsCommand.TargetT } private void handleKVM(long hostId, long storagePoolId) { - StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + StoragePool storagePool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); @@ -187,19 +187,19 @@ private void handleKVM(long hostId, long storagePoolId) { List<String> storagePaths = new ArrayList<>(); // If you do not pass in null for the second parameter, you only get back applicable ROOT disks. - List<VolumeVO> volumes = _volumeDao.findByPoolId(storagePoolId, null); + List<VolumeVO> volumes = volumeDao.findByPoolId(storagePoolId, null); if (volumes != null) { for (VolumeVO volume : volumes) { Long instanceId = volume.getInstanceId(); if (instanceId != null) { - VMInstanceVO vmInstance = _vmDao.findById(instanceId); + VMInstanceVO vmInstance = vmDao.findById(instanceId); Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); if (hostIdForVm != null) { - HostVO hostForVm = _hostDao.findById(hostIdForVm); + HostVO hostForVm = hostDao.findById(hostIdForVm); if (hostForVm != null && hostForVm.getClusterId().equals(clusterId)) { storagePaths.add(volume.get_iScsiName()); @@ -215,22 +215,22 @@ private void handleKVM(long hostId, long storagePoolId) { private List<Map<String, String>> getTargets(long clusterId, long storagePoolId) { List<Map<String, String>> targets = new ArrayList<>(); - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); // If you do not pass in null for the second parameter, you only get back applicable ROOT disks. - List<VolumeVO> volumes = _volumeDao.findByPoolId(storagePoolId, null); + List<VolumeVO> volumes = volumeDao.findByPoolId(storagePoolId, null); if (volumes != null) { for (VolumeVO volume : volumes) { Long instanceId = volume.getInstanceId(); if (instanceId != null) { - VMInstanceVO vmInstance = _vmDao.findById(instanceId); + VMInstanceVO vmInstance = vmDao.findById(instanceId); Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); if (hostIdForVm != null) { - HostVO hostForVm = _hostDao.findById(hostIdForVm); + HostVO hostForVm = hostDao.findById(hostIdForVm); if (hostForVm.getClusterId().equals(clusterId)) { Map<String, String> details = new HashMap<>(); @@ -250,7 +250,7 @@ private void handleKVM(long hostId, long storagePoolId) { } private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { - Answer answer = _agentMgr.easySend(hostId, cmd); + Answer answer = agentMgr.easySend(hostId, cmd); if (answer == null) { throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); @@ -259,16 +259,16 @@ private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { if (!answer.getResult()) { String msg = "Unable to modify targets on the following host: " + hostId; - HostVO host = _hostDao.findById(hostId); + HostVO host = hostDao.findById(hostId); - _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); throw new CloudRuntimeException(msg); } } private void sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { - Answer answer = _agentMgr.easySend(hostId, cmd); + Answer answer = agentMgr.easySend(hostId, cmd); if (answer == null) { throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command (" + storagePool.getId() + ")"); @@ -277,7 +277,7 @@ private void sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StorageP if (!answer.getResult()) { String msg = "Unable to attach storage pool " + storagePool.getId() + " to host " + hostId; - _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); throw new CloudRuntimeException("Unable to establish a connection from agent to storage pool " + storagePool.getId() + " due to " + answer.getDetails() + " (" + storagePool.getId() + ")"); @@ -285,6 +285,6 @@ private void sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StorageP assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer expected ; Pool = " + storagePool.getId() + " Host = " + hostId; - s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId); + LOGGER.info("Connection established between storage pool " + storagePool + " and host + " + hostId); } } diff --git a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java index 66aafacdbfd..575a3020d37 100644 --- a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java +++ b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java @@ -40,7 +40,6 @@ import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.alert.AlertManager; -import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.dao.ClusterDao; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; @@ -57,7 +56,6 @@ @Inject private AgentManager agentMgr; @Inject private AlertManager alertMgr; @Inject private ClusterDao clusterDao; - @Inject private ClusterDetailsDao clusterDetailsDao; @Inject private DataStoreManager dataStoreMgr; @Inject private HostDao hostDao; @Inject private PrimaryDataStoreDao storagePoolDao; @@ -69,14 +67,15 @@ public boolean hostAdded(long hostId) { HostVO host = hostDao.findById(hostId); if (host == null) { - LOGGER.error("Failed to add host by SolidFireSharedHostListener as host was not found with id=" + hostId); + LOGGER.error("Failed to add host by SolidFireSharedHostListener as host was not found with id = " + hostId); + return false; } - SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.SHARED_PROVIDER_NAME, - clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); + SolidFireUtil.hostAddedToCluster(hostId, host.getClusterId(), SolidFireUtil.SHARED_PROVIDER_NAME, + clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); - handleVMware(hostId, true, ModifyTargetsCommand.TargetTypeToRemove.NEITHER); + handleVMware(host, true, ModifyTargetsCommand.TargetTypeToRemove.NEITHER); return true; } @@ -123,10 +122,10 @@ public boolean hostDisconnected(long hostId, long storagePoolId) { public boolean hostAboutToBeRemoved(long hostId) { HostVO host = hostDao.findById(hostId); - SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), false, SolidFireUtil.SHARED_PROVIDER_NAME, - clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); + SolidFireUtil.hostRemovedFromCluster(hostId, host.getClusterId(), SolidFireUtil.SHARED_PROVIDER_NAME, + clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); - handleVMware(hostId, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); + handleVMware(host, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); return true; } @@ -136,9 +135,7 @@ public boolean hostRemoved(long hostId, long clusterId) { return true; } - private void handleVMware(long hostId, boolean add, ModifyTargetsCommand.TargetTypeToRemove targetTypeToRemove) { - HostVO host = hostDao.findById(hostId); - + private void handleVMware(HostVO host, boolean add, ModifyTargetsCommand.TargetTypeToRemove targetTypeToRemove) { if (HypervisorType.VMware.equals(host.getHypervisorType())) { List<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME); @@ -179,7 +176,7 @@ private void handleVMware(long hostId, boolean add, ModifyTargetsCommand.TargetT cmd.setTargetTypeToRemove(targetTypeToRemove); cmd.setRemoveAsync(true); - sendModifyTargetsCommand(cmd, hostId); + sendModifyTargetsCommand(cmd, host.getId()); } } } diff --git a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 81adf4b343e..1f8a2885945 100644 --- a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -17,13 +17,16 @@ package org.apache.cloudstack.storage.datastore.util; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.StringTokenizer; +import java.util.UUID; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -32,8 +35,6 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.host.Host; @@ -44,11 +45,14 @@ import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.base.Preconditions; 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.AddInitiatorsToVolumeAccessGroupRequest; +import com.solidfire.element.api.AddVolumesToVolumeAccessGroupRequest; import com.solidfire.element.api.CloneVolumeRequest; import com.solidfire.element.api.CloneVolumeResult; import com.solidfire.element.api.CreateSnapshotRequest; @@ -62,9 +66,10 @@ 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.RemoveInitiatorsFromVolumeAccessGroupRequest; +import com.solidfire.element.api.RemoveVolumesFromVolumeAccessGroupRequest; import com.solidfire.element.api.RollbackToSnapshotRequest; import com.solidfire.element.api.Snapshot; import com.solidfire.element.api.SolidFireElement; @@ -75,12 +80,13 @@ import static org.apache.commons.lang.ArrayUtils.toPrimitive; public class SolidFireUtil { - private static final Logger s_logger = Logger.getLogger(SolidFireUtil.class); + private static final Logger LOGGER = Logger.getLogger(SolidFireUtil.class); public static final String PROVIDER_NAME = "SolidFire"; public static final String SHARED_PROVIDER_NAME = "SolidFireShared"; - public static final int s_lockTimeInSeconds = 300; + private static final Random RANDOM = new Random(System.nanoTime()); + public static final int LOCK_TIME_IN_SECONDS = 300; public static final String LOG_PREFIX = "SolidFire: "; @@ -127,6 +133,8 @@ public static final String DATASTORE_NAME = "datastoreName"; public static final String IQN = "iqn"; + private static final String SF_CS_ACCOUNT_PREFIX = "CloudStack_"; + public static final long MIN_VOLUME_SIZE = 1000000000; public static final long MIN_IOPS_PER_VOLUME = 100; @@ -136,6 +144,9 @@ private static final int DEFAULT_MANAGEMENT_PORT = 443; private static final int DEFAULT_STORAGE_PORT = 3260; + private static final int MAX_NUM_VAGS_PER_VOLUME = 4; + private static final int MAX_NUM_INITIATORS_PER_VAG = 64; + public static class SolidFireConnection { private final String _managementVip; private final int _managementPort; @@ -300,7 +311,7 @@ public static String getValue(String keyToMatch, String url, boolean throwExcept } public static String getSolidFireAccountName(String csAccountUuid, long csAccountId) { - return "CloudStack_" + csAccountUuid + "_" + csAccountId; + return SF_CS_ACCOUNT_PREFIX + csAccountUuid + "_" + csAccountId; } public static void updateCsDbWithSolidFireIopsInfo(long storagePoolId, PrimaryDataStoreDao primaryDataStoreDao, @@ -344,17 +355,72 @@ public static SolidFireAccount getAccount(SolidFireConnection sfConnection, Stri } } - public static void hostAddedToOrRemovedFromCluster(long hostId, long clusterId, boolean added, String storageProvider, - ClusterDao clusterDao, ClusterDetailsDao clusterDetailsDao, PrimaryDataStoreDao storagePoolDao, - StoragePoolDetailsDao storagePoolDetailsDao, HostDao hostDao) { + private static boolean isCloudStackOnlyVag(SolidFireConnection sfConnection, SolidFireVag sfVag) { + long[] volumeIds = sfVag.getVolumeIds(); + + if (ArrayUtils.isEmpty(volumeIds)) { + // We count this situation as being "CloudStack only" because the reason we call this method is to determine + // if we can remove a host from a VAG (we only want to allow the host to be removed from the VAG if there are + // no non-CloudStack volumes in it). + return true; + } + + List<Long> knownSfAccountsForCs = new ArrayList<>(); + + for (long volumeId : volumeIds) { + SolidFireVolume sfVolume = getVolume(sfConnection, volumeId); + long sfAccountId = sfVolume.getAccountId(); + + if (!knownSfAccountsForCs.contains(sfAccountId)) { + SolidFireAccount sfAccount = getAccountById(sfConnection, sfAccountId); + + if (sfAccount.getName().startsWith(SF_CS_ACCOUNT_PREFIX)) { + knownSfAccountsForCs.add(sfAccountId); + } + else { + return false; + } + } + } + + return true; + } + + private static boolean isStorageApplicableToZoneOrCluster(StoragePoolVO storagePoolVO, long clusterId, ClusterDao clusterDao) { + if (storagePoolVO.getClusterId() != null) { + if (storagePoolVO.getClusterId() == clusterId) { + return true; + } + } + else { + List<ClusterVO> clustersInZone = clusterDao.listByZoneId(storagePoolVO.getDataCenterId()); + + if (clustersInZone != null) { + for (ClusterVO clusterInZone : clustersInZone) { + if (clusterInZone.getId() == clusterId) { + return true; + } + } + } + } + + return false; + } + + public static void hostRemovedFromCluster(long hostId, long clusterId, String storageProvider, ClusterDao clusterDao, HostDao hostDao, + PrimaryDataStoreDao storagePoolDao, StoragePoolDetailsDao storagePoolDetailsDao) { + HostVO hostVO = hostDao.findByIdIncludingRemoved(hostId); + + Preconditions.checkArgument(hostVO != null, "Could not locate host for ID: " + hostId); + ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(s_lockTimeInSeconds)) { + if (!lock.lock(LOCK_TIME_IN_SECONDS)) { String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); - s_logger.debug(errMsg); + LOGGER.warn(errMsg); throw new CloudRuntimeException(errMsg); } @@ -366,26 +432,72 @@ public static void hostAddedToOrRemovedFromCluster(long hostId, long clusterId, List<SolidFireUtil.SolidFireConnection> sfConnections = new ArrayList<>(); for (StoragePoolVO storagePool : storagePools) { - ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePool.getId())); + if (!isStorageApplicableToZoneOrCluster(storagePool, clusterId, clusterDao)) { + continue; + } + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); + + if (!sfConnections.contains(sfConnection)) { + sfConnections.add(sfConnection); + + List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); + SolidFireVag sfVag = getVolumeAccessGroup(hostVO.getStorageUrl(), sfVags); - String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + if (sfVag != null && isCloudStackOnlyVag(sfConnection, sfVag)) { + removeInitiatorsFromSolidFireVag(sfConnection, sfVag.getId(), new String[] { hostVO.getStorageUrl() }); + } + } + } + } + } + finally { + lock.unlock(); + lock.releaseRef(); + } + } + + public static void hostAddedToCluster(long hostId, long clusterId, String storageProvider, ClusterDao clusterDao, HostDao hostDao, + PrimaryDataStoreDao storagePoolDao, StoragePoolDetailsDao storagePoolDetailsDao) { + HostVO hostVO = hostDao.findById(hostId); + + Preconditions.checkArgument(hostVO != null, "Could not locate host for ID: " + hostId); + + ClusterVO cluster = clusterDao.findById(clusterId); + + GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (vagId != null) { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); + if (!lock.lock(LOCK_TIME_IN_SECONDS)) { + String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); + + LOGGER.warn(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + try { + List<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(storageProvider); - if (!sfConnections.contains(sfConnection)) { - sfConnections.add(sfConnection); + if (storagePools != null && storagePools.size() > 0) { + List<SolidFireUtil.SolidFireConnection> sfConnections = new ArrayList<>(); - SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); + for (StoragePoolVO storagePool : storagePools) { + if (!isStorageApplicableToZoneOrCluster(storagePool, clusterId, clusterDao)) { + continue; + } - List<HostVO> hostsToAddOrRemove = new ArrayList<>(); - HostVO hostToAddOrRemove = hostDao.findByIdIncludingRemoved(hostId); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); - hostsToAddOrRemove.add(hostToAddOrRemove); + if (!sfConnections.contains(sfConnection)) { + sfConnections.add(sfConnection); - String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hostsToAddOrRemove), added); + List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); + SolidFireVag sfVag = getVolumeAccessGroup(hostVO.getStorageUrl(), sfVags); - SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), hostIqns, sfVag.getVolumeIds()); + if (sfVag != null) { + placeVolumeIdsInVag(sfConnection, sfVags, sfVag, hostVO, hostDao); + } else { + handleVagForHost(sfConnection, sfVags, hostVO, hostDao); } } } @@ -397,50 +509,285 @@ public static void hostAddedToOrRemovedFromCluster(long hostId, long clusterId, } } - public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId, - String vagUuid, List<HostVO> hosts, ClusterDetailsDao clusterDetailsDao) { - if (hosts == null || hosts.isEmpty()) { - throw new CloudRuntimeException("There must be at least one host in the cluster."); + // Put the host in an existing VAG or create a new one (only create a new one if all existing VAGs are full (i.e. 64 hosts max per VAG) and if + // creating a new VAG won't exceed 4 VAGs for the computer cluster). + // If none of the hosts in the cluster are in a VAG, then leave this host out of a VAG. + // Place applicable volume IDs in VAG, if need be (account of volume starts with SF_CS_ACCOUNT_PREFIX). + private static void handleVagForHost(SolidFireUtil.SolidFireConnection sfConnection, List<SolidFireUtil.SolidFireVag> sfVags, Host host, HostDao hostDao) { + List<HostVO> hostVOs = hostDao.findByClusterId(host.getClusterId()); + + if (hostVOs != null) { + int numVags = 0; + + Collections.shuffle(hostVOs, RANDOM); + + for (HostVO hostVO : hostVOs) { + if (hostVO.getId() != host.getId()) { + SolidFireVag sfVag = getVolumeAccessGroup(hostVO.getStorageUrl(), sfVags); + + if (sfVag != null) { + numVags++; + + // A volume should be visible to all hosts that are in the same compute cluster. That being the case, you + // can use MAX_NUM_VAGS_PER_VOLUME here. This is to limit the number of VAGs being used in a compute cluster + // to MAX_NUM_VAGS_PER_VOLUME. + if (numVags > MAX_NUM_VAGS_PER_VOLUME) { + throw new CloudRuntimeException("Can support at most four volume access groups per compute cluster (>)"); + } + + if (sfVag.getInitiators().length < MAX_NUM_INITIATORS_PER_VAG) { + if (!hostSupports_iScsi(host)) { + String errMsg = "Host with ID " + host.getId() + " does not support iSCSI."; + + LOGGER.warn(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + addInitiatorsToSolidFireVag(sfConnection, sfVag.getId(), new String[] { host.getStorageUrl() }); + + return; + } + } + } + } + + if (numVags == MAX_NUM_VAGS_PER_VOLUME) { + throw new CloudRuntimeException("Can support at most four volume access groups per compute cluster (==)"); + } + + if (numVags > 0) { + if (!hostSupports_iScsi(host)) { + String errMsg = "Host with ID " + host.getId() + " does not support iSCSI."; + + LOGGER.warn(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + SolidFireUtil.createVag(sfConnection, "CloudStack-" + UUID.randomUUID().toString(), + new String[]{host.getStorageUrl()}, getVolumeIds(sfConnection, sfVags, host, hostDao)); + } } + } - long lVagId; + /** + * Make use of the volume access group (VAG) of a random host in the cluster. With this VAG, collect all of its volume IDs that are for + * volumes that are in SolidFire accounts that are for CloudStack. + */ + private static long[] getVolumeIds(SolidFireUtil.SolidFireConnection sfConnection, List<SolidFireUtil.SolidFireVag> sfVags, + Host host, HostDao hostDao) { + List<Long> volumeIdsToReturn = new ArrayList<>(); - try { - lVagId = SolidFireUtil.createVag(sfConnection, "CloudStack-" + vagUuid, - SolidFireUtil.getIqnsFromHosts(hosts), new long[] { sfVolumeId }); + SolidFireVag sfVagForRandomHostInCluster = getVagForRandomHostInCluster(sfVags, host, hostDao); + + if (sfVagForRandomHostInCluster != null) { + long[] volumeIds = sfVagForRandomHostInCluster.getVolumeIds(); + + if (volumeIds != null) { + List<Long> knownSfAccountsForCs = new ArrayList<>(); + List<Long> knownSfAccountsNotForCs = new ArrayList<>(); + + for (long volumeId : volumeIds) { + SolidFireVolume sfVolume = getVolume(sfConnection, volumeId); + long sfAccountId = sfVolume.getAccountId(); + + if (knownSfAccountsForCs.contains(sfAccountId)) { + volumeIdsToReturn.add(volumeId); + } + else if (!knownSfAccountsNotForCs.contains(sfAccountId)) { + SolidFireAccount sfAccount = getAccountById(sfConnection, sfAccountId); + + if (sfAccount.getName().startsWith(SF_CS_ACCOUNT_PREFIX)) { + knownSfAccountsForCs.add(sfAccountId); + + volumeIdsToReturn.add(volumeId); + } + else { + knownSfAccountsNotForCs.add(sfAccountId); + } + } + } + } } - catch (Exception ex) { - String iqnInVagAlready1 = "Exceeded maximum number of Volume Access Groups per initiator"; - String iqnInVagAlready2 = "Exceeded maximum number of VolumeAccessGroups per Initiator"; - if (!ex.getMessage().contains(iqnInVagAlready1) && !ex.getMessage().contains(iqnInVagAlready2)) { - throw new CloudRuntimeException(ex.getMessage()); + return volumeIdsToReturn.stream().mapToLong(l -> l).toArray(); + } + + private static void placeVolumeIdsInVag(SolidFireUtil.SolidFireConnection sfConnection, List<SolidFireUtil.SolidFireVag> sfVags, + SolidFireVag sfVag, Host host, HostDao hostDao) { + SolidFireVag sfVagForRandomHostInCluster = getVagForRandomHostInCluster(sfVags, host, hostDao); + + if (sfVagForRandomHostInCluster != null) { + long[] volumeIds = sfVagForRandomHostInCluster.getVolumeIds(); + + if (volumeIds != null) { + List<Long> knownSfAccountsForCs = new ArrayList<>(); + List<Long> knownSfAccountsNotForCs = new ArrayList<>(); + + List<Long> newVolumeIds = new ArrayList<>(); + + for (long volumeId : volumeIds) { + SolidFireVolume sfVolume = getVolume(sfConnection, volumeId); + long sfAccountId = sfVolume.getAccountId(); + + if (knownSfAccountsForCs.contains(sfAccountId)) { + addVolumeIdToSolidFireVag(volumeId, sfVag, newVolumeIds); + } + else if (!knownSfAccountsNotForCs.contains(sfAccountId)) { + SolidFireAccount sfAccount = getAccountById(sfConnection, sfAccountId); + + if (sfAccount.getName().startsWith(SF_CS_ACCOUNT_PREFIX)) { + knownSfAccountsForCs.add(sfAccountId); + + addVolumeIdToSolidFireVag(volumeId, sfVag, newVolumeIds); + } + else { + knownSfAccountsNotForCs.add(sfAccountId); + } + } + } + + if (newVolumeIds.size() > 0) { + addVolumeIdsToSolidFireVag(sfConnection, sfVag.getId(), newVolumeIds.toArray(new Long[0])); + } } + } + } + + private static void addVolumeIdToSolidFireVag(long volumeId, SolidFireVag sfVag, List<Long> newVolumeIds) { + List<Long> existingVolumeIds = Longs.asList(sfVag.getVolumeIds()); - // getCompatibleVag throws an exception if an existing VAG can't be located - SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(sfConnection, hosts); + if (!existingVolumeIds.contains(volumeId) && !newVolumeIds.contains(volumeId)) { + newVolumeIds.add(volumeId); + } + } - lVagId = sfVag.getId(); + private static SolidFireVag getVagForRandomHostInCluster(List<SolidFireUtil.SolidFireVag> sfVags, Host host, HostDao hostDao) { + List<HostVO> hostVOs = hostDao.findByClusterId(host.getClusterId()); - long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); + if (hostVOs != null) { + Collections.shuffle(hostVOs, RANDOM); - SolidFireUtil.modifyVag(sfConnection, lVagId, sfVag.getInitiators(), volumeIds); + for (HostVO hostVO : hostVOs) { + if (hostVO.getId() != host.getId() && hostSupports_iScsi(hostVO)) { + SolidFireVag sfVag = getVolumeAccessGroup(hostVO.getStorageUrl(), sfVags); + + if (sfVag != null) { + return sfVag; + } + } + } } - ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId)); + return null; + } + + public static void placeVolumeInVolumeAccessGroups(SolidFireConnection sfConnection, long sfVolumeId, List<HostVO> hosts) { + if (!SolidFireUtil.hostsSupport_iScsi(hosts)) { + String errMsg = "Not all hosts in the compute cluster support iSCSI."; + + LOGGER.warn(errMsg); - clusterDetailsDao.persist(clusterDetail); + throw new CloudRuntimeException(errMsg); + } - return lVagId; + List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); + + Map<SolidFireUtil.SolidFireVag, List<String>> sfVagToIqnsMap = new HashMap<>(); + + for (HostVO hostVO : hosts) { + String iqn = hostVO.getStorageUrl(); + + SolidFireUtil.SolidFireVag sfVag = getVolumeAccessGroup(iqn, sfVags); + + List<String> iqnsInVag = sfVagToIqnsMap.computeIfAbsent(sfVag, k -> new ArrayList<>()); + + iqnsInVag.add(iqn); + } + + if (sfVagToIqnsMap.size() > MAX_NUM_VAGS_PER_VOLUME) { + throw new CloudRuntimeException("A SolidFire volume can be in at most four volume access groups simultaneously."); + } + + for (SolidFireUtil.SolidFireVag sfVag : sfVagToIqnsMap.keySet()) { + if (sfVag != null) { + if (!SolidFireUtil.isVolumeIdInSfVag(sfVolumeId, sfVag)) { + SolidFireUtil.addVolumeIdsToSolidFireVag(sfConnection, sfVag.getId(), new Long[] { sfVolumeId }); + } + } + else { + List<String> iqnsNotInVag = sfVagToIqnsMap.get(null); + + SolidFireUtil.createVag(sfConnection, "CloudStack-" + UUID.randomUUID().toString(), + iqnsNotInVag.toArray(new String[0]), new long[] { sfVolumeId }); + } + } + } + + public static SolidFireUtil.SolidFireVag getVolumeAccessGroup(String hostIqn, List<SolidFireUtil.SolidFireVag> sfVags) { + if (hostIqn == null) { + return null; + } + + hostIqn = hostIqn.toLowerCase(); + + if (sfVags != null) { + for (SolidFireUtil.SolidFireVag sfVag : sfVags) { + List<String> lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators()); + + // lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null + if (lstInitiators.contains(hostIqn)) { + return sfVag; + } + } + } + + return null; } - public static boolean hostsSupport_iScsi(List<HostVO> hosts) { + public static boolean sfVagContains(SolidFireUtil.SolidFireVag sfVag, long sfVolumeId, long clusterId, HostDao hostDao) { + if (isVolumeIdInSfVag(sfVolumeId, sfVag)) { + String[] iqns = sfVag.getInitiators(); + List<HostVO> hosts = hostDao.findByClusterId(clusterId); + + for (String iqn : iqns) { + for (HostVO host : hosts) { + String hostIqn = host.getStorageUrl(); + + if (iqn.equalsIgnoreCase(hostIqn)) { + return true; + } + } + } + } + + return false; + } + + private static boolean isVolumeIdInSfVag(long sfVolumeIdToCheck, SolidFireUtil.SolidFireVag sfVag) { + long[] sfVolumeIds = sfVag.getVolumeIds(); + + for (long sfVolumeId : sfVolumeIds) { + if (sfVolumeId == sfVolumeIdToCheck) { + return true; + } + } + + return false; + } + + private static boolean hostSupports_iScsi(Host host) { + return host != null && host.getStorageUrl() != null && host.getStorageUrl().trim().length() > 0 && host.getStorageUrl().startsWith("iqn"); + } + + private static boolean hostsSupport_iScsi(List<HostVO> hosts) { if (hosts == null || hosts.size() == 0) { return false; } for (Host host : hosts) { - if (host == null || host.getStorageUrl() == null || host.getStorageUrl().trim().length() == 0 || !host.getStorageUrl().startsWith("iqn")) { + if (!hostSupports_iScsi(host)) { return false; } } @@ -448,14 +795,6 @@ public static boolean hostsSupport_iScsi(List<HostVO> hosts) { return true; } - public static long[] getNewVolumeIds(long[] volumeIds, long volumeIdToAddOrRemove, boolean add) { - if (add) { - return getNewVolumeIdsAdd(volumeIds, volumeIdToAddOrRemove); - } - - return getNewVolumeIdsRemove(volumeIds, volumeIdToAddOrRemove); - } - public static String getVagKey(long storagePoolId) { return "sfVolumeAccessGroup_" + storagePoolId; } @@ -851,32 +1190,43 @@ private static long createVag(SolidFireConnection sfConnection, String vagName, return getSolidFireElement(sfConnection).createVolumeAccessGroup(request).getVolumeAccessGroupID(); } - public static void modifyVag(SolidFireConnection sfConnection, long vagId, String[] iqns, long[] volumeIds) { - ModifyVolumeAccessGroupRequest request = ModifyVolumeAccessGroupRequest.builder() + private static void addInitiatorsToSolidFireVag(SolidFireConnection sfConnection, long vagId, String[] initiators) { + AddInitiatorsToVolumeAccessGroupRequest request = AddInitiatorsToVolumeAccessGroupRequest.builder() .volumeAccessGroupID(vagId) - .optionalInitiators(iqns) - .optionalVolumes(Longs.asList(volumeIds).toArray(new Long[volumeIds.length])) + .initiators(initiators) .build(); - getSolidFireElement(sfConnection).modifyVolumeAccessGroup(request); + getSolidFireElement(sfConnection).addInitiatorsToVolumeAccessGroup(request); } - public static SolidFireVag getVag(SolidFireConnection sfConnection, long vagId) - { - ListVolumeAccessGroupsRequest request = ListVolumeAccessGroupsRequest.builder() - .optionalStartVolumeAccessGroupID(vagId) - .optionalLimit(1L) + private static void removeInitiatorsFromSolidFireVag(SolidFireConnection sfConnection, long vagId, String[] initiators) { + RemoveInitiatorsFromVolumeAccessGroupRequest request = RemoveInitiatorsFromVolumeAccessGroupRequest.builder() + .volumeAccessGroupID(vagId) + .initiators(initiators) .build(); - VolumeAccessGroup vag = getSolidFireElement(sfConnection).listVolumeAccessGroups(request).getVolumeAccessGroups()[0]; + getSolidFireElement(sfConnection).removeInitiatorsFromVolumeAccessGroup(request); + } - String[] vagIqns = vag.getInitiators(); - long[] vagVolumeIds = toPrimitive(vag.getVolumes()); + private static void addVolumeIdsToSolidFireVag(SolidFireConnection sfConnection, long vagId, Long[] volumeIds) { + AddVolumesToVolumeAccessGroupRequest request = AddVolumesToVolumeAccessGroupRequest.builder() + .volumeAccessGroupID(vagId) + .volumes(volumeIds) + .build(); - return new SolidFireVag(vagId, vagIqns, vagVolumeIds); + getSolidFireElement(sfConnection).addVolumesToVolumeAccessGroup(request); } - private static List<SolidFireVag> getAllVags(SolidFireConnection sfConnection) + public static void removeVolumeIdsFromSolidFireVag(SolidFireConnection sfConnection, long vagId, Long[] volumeIds) { + RemoveVolumesFromVolumeAccessGroupRequest request = RemoveVolumesFromVolumeAccessGroupRequest.builder() + .volumeAccessGroupID(vagId) + .volumes(volumeIds) + .build(); + + getSolidFireElement(sfConnection).removeVolumesFromVolumeAccessGroup(request); + } + + public static List<SolidFireVag> getAllVags(SolidFireConnection sfConnection) { ListVolumeAccessGroupsRequest request = ListVolumeAccessGroupsRequest.builder().build(); @@ -980,113 +1330,6 @@ private static int getPort(String keyToMatch, String url, int defaultPortNumber) return portNumber; } - private 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<String> lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList<String>(); - - 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<String> lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList<String>(); - - if (iqnsToRemove != null) { - for (String iqnToRemove : iqnsToRemove) { - lstIqns.remove(iqnToRemove); - } - } - - return lstIqns.toArray(new String[0]); - } - - private static long[] getNewVolumeIdsAdd(long[] volumeIds, long volumeIdToAdd) { - List<Long> 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<Long> 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<? extends Host> hosts) { - if (hosts == null || hosts.size() == 0) { - throw new CloudRuntimeException("There do not appear to be any hosts in this cluster."); - } - - List<String> lstIqns = new ArrayList<>(); - - for (Host host : hosts) { - lstIqns.add(host.getStorageUrl()); - } - - return lstIqns.toArray(new String[0]); - } - - // this method takes in a collection of hosts and tries to find an existing VAG that has all of them in it - // if successful, the VAG is returned; else, a CloudRuntimeException is thrown and this issue should be corrected by an admin - private static SolidFireUtil.SolidFireVag getCompatibleVag(SolidFireConnection sfConnection, List<HostVO> hosts) { - List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); - - if (sfVags != null) { - List<String> 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<String> lstInitiators = getStringArrayAsLowerCaseStringList(sfVag.getInitiators()); - - // lstInitiators should not be returned from getStringArrayAsLowerCaseStringList as null - if (lstInitiators.containsAll(hostIqns)) { - return sfVag; - } - } - } - - throw new CloudRuntimeException("Unable to locate the appropriate SolidFire Volume Access Group"); - } - private static List<String> getStringArrayAsLowerCaseStringList(String[] aString) { List<String> lstLowerCaseString = new ArrayList<>(); @@ -1106,10 +1349,6 @@ private static int getPort(String keyToMatch, String url, int defaultPortNumber) return null; } - Map<String, Object> convertedMap = new HashMap<>(); - - convertedMap.putAll(map); - - return convertedMap; + return new HashMap<>(map); } } diff --git a/test/integration/plugins/solidfire/TestAddRemoveHosts.py b/test/integration/plugins/solidfire/TestAddRemoveHosts.py index d9118dd6cab..1dd29bbcf1c 100644 --- a/test/integration/plugins/solidfire/TestAddRemoveHosts.py +++ b/test/integration/plugins/solidfire/TestAddRemoveHosts.py @@ -34,7 +34,7 @@ from marvin.lib.base import Account, ServiceOffering, User, Host, StoragePool, VirtualMachine # common - commonly used methods for all tests are listed here -from marvin.lib.common import get_domain, get_template, get_zone, list_hosts, list_clusters, list_volumes +from marvin.lib.common import get_domain, get_template, get_zone, list_clusters, list_hosts, list_volumes # utils - utility classes for common cleanup, external library wrappers, etc. from marvin.lib.utils import cleanup_resources @@ -46,14 +46,15 @@ # # Running the tests: # 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. +# 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. # # Note: -# If you do have more than one cluster, you might need to change this line: cls.cluster = list_clusters(cls.apiClient)[0] +# If you do have more than one cluster, you might need to change this line: cls.cluster = list_clusters(cls.apiClient)[0] and +# this variable's value: TestData.clusterId. class TestData: @@ -95,18 +96,18 @@ class TestData: # modify to control which hypervisor type to test hypervisor_type = xenServer xen_server_master_hostname = "XenServer-6.5-1" - kvm_1_ip_address = "10.117.40.112" - ip_address_of_new_xenserver_host = "10.117.40.107" - ip_address_of_new_kvm_host = "10.117.40.116" + kvm_1_ip_address = "10.117.40.111" + ip_address_of_new_xenserver_host = "10.117.40.118" + ip_address_of_new_kvm_host = "10.117.40.115" def __init__(self): self.testdata = { TestData.solidFire: { - TestData.mvip: "10.117.40.120", + TestData.mvip: "10.117.78.225", TestData.username: "admin", TestData.password: "admin", TestData.port: 443, - TestData.url: "https://10.117.40.120:443" + TestData.url: "https://10.117.78.225:443" }, TestData.kvm: { TestData.username: "root", @@ -147,7 +148,7 @@ def __init__(self): TestData.primaryStorage: { TestData.name: "SolidFire-%d" % random.randint(0, 100), TestData.scope: "ZONE", - TestData.url: "MVIP=10.117.40.120;SVIP=10.117.41.120;" + + TestData.url: "MVIP=10.117.78.225;SVIP=10.117.94.225;" + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", @@ -160,7 +161,7 @@ def __init__(self): TestData.primaryStorage2: { TestData.name: "SolidFireShared-%d" % random.randint(0, 100), TestData.scope: "CLUSTER", - TestData.url: "MVIP=10.117.40.120;SVIP=10.117.41.120;" + + TestData.url: "MVIP=10.117.78.225;SVIP=10.117.94.225;" + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + "minIops=5000;maxIops=50000;burstIops=75000", TestData.provider: "SolidFireShared", @@ -454,6 +455,143 @@ def test_add_remove_host_with_solidfire_plugin_4(self): self._perform_add_remove_xenserver_host(primary_storage_2.id, sf_iscsi_name) + # Make sure each host is in its own VAG. + # Create a VM that needs a new volume from the storage that has a VAG per host. + # Verify the volume is in all VAGs. + # Remove one of the hosts. + # Check that the IQN is no longer in its previous VAG, but that the volume ID is still in that VAG, though. + # Add the host back into the cluster. The IQN should be added to a VAG that already has an IQN from this cluster in it. + def test_vag_per_host_5(self): + hosts = list_hosts(self.apiClient, clusterid=self.cluster.id) + + self.assertTrue( + len(hosts) >= 2, + "There needs to be at least two hosts." + ) + + unique_vag_ids = self._get_unique_vag_ids(hosts) + + self.assertTrue(len(hosts) == len(unique_vag_ids), "To run this test, each host should be in its own VAG.") + + primarystorage = self.testdata[TestData.primaryStorage] + + primary_storage = StoragePool.create( + self.apiClient, + primarystorage, + scope=primarystorage[TestData.scope], + zoneid=self.zone.id, + provider=primarystorage[TestData.provider], + tags=primarystorage[TestData.tags], + capacityiops=primarystorage[TestData.capacityIops], + capacitybytes=primarystorage[TestData.capacityBytes], + hypervisor=primarystorage[TestData.hypervisor] + ) + + self.cleanup.append(primary_storage) + + self.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 + ) + + root_volume = self._get_root_volume(self.virtual_machine) + + sf_account_id = sf_util.get_sf_account_id(self.cs_api, self.account.id, primary_storage.id, self, TestAddRemoveHosts._sf_account_id_should_be_non_zero_int_err_msg) + + sf_volumes = sf_util.get_active_sf_volumes(self.sfe, sf_account_id) + + sf_volume = sf_util.check_and_get_sf_volume(sf_volumes, root_volume.name, self) + + sf_vag_ids = sf_util.get_vag_ids(self.cs_api, self.cluster.id, primary_storage.id, self) + + sf_util.check_vags(sf_volume, sf_vag_ids, self) + + host = Host(hosts[0].__dict__) + + host_iqn = self._get_host_iqn(host) + + all_vags = sf_util.get_all_vags(self.sfe) + + host_vag = self._get_host_vag(host_iqn, all_vags) + + self.assertTrue(host_vag != None, "The host should be in a VAG.") + + host.delete(self.apiClient) + + sf_volumes = sf_util.get_active_sf_volumes(self.sfe, sf_account_id) + + sf_volume = sf_util.check_and_get_sf_volume(sf_volumes, root_volume.name, self) + + sf_util.check_vags(sf_volume, sf_vag_ids, self) + + all_vags = sf_util.get_all_vags(self.sfe) + + host_vag = self._get_host_vag(host_iqn, all_vags) + + self.assertTrue(host_vag == None, "The host should not be in a VAG.") + + details = { + TestData.username: "root", + TestData.password: "solidfire", + TestData.url: "http://" + host.ipaddress, + TestData.podId : host.podid, + TestData.zoneId: host.zoneid + } + + host = Host.create( + self.apiClient, + self.cluster, + details, + hypervisor=host.hypervisor + ) + + self.assertTrue( + isinstance(host, Host), + "'host' is not a 'Host'." + ) + + hosts = list_hosts(self.apiClient, clusterid=self.cluster.id) + + unique_vag_ids = self._get_unique_vag_ids(hosts) + + self.assertTrue(len(hosts) == len(unique_vag_ids) + 1, "There should be one more host than unique VAG.") + + def _get_unique_vag_ids(self, hosts): + all_vags = sf_util.get_all_vags(self.sfe) + + unique_vag_ids = [] + + for host in hosts: + host = Host(host.__dict__) + + host_iqn = self._get_host_iqn(host) + + host_vag = self._get_host_vag(host_iqn, all_vags) + + if host_vag != None and host_vag.volume_access_group_id not in unique_vag_ids: + unique_vag_ids.append(host_vag.volume_access_group_id) + + return unique_vag_ids + + def _get_host_vag(self, host_iqn, vags): + self.assertTrue(host_iqn, "'host_iqn' should not be 'None'.") + self.assertTrue(vags, "'vags' should not be 'None'.") + + self.assertTrue(isinstance(host_iqn, basestring), "'host_iqn' should be a 'string'.") + self.assertTrue(isinstance(vags, list), "'vags' should be a 'list'.") + + for vag in vags: + if host_iqn in vag.initiators: + return vag + + return None + 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] @@ -463,7 +601,7 @@ def _perform_add_remove_xenserver_host(self, primary_storage_id, sr_name): num_pbds = len(pbds) - sf_vag_id = self._get_sf_vag_id(self.cluster.id, primary_storage_id) + sf_vag_id = sf_util.get_vag_id(self.cs_api, self.cluster.id, primary_storage_id, self) host_iscsi_iqns = self._get_xenserver_host_iscsi_iqns() @@ -604,7 +742,7 @@ def _perform_add_remove_xenserver_host(self, primary_storage_id, sr_name): ) def _perform_add_remove_kvm_host(self, primary_storage_id): - sf_vag_id = self._get_sf_vag_id(self.cluster.id, primary_storage_id) + sf_vag_id = sf_util.get_vag_id(self.cs_api, self.cluster.id, primary_storage_id, self) kvm_login = self.testdata[TestData.kvm] @@ -720,6 +858,14 @@ def _get_iqn_2(self, primary_storage): return sql_result[0][0] + def _get_host_iqn(self, host): + sql_query = "Select url From host Where uuid = '" + str(host.id) + "'" + + # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench + sql_result = self.dbConnection.execute(sql_query) + + return sql_result[0][0] + def _get_xenserver_host_iscsi_iqns(self): hosts = self.xen_session.xenapi.host.get_all() @@ -767,20 +913,6 @@ def _get_kvm_iqn(self, ip_address, username, password): 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} - sf_vag_id_result = self.cs_api.getSolidFireVolumeAccessGroupId(sf_vag_id_request) - sf_vag_id = sf_vag_id_result['apisolidfirevolumeaccessgroupid']['solidFireVolumeAccessGroupId'] - - self.assertEqual( - isinstance(sf_vag_id, int), - True, - TestAddRemoveHosts._vag_id_should_be_non_zero_int_err_msg - ) - - return sf_vag_id - def _get_sf_vag(self, sf_vag_id): return self.sfe.list_volume_access_groups(sf_vag_id, 1).volume_access_groups[0] diff --git a/test/integration/plugins/solidfire/TestCapacityManagement.py b/test/integration/plugins/solidfire/TestCapacityManagement.py index ab6eff124cd..0cc9db2dae1 100644 --- a/test/integration/plugins/solidfire/TestCapacityManagement.py +++ b/test/integration/plugins/solidfire/TestCapacityManagement.py @@ -33,7 +33,7 @@ from marvin.lib.base import Account, ServiceOffering, StoragePool, User, VirtualMachine # 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 +from marvin.lib.common import get_domain, get_template, get_zone, list_hosts # utils - utility classes for common cleanup, external library wrappers, etc. from marvin.lib.utils import cleanup_resources @@ -47,7 +47,7 @@ # If using XenServer, verify the "xen_server_hostname" variable is correct. # # Note: -# If you do have more than one cluster, you might need to change this line: cls.cluster = list_clusters(cls.apiClient)[0] +# If you do have more than one cluster, you might need to change this variable: TestData.clusterId. class TestData(): @@ -193,7 +193,6 @@ def setUpClass(cls): # Get Resources from Cloud Infrastructure cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) - cls.cluster = list_clusters(cls.apiClient)[0] cls.template = get_template(cls.apiClient, cls.zone.id, hypervisor=TestData.hypervisor_type) cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) diff --git a/test/integration/plugins/solidfire/TestSnapshots.py b/test/integration/plugins/solidfire/TestSnapshots.py index fab509e4b69..d9ab3b2b3e9 100644 --- a/test/integration/plugins/solidfire/TestSnapshots.py +++ b/test/integration/plugins/solidfire/TestSnapshots.py @@ -35,7 +35,7 @@ from marvin.lib.base import Account, DiskOffering, ServiceOffering, Snapshot, StoragePool, Template, User, VirtualMachine, Volume # common - commonly used methods for all tests are listed here -from marvin.lib.common import get_domain, get_template, get_zone, list_clusters, list_volumes, list_snapshots +from marvin.lib.common import get_domain, get_template, get_zone, list_volumes, list_snapshots # utils - utility classes for common cleanup, external library wrappers, etc. from marvin.lib.utils import cleanup_resources, wait_until @@ -87,16 +87,16 @@ class TestData(): def __init__(self): self.testdata = { TestData.solidFire: { - TestData.mvip: "10.117.40.120", + TestData.mvip: "10.117.78.225", TestData.username: "admin", TestData.password: "admin", TestData.port: 443, - TestData.url: "https://10.117.40.120:443" + TestData.url: "https://10.117.78.225:443" }, TestData.primaryStorage: { "name": "SolidFire-%d" % random.randint(0, 100), TestData.scope: "ZONE", - "url": "MVIP=10.117.40.120;SVIP=10.117.41.120;" + + "url": "MVIP=10.117.78.225;SVIP=10.117.94.225;" + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", @@ -155,7 +155,6 @@ def __init__(self): TestData.diskName: "test-volume-2", }, TestData.zoneId: 1, - TestData.clusterId: 1, TestData.domainId: 1, TestData.url: "10.117.40.114" } @@ -198,7 +197,6 @@ def setUpClass(cls): # Get Resources from Cloud Infrastructure cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) - cls.cluster = list_clusters(cls.apiClient)[0] cls.template = get_template(cls.apiClient, cls.zone.id, hypervisor=TestData.hypervisor_type) cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) diff --git a/test/integration/plugins/solidfire/TestUploadDownload.py b/test/integration/plugins/solidfire/TestUploadDownload.py index d81600e9128..a15f27b98bf 100644 --- a/test/integration/plugins/solidfire/TestUploadDownload.py +++ b/test/integration/plugins/solidfire/TestUploadDownload.py @@ -185,7 +185,7 @@ def setUpClass(cls): # Get Resources from Cloud Infrastructure cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) - cls.cluster = list_clusters(cls.apiClient)[1] + cls.cluster = list_clusters(cls.apiClient)[0] cls.template = get_template(cls.apiClient, cls.zone.id, hypervisor=TestData.hypervisor_type) cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) diff --git a/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py b/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py index 93ab3b6ff61..7da6c9d542b 100644 --- a/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py +++ b/test/integration/plugins/solidfire/TestVMMigrationWithStorage.py @@ -40,6 +40,9 @@ # Only one zone # Only one pod # Two clusters (have system VMs (including the VR) running on local or NFS storage) +# +# Running the tests: +# Verify the "xen_server_hostname_src" and "xen_server_hostname_dest" variables are correct. class TestData(): @@ -81,6 +84,9 @@ class TestData(): xenServer = "xenserver" zoneId = "zoneid" + xen_server_hostname_src = "XenServer-6.5-1" + xen_server_hostname_dest = "XenServer-6.5-3" + def __init__(self): self.testdata = { TestData.solidFire: { @@ -233,7 +239,7 @@ def setUpClass(cls): # Set up xenAPI connection host_ip = "https://" + \ - list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId1], name="XenServer-6.5-1")[0].ipaddress + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId1], name=TestData.xen_server_hostname_src)[0].ipaddress # Set up XenAPI connection cls.xen_session_1 = XenAPI.Session(host_ip) @@ -242,7 +248,7 @@ def setUpClass(cls): # Set up xenAPI connection host_ip = "https://" + \ - list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId2], name="XenServer-6.5-3")[0].ipaddress + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId2], name=TestData.xen_server_hostname_dest)[0].ipaddress # Set up XenAPI connection cls.xen_session_2 = XenAPI.Session(host_ip) @@ -532,9 +538,9 @@ def _get_source_and_dest_hosts(self): hosts = list_hosts(self.apiClient) for host in hosts: - if host.name == "XenServer-6.5-1": + if host.name == TestData.xen_server_hostname_src: src_host = host - elif host.name == "XenServer-6.5-3": + elif host.name == TestData.xen_server_hostname_dest: dest_host = host self.assertIsNotNone(src_host, "Could not locate the source host") diff --git a/test/integration/plugins/solidfire/TestVMSnapshots.py b/test/integration/plugins/solidfire/TestVMSnapshots.py index 45c42429843..106d5836fa7 100644 --- a/test/integration/plugins/solidfire/TestVMSnapshots.py +++ b/test/integration/plugins/solidfire/TestVMSnapshots.py @@ -44,6 +44,10 @@ # Only one pod # Only one cluster +# 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. + class TestData: account = "account" @@ -74,6 +78,7 @@ class TestData: # modify to control which hypervisor type to test hypervisor_type = xenServer + xen_server_hostname = "XenServer-6.5-1" def __init__(self): self.testdata = { @@ -129,7 +134,7 @@ def __init__(self): "customizediops": False, "miniops": "10000", "maxiops": "15000", - "hypervisorsnapshotreserve": 200, + "hypervisorsnapshotreserve": 400, TestData.tags: TestData.storageTag }, TestData.diskOffering: { @@ -139,7 +144,7 @@ def __init__(self): "customizediops": False, "miniops": 300, "maxiops": 500, - "hypervisorsnapshotreserve": 200, + "hypervisorsnapshotreserve": 400, TestData.tags: TestData.storageTag, "storagetype": "shared" }, @@ -179,7 +184,7 @@ def setUpClass(cls): # Set up XenAPI connection host_ip = "https://" + \ - list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress + list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name=TestData.xen_server_hostname)[0].ipaddress cls.xen_session = XenAPI.Session(host_ip) diff --git a/test/integration/plugins/solidfire/TestVolumes.py b/test/integration/plugins/solidfire/TestVolumes.py index 9d3ab2f43ee..9685e509cb8 100644 --- a/test/integration/plugins/solidfire/TestVolumes.py +++ b/test/integration/plugins/solidfire/TestVolumes.py @@ -51,7 +51,8 @@ # If using XenServer, change the "supports_cloning" variable to True or False as desired. # # Note: -# If you do have more than one cluster, you might need to change this line: cls.cluster = list_clusters(cls.apiClient)[0] +# If you do have more than one cluster, you might need to change this line: cls.cluster = list_clusters(cls.apiClient)[0] and +# this variable's value: TestData.clusterId. class TestData(): @@ -79,6 +80,7 @@ class TestData(): tags = "tags" templateCacheNameKvm = "centos55-x86-64" templateCacheNameXenServer = "centos56-x86-64-xen" + # templateCacheNameXenServer = "centos65-x86-64-XenServer" testAccount = "testaccount" url = "url" user = "user" @@ -91,17 +93,17 @@ class TestData(): zoneId = "zoneId" # modify to control which hypervisor type to test - hypervisor_type = kvm + hypervisor_type = xenServer xen_server_hostname = "XenServer-6.5-1" def __init__(self): self.testdata = { TestData.solidFire: { - TestData.mvip: "10.117.40.120", + TestData.mvip: "10.117.78.225", TestData.username: "admin", TestData.password: "admin", TestData.port: 443, - TestData.url: "https://10.117.40.120:443" + TestData.url: "https://10.117.78.225:443" }, TestData.kvm: { TestData.username: "root", @@ -135,7 +137,7 @@ def __init__(self): TestData.primaryStorage: { "name": "SolidFire-%d" % random.randint(0, 100), TestData.scope: "ZONE", - "url": "MVIP=10.117.40.120;SVIP=10.117.41.120;" + + "url": "MVIP=10.117.78.225;SVIP=10.117.94.225;" + "clusterAdminUsername=admin;clusterAdminPassword=admin;" + "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services