mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Merge pull request #2503 from mike-tutkowski/multi-sf-vags
Support multiple volume access groups per compute cluster
This commit is contained in:
		
						commit
						99bc0e6677
					
				| @ -1654,18 +1654,18 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy { | |||||||
|         details.put(ModifyTargetsCommand.STORAGE_HOST, storagePool.getHostAddress()); |         details.put(ModifyTargetsCommand.STORAGE_HOST, storagePool.getHostAddress()); | ||||||
|         details.put(ModifyTargetsCommand.STORAGE_PORT, String.valueOf(storagePool.getPort())); |         details.put(ModifyTargetsCommand.STORAGE_PORT, String.valueOf(storagePool.getPort())); | ||||||
| 
 | 
 | ||||||
|         ModifyTargetsCommand modifyTargetsCommand = new ModifyTargetsCommand(); |         ModifyTargetsCommand cmd = new ModifyTargetsCommand(); | ||||||
| 
 | 
 | ||||||
|         List<Map<String, String>> targets = new ArrayList<>(); |         List<Map<String, String>> targets = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|         targets.add(details); |         targets.add(details); | ||||||
| 
 | 
 | ||||||
|         modifyTargetsCommand.setTargets(targets); |         cmd.setTargets(targets); | ||||||
|         modifyTargetsCommand.setApplyToAllHostsInCluster(true); |         cmd.setApplyToAllHostsInCluster(true); | ||||||
|         modifyTargetsCommand.setAdd(add); |         cmd.setAdd(add); | ||||||
|         modifyTargetsCommand.setTargetTypeToRemove(ModifyTargetsCommand.TargetTypeToRemove.DYNAMIC); |         cmd.setTargetTypeToRemove(ModifyTargetsCommand.TargetTypeToRemove.DYNAMIC); | ||||||
| 
 | 
 | ||||||
|         return modifyTargetsCommand; |         return cmd; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private List<String> sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { |     private List<String> sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { | ||||||
|  | |||||||
| @ -26,16 +26,16 @@ import org.apache.cloudstack.api.ApiConstants; | |||||||
| import org.apache.cloudstack.api.APICommand; | import org.apache.cloudstack.api.APICommand; | ||||||
| import org.apache.cloudstack.api.BaseCmd; | import org.apache.cloudstack.api.BaseCmd; | ||||||
| import org.apache.cloudstack.api.Parameter; | 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.context.CallContext; | ||||||
| import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; | import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; | ||||||
| import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; | 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) |         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) | ||||||
| public class GetSolidFireVolumeAccessGroupIdCmd extends BaseCmd { | public class GetSolidFireVolumeAccessGroupIdsCmd extends BaseCmd { | ||||||
|     private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeAccessGroupIdCmd.class.getName()); |     private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeAccessGroupIdsCmd.class.getName()); | ||||||
|     private static final String NAME = "getsolidfirevolumeaccessgroupidresponse"; |     private static final String NAME = "getsolidfirevolumeaccessgroupidsresponse"; | ||||||
| 
 | 
 | ||||||
|     @Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.STRING, description = "Cluster UUID", required = true) |     @Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.STRING, description = "Cluster UUID", required = true) | ||||||
|     private String clusterUuid; |     private String clusterUuid; | ||||||
| @ -67,14 +67,14 @@ public class GetSolidFireVolumeAccessGroupIdCmd extends BaseCmd { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void execute() { |     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.setResponseName(getCommandName()); | ||||||
|         response.setObjectName("apisolidfirevolumeaccessgroupid"); |         response.setObjectName("apisolidfirevolumeaccessgroupids"); | ||||||
| 
 | 
 | ||||||
|         this.setResponseObject(response); |         this.setResponseObject(response); | ||||||
|     } |     } | ||||||
| @ -22,12 +22,12 @@ import com.google.gson.annotations.SerializedName; | |||||||
| 
 | 
 | ||||||
| import org.apache.cloudstack.api.BaseResponse; | import org.apache.cloudstack.api.BaseResponse; | ||||||
| 
 | 
 | ||||||
| public class ApiSolidFireVolumeAccessGroupIdResponse extends BaseResponse { | public class ApiSolidFireVolumeAccessGroupIdsResponse extends BaseResponse { | ||||||
|     @SerializedName("solidFireVolumeAccessGroupId") |     @SerializedName("solidFireVolumeAccessGroupIds") | ||||||
|     @Param(description = "SolidFire Volume Access Group Id") |     @Param(description = "SolidFire Volume Access Group Ids") | ||||||
|     private long solidFireVolumeAccessGroupId; |     private long[] solidFireVolumeAccessGroupIds; | ||||||
| 
 | 
 | ||||||
|     public ApiSolidFireVolumeAccessGroupIdResponse(long sfVolumeAccessGroupId) { |     public ApiSolidFireVolumeAccessGroupIdsResponse(long[] sfVolumeAccessGroupIds) { | ||||||
|         solidFireVolumeAccessGroupId = sfVolumeAccessGroupId; |         solidFireVolumeAccessGroupIds = sfVolumeAccessGroupIds; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -22,7 +22,7 @@ import java.util.ArrayList; | |||||||
| import org.apache.cloudstack.api.command.admin.solidfire.GetPathForVolumeCmd; | import org.apache.cloudstack.api.command.admin.solidfire.GetPathForVolumeCmd; | ||||||
| // import org.apache.log4j.Logger; | // import org.apache.log4j.Logger; | ||||||
| import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireAccountIdCmd; | 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.GetVolumeSnapshotDetailsCmd; | ||||||
| import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeiScsiNameCmd; | import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeiScsiNameCmd; | ||||||
| import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeSizeCmd; | import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeSizeCmd; | ||||||
| @ -38,7 +38,7 @@ public class ApiSolidFireIntegrationTestServiceImpl extends AdapterBase implemen | |||||||
| 
 | 
 | ||||||
|         cmdList.add(GetPathForVolumeCmd.class); |         cmdList.add(GetPathForVolumeCmd.class); | ||||||
|         cmdList.add(GetSolidFireAccountIdCmd.class); |         cmdList.add(GetSolidFireAccountIdCmd.class); | ||||||
|         cmdList.add(GetSolidFireVolumeAccessGroupIdCmd.class); |         cmdList.add(GetSolidFireVolumeAccessGroupIdsCmd.class); | ||||||
|         cmdList.add(GetVolumeiScsiNameCmd.class); |         cmdList.add(GetVolumeiScsiNameCmd.class); | ||||||
|         cmdList.add(GetSolidFireVolumeSizeCmd.class); |         cmdList.add(GetSolidFireVolumeSizeCmd.class); | ||||||
|         cmdList.add(GetVolumeSnapshotDetailsCmd.class); |         cmdList.add(GetVolumeSnapshotDetailsCmd.class); | ||||||
|  | |||||||
| @ -18,6 +18,6 @@ package org.apache.cloudstack.solidfire; | |||||||
| 
 | 
 | ||||||
| public interface SolidFireIntegrationTestManager { | public interface SolidFireIntegrationTestManager { | ||||||
|     long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid); |     long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid); | ||||||
|     long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid); |     long[] getSolidFireVolumeAccessGroupIds(String csClusterUuid, String storagePoolUuid); | ||||||
|     long getSolidFireVolumeSize(String volumeUuid); |     long getSolidFireVolumeSize(String volumeUuid); | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,8 +16,8 @@ | |||||||
| // under the License. | // under the License. | ||||||
| package org.apache.cloudstack.solidfire; | package org.apache.cloudstack.solidfire; | ||||||
| 
 | 
 | ||||||
| import com.cloud.dc.ClusterDetailsDao; | import com.cloud.host.HostVO; | ||||||
| import com.cloud.dc.ClusterDetailsVO; | import com.cloud.host.dao.HostDao; | ||||||
| import com.cloud.storage.VolumeDetailVO; | import com.cloud.storage.VolumeDetailVO; | ||||||
| import com.cloud.storage.VolumeVO; | import com.cloud.storage.VolumeVO; | ||||||
| import com.cloud.storage.dao.VolumeDao; | import com.cloud.storage.dao.VolumeDao; | ||||||
| @ -26,18 +26,21 @@ import com.cloud.user.AccountDetailVO; | |||||||
| import com.cloud.user.AccountDetailsDao; | import com.cloud.user.AccountDetailsDao; | ||||||
| import com.cloud.utils.exception.CloudRuntimeException; | 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.storage.datastore.util.SolidFireUtil; | ||||||
| import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; | import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
| 
 | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
| import javax.inject.Inject; | import javax.inject.Inject; | ||||||
| 
 | 
 | ||||||
| @Component | @Component | ||||||
| public class SolidFireIntegrationTestManagerImpl implements SolidFireIntegrationTestManager { | public class SolidFireIntegrationTestManagerImpl implements SolidFireIntegrationTestManager { | ||||||
| 
 |  | ||||||
|     @Inject private AccountDetailsDao accountDetailsDao; |     @Inject private AccountDetailsDao accountDetailsDao; | ||||||
|     @Inject private ClusterDetailsDao clusterDetailsDao; |     @Inject private HostDao hostDao; | ||||||
|     @Inject private SolidFireIntegrationTestUtil util; |     @Inject private SolidFireIntegrationTestUtil util; | ||||||
|  |     @Inject private StoragePoolDetailsDao storagePoolDetailsDao; | ||||||
|     @Inject private VolumeDao volumeDao; |     @Inject private VolumeDao volumeDao; | ||||||
|     @Inject private VolumeDetailsDao volumeDetailsDao; |     @Inject private VolumeDetailsDao volumeDetailsDao; | ||||||
| 
 | 
 | ||||||
| @ -48,7 +51,7 @@ public class SolidFireIntegrationTestManagerImpl implements SolidFireIntegration | |||||||
| 
 | 
 | ||||||
|         AccountDetailVO accountDetail = accountDetailsDao.findDetail(csAccountId, SolidFireUtil.getAccountKey(storagePoolId)); |         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); |             throw new CloudRuntimeException("Unable to find SF account for storage " + storagePoolUuid + " for CS account " + csAccountUuid); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -58,14 +61,35 @@ public class SolidFireIntegrationTestManagerImpl implements SolidFireIntegration | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid) { |     public long[] getSolidFireVolumeAccessGroupIds(String csClusterUuid, String storagePoolUuid) { | ||||||
|         long csClusterId = util.getClusterIdForClusterUuid(csClusterUuid); |  | ||||||
|         long storagePoolId = util.getStoragePoolIdForStoragePoolUuid(storagePoolUuid); |         long storagePoolId = util.getStoragePoolIdForStoragePoolUuid(storagePoolUuid); | ||||||
| 
 | 
 | ||||||
|         ClusterDetailsVO clusterDetails = clusterDetailsDao.findDetail(csClusterId, SolidFireUtil.getVagKey(storagePoolId)); |         SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); | ||||||
|         String sfVagId = clusterDetails.getValue(); |  | ||||||
| 
 | 
 | ||||||
|         return Long.parseLong(sfVagId); |         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 vagIds.stream().mapToLong(l -> l).toArray(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | |||||||
| @ -145,6 +145,7 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
| 
 | 
 | ||||||
|     private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); |     private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); | ||||||
|     private static final int DEFAULT_NFS_PORT = 2049; |     private static final int DEFAULT_NFS_PORT = 2049; | ||||||
|  |     private static final int SECONDS_TO_WAIT_FOR_DATASTORE = 120; | ||||||
| 
 | 
 | ||||||
|     private final VmwareHostService hostService; |     private final VmwareHostService hostService; | ||||||
|     private boolean _fullCloneFlag; |     private boolean _fullCloneFlag; | ||||||
| @ -2602,8 +2603,7 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void waitForAllHostsToSeeDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { |     private void waitForAllHostsToSeeDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { | ||||||
|         long secondsToWait = 120; |         long endWaitTime = System.currentTimeMillis() + SECONDS_TO_WAIT_FOR_DATASTORE * 1000; | ||||||
|         long endWaitTime = System.currentTimeMillis() + secondsToWait * 1000; |  | ||||||
| 
 | 
 | ||||||
|         boolean isConditionMet = false; |         boolean isConditionMet = false; | ||||||
| 
 | 
 | ||||||
| @ -2621,7 +2621,7 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
|     private boolean verifyAllHostsSeeDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { |     private boolean verifyAllHostsSeeDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { | ||||||
|         int numHostsChecked = 0; |         int numHostsChecked = 0; | ||||||
| 
 | 
 | ||||||
|         for (Pair<ManagedObjectReference, String> host: lstHosts) { |         for (Pair<ManagedObjectReference, String> host : lstHosts) { | ||||||
|             ManagedObjectReference morHostToMatch = host.first(); |             ManagedObjectReference morHostToMatch = host.first(); | ||||||
|             HostMO hostToMatchMO = new HostMO(dsMO.getContext(), morHostToMatch); |             HostMO hostToMatchMO = new HostMO(dsMO.getContext(), morHostToMatch); | ||||||
| 
 | 
 | ||||||
| @ -2641,8 +2641,7 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void waitForAllHostsToMountDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { |     private void waitForAllHostsToMountDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { | ||||||
|         long secondsToWait = 120; |         long endWaitTime = System.currentTimeMillis() + SECONDS_TO_WAIT_FOR_DATASTORE * 1000; | ||||||
|         long endWaitTime = System.currentTimeMillis() + secondsToWait * 1000; |  | ||||||
| 
 | 
 | ||||||
|         boolean isConditionMet = false; |         boolean isConditionMet = false; | ||||||
| 
 | 
 | ||||||
| @ -2657,13 +2656,39 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private boolean verifyAllHostsMountedDatastore(List<Pair<ManagedObjectReference, String>> lstHosts, DatastoreMO dsMO) throws Exception { |     private void waitForAllHostsToMountDatastore2(List<HostMO> lstHosts, DatastoreMO dsMO) throws Exception { | ||||||
|         int numHostsChecked = 0; |         long endWaitTime = System.currentTimeMillis() + SECONDS_TO_WAIT_FOR_DATASTORE * 1000; | ||||||
| 
 | 
 | ||||||
|         for (Pair<ManagedObjectReference, String> host: lstHosts) { |         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 { | ||||||
|  |         List<HostMO> hostMOs = new ArrayList<>(lstHosts.size()); | ||||||
|  | 
 | ||||||
|  |         for (Pair<ManagedObjectReference, String> host : lstHosts) { | ||||||
|             ManagedObjectReference morHostToMatch = host.first(); |             ManagedObjectReference morHostToMatch = host.first(); | ||||||
|             HostMO hostToMatchMO = new HostMO(dsMO.getContext(), morHostToMatch); |             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(); |             List<DatastoreHostMount> datastoreHostMounts = dsMO.getHostMounts(); | ||||||
| 
 | 
 | ||||||
|             for (DatastoreHostMount datastoreHostMount : datastoreHostMounts) { |             for (DatastoreHostMount datastoreHostMount : datastoreHostMounts) { | ||||||
| @ -2753,6 +2778,16 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
|         for (Pair<ManagedObjectReference, String> host : hosts) { |         for (Pair<ManagedObjectReference, String> host : hosts) { | ||||||
|             HostMO hostMO = new HostMO(dsMO.getContext(), host.first()); |             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)) { |             if (!isDatastoreMounted(dsMO, hostMO)) { | ||||||
|                 HostStorageSystemMO hostStorageSystemMO = hostMO.getHostStorageSystemMO(); |                 HostStorageSystemMO hostStorageSystemMO = hostMO.getHostStorageSystemMO(); | ||||||
| 
 | 
 | ||||||
| @ -2760,11 +2795,15 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
|                     hostStorageSystemMO.mountVmfsVolume(getDatastoreUuid(dsMO, hostMO)); |                     hostStorageSystemMO.mountVmfsVolume(getDatastoreUuid(dsMO, hostMO)); | ||||||
|                 } |                 } | ||||||
|                 catch (InvalidStateFaultMsg ex) { |                 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 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
| 
 | 
 | ||||||
|     private void unmountVmfsDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String datastoreName, |     private void unmountVmfsDatastore(VmwareContext context, VmwareHypervisorHost hyperHost, String datastoreName, | ||||||
|                                       List<Pair<ManagedObjectReference, String>> hosts) throws Exception { |                                       List<Pair<ManagedObjectReference, String>> hosts) throws Exception { | ||||||
|         ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, datastoreName); |  | ||||||
|         DatastoreMO dsMO = new DatastoreMO(context, morDs); |  | ||||||
| 
 |  | ||||||
|         for (Pair<ManagedObjectReference, String> host : hosts) { |         for (Pair<ManagedObjectReference, String> host : hosts) { | ||||||
|             HostMO hostMO = new HostMO(context, host.first()); |             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 (HostMO hostMO : hosts) { | ||||||
|  |             unmountVmfsVolume(dsMO, hostMO); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void unmountVmfsVolume(DatastoreMO dsMO, HostMO hostMO) throws Exception { | ||||||
|  |         if (isDatastoreMounted(dsMO, hostMO)) { | ||||||
|             HostStorageSystemMO hostStorageSystemMO = hostMO.getHostStorageSystemMO(); |             HostStorageSystemMO hostStorageSystemMO = hostMO.getHostStorageSystemMO(); | ||||||
| 
 | 
 | ||||||
|             hostStorageSystemMO.unmountVmfsVolume(getDatastoreUuid(dsMO, hostMO)); |             hostStorageSystemMO.unmountVmfsVolume(getDatastoreUuid(dsMO, hostMO)); | ||||||
| @ -2902,6 +2958,20 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
| 
 | 
 | ||||||
|                         if (rescan) { |                         if (rescan) { | ||||||
|                             rescanAllHosts(hosts, true, false); |                             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) { |                     catch (Exception ex) { | ||||||
| @ -2924,26 +2994,9 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
| 
 | 
 | ||||||
|                 if (targetsToRemove.size() > 0) { |                 if (targetsToRemove.size() > 0) { | ||||||
|                     if (isRemoveAsync) { |                     if (isRemoveAsync) { | ||||||
|                         new Thread(() -> { |                         new Thread(() -> handleRemove(targetsToRemove, host, hosts)).start(); | ||||||
|                             try { |  | ||||||
|                                 addRemoveInternetScsiTargetsToAllHosts(false, targetsToRemove, hosts); |  | ||||||
| 
 |  | ||||||
|                                 rescanAllHosts(hosts, true, false); |  | ||||||
|                             } catch (Exception ex) { |  | ||||||
|                                 s_logger.warn(ex.getMessage()); |  | ||||||
|                             } |  | ||||||
|                         }).start(); |  | ||||||
|                     } else { |                     } else { | ||||||
|                         executorService.submit(new Thread(() -> { |                         executorService.submit(new Thread(() -> handleRemove(targetsToRemove, host, hosts))); | ||||||
|                             try { |  | ||||||
|                                 addRemoveInternetScsiTargetsToAllHosts(false, targetsToRemove, hosts); |  | ||||||
| 
 |  | ||||||
|                                 rescanAllHosts(hosts, true, false); |  | ||||||
|                             } |  | ||||||
|                             catch (Exception ex) { |  | ||||||
|                                 s_logger.warn(ex.getMessage()); |  | ||||||
|                             } |  | ||||||
|                         })); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -2956,6 +3009,60 @@ public class VmwareStorageProcessor implements StorageProcessor { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     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, |     private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List<HostInternetScsiHbaStaticTarget> targets, | ||||||
|                                                         List<Pair<ManagedObjectReference, String>> hostPairs) throws Exception { |                                                         List<Pair<ManagedObjectReference, String>> hostPairs) throws Exception { | ||||||
|         List<HostMO> hosts = new ArrayList<>(); |         List<HostMO> hosts = new ArrayList<>(); | ||||||
|  | |||||||
| @ -30,8 +30,6 @@ import com.cloud.agent.api.to.DataStoreTO; | |||||||
| import com.cloud.agent.api.to.DataTO; | import com.cloud.agent.api.to.DataTO; | ||||||
| import com.cloud.agent.api.to.DiskTO; | import com.cloud.agent.api.to.DiskTO; | ||||||
| import com.cloud.dc.ClusterVO; | import com.cloud.dc.ClusterVO; | ||||||
| import com.cloud.dc.ClusterDetailsVO; |  | ||||||
| import com.cloud.dc.ClusterDetailsDao; |  | ||||||
| import com.cloud.dc.dao.ClusterDao; | import com.cloud.dc.dao.ClusterDao; | ||||||
| import com.cloud.host.Host; | import com.cloud.host.Host; | ||||||
| import com.cloud.host.HostVO; | import com.cloud.host.HostVO; | ||||||
| @ -88,7 +86,6 @@ import org.apache.log4j.Logger; | |||||||
| 
 | 
 | ||||||
| public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | ||||||
|     private static final Logger LOGGER = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class); |     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 int LOWEST_HYPERVISOR_SNAPSHOT_RESERVE = 10; | ||||||
|     private static final long MIN_IOPS_FOR_TEMPLATE_VOLUME = 100L; |     private static final long MIN_IOPS_FOR_TEMPLATE_VOLUME = 100L; | ||||||
|     private static final long MAX_IOPS_FOR_TEMPLATE_VOLUME = 20000L; |     private static final long MAX_IOPS_FOR_TEMPLATE_VOLUME = 20000L; | ||||||
| @ -102,7 +99,6 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
|     @Inject private AccountDao accountDao; |     @Inject private AccountDao accountDao; | ||||||
|     @Inject private AccountDetailsDao accountDetailsDao; |     @Inject private AccountDetailsDao accountDetailsDao; | ||||||
|     @Inject private ClusterDao clusterDao; |     @Inject private ClusterDao clusterDao; | ||||||
|     @Inject private ClusterDetailsDao clusterDetailsDao; |  | ||||||
|     @Inject private DataStoreManager dataStoreMgr; |     @Inject private DataStoreManager dataStoreMgr; | ||||||
|     @Inject private HostDao hostDao; |     @Inject private HostDao hostDao; | ||||||
|     @Inject private SnapshotDao snapshotDao; |     @Inject private SnapshotDao snapshotDao; | ||||||
| @ -147,14 +143,8 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
|         return null; |         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 |     @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(dataObject != null, "'dataObject' should not be 'null'"); | ||||||
|         Preconditions.checkArgument(host != null, "'host' should not be 'null'"); |         Preconditions.checkArgument(host != null, "'host' should not be 'null'"); | ||||||
|         Preconditions.checkArgument(dataStore != null, "'dataStore' should not be 'null'"); |         Preconditions.checkArgument(dataStore != null, "'dataStore' should not be 'null'"); | ||||||
| @ -167,7 +157,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
| 
 | 
 | ||||||
|         GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); |         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(); |             String errMsg = "Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid(); | ||||||
| 
 | 
 | ||||||
|             LOGGER.warn(errMsg); |             LOGGER.warn(errMsg); | ||||||
| @ -176,32 +166,11 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); |  | ||||||
| 
 |  | ||||||
|             String vagId = clusterDetail != null ? clusterDetail.getValue() : null; |  | ||||||
| 
 |  | ||||||
|             List<HostVO> hosts = hostDao.findByClusterId(clusterId); |             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); |             SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); | ||||||
| 
 | 
 | ||||||
|             if (vagId != null) { |             SolidFireUtil.placeVolumeInVolumeAccessGroups(sfConnection, sfVolumeId, hosts); | ||||||
|                 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); |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| @ -211,9 +180,6 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // 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 |     @Override | ||||||
|     public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) |     public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) | ||||||
|     { |     { | ||||||
| @ -229,27 +195,23 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
| 
 | 
 | ||||||
|         GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); |         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(); |             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); |             throw new CloudRuntimeException(errMsg); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         try { |         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.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); | ||||||
| 
 | 
 | ||||||
|                 SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); |             List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); | ||||||
| 
 | 
 | ||||||
|                 long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); |             for (SolidFireUtil.SolidFireVag sfVag : sfVags) { | ||||||
| 
 |                 if (SolidFireUtil.sfVagContains(sfVag, sfVolumeId, clusterId, hostDao)) { | ||||||
|                 SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); |                     SolidFireUtil.removeVolumeIdsFromSolidFireVag(sfConnection, sfVag.getId(), new Long[] { sfVolumeId }); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         finally { |         finally { | ||||||
| @ -735,11 +697,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
|     private boolean getBooleanValueFromVolumeDetails(long volumeId, String name) { |     private boolean getBooleanValueFromVolumeDetails(long volumeId, String name) { | ||||||
|         VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volumeId, name); |         VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volumeId, name); | ||||||
| 
 | 
 | ||||||
|         if (volumeDetail != null && volumeDetail.getValue() != null) { |         return volumeDetail != null && volumeDetail.getValue() != null && Boolean.parseBoolean(volumeDetail.getValue()); | ||||||
|             return Boolean.parseBoolean(volumeDetail.getValue()); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return false; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private long getCsIdForCloning(long volumeId, String cloneOf) { |     private long getCsIdForCloning(long volumeId, String cloneOf) { | ||||||
| @ -755,11 +713,7 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { | |||||||
|     private boolean shouldTakeSnapshot(long snapshotId) { |     private boolean shouldTakeSnapshot(long snapshotId) { | ||||||
|         SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, "takeSnapshot"); |         SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, "takeSnapshot"); | ||||||
| 
 | 
 | ||||||
|         if (snapshotDetails != null && snapshotDetails.getValue() != null) { |         return snapshotDetails != null && snapshotDetails.getValue() != null && Boolean.parseBoolean(snapshotDetails.getValue()); | ||||||
|             return Boolean.parseBoolean(snapshotDetails.getValue()); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return false; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private SolidFireUtil.SolidFireVolume createClone(SolidFireUtil.SolidFireConnection sfConnection, long dataObjectId, VolumeInfo volumeInfo, long sfAccountId, |     private SolidFireUtil.SolidFireVolume createClone(SolidFireUtil.SolidFireConnection sfConnection, long dataObjectId, VolumeInfo volumeInfo, long sfAccountId, | ||||||
|  | |||||||
| @ -49,8 +49,6 @@ import com.cloud.agent.api.CreateStoragePoolCommand; | |||||||
| import com.cloud.agent.api.DeleteStoragePoolCommand; | import com.cloud.agent.api.DeleteStoragePoolCommand; | ||||||
| import com.cloud.agent.api.ModifyTargetsCommand; | import com.cloud.agent.api.ModifyTargetsCommand; | ||||||
| import com.cloud.agent.api.StoragePoolInfo; | 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.ClusterVO; | ||||||
| import com.cloud.dc.dao.ClusterDao; | import com.cloud.dc.dao.ClusterDao; | ||||||
| import com.cloud.dc.dao.DataCenterDao; | import com.cloud.dc.dao.DataCenterDao; | ||||||
| @ -75,23 +73,22 @@ import com.cloud.utils.db.GlobalLock; | |||||||
| import com.cloud.utils.exception.CloudRuntimeException; | import com.cloud.utils.exception.CloudRuntimeException; | ||||||
| 
 | 
 | ||||||
| public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { | public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { | ||||||
|     private static final Logger s_logger = Logger.getLogger(SolidFireSharedPrimaryDataStoreLifeCycle.class); |     private static final Logger LOGGER = Logger.getLogger(SolidFireSharedPrimaryDataStoreLifeCycle.class); | ||||||
| 
 | 
 | ||||||
|     @Inject private AccountDao _accountDao; |     @Inject private AccountDao accountDao; | ||||||
|     @Inject private AccountDetailsDao _accountDetailsDao; |     @Inject private AccountDetailsDao accountDetailsDao; | ||||||
|     @Inject private AgentManager _agentMgr; |     @Inject private AgentManager agentMgr; | ||||||
|     @Inject private ClusterDao _clusterDao; |     @Inject private ClusterDao clusterDao; | ||||||
|     @Inject private ClusterDetailsDao _clusterDetailsDao; |     @Inject private DataCenterDao zoneDao; | ||||||
|     @Inject private DataCenterDao _zoneDao; |     @Inject private HostDao hostDao; | ||||||
|     @Inject private HostDao _hostDao; |     @Inject private PrimaryDataStoreDao primaryDataStoreDao; | ||||||
|     @Inject private PrimaryDataStoreDao _primaryDataStoreDao; |     @Inject private PrimaryDataStoreHelper primaryDataStoreHelper; | ||||||
|     @Inject private PrimaryDataStoreHelper _primaryDataStoreHelper; |     @Inject private ResourceManager resourceMgr; | ||||||
|     @Inject private ResourceManager _resourceMgr; |     @Inject private StorageManager storageMgr; | ||||||
|     @Inject private StorageManager _storageMgr; |     @Inject private StoragePoolAutomation storagePoolAutomation; | ||||||
|     @Inject private StoragePoolAutomation _storagePoolAutomation; |     @Inject private StoragePoolDetailsDao storagePoolDetailsDao; | ||||||
|     @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; |     @Inject private StoragePoolHostDao storagePoolHostDao; | ||||||
|     @Inject private StoragePoolHostDao _storagePoolHostDao; |     @Inject private TemplateManager tmpltMgr; | ||||||
|     @Inject private TemplateManager _tmpltMgr; |  | ||||||
| 
 | 
 | ||||||
|     // invoked to add primary storage that is based on the SolidFire plug-in |     // invoked to add primary storage that is based on the SolidFire plug-in | ||||||
|     @Override |     @Override | ||||||
| @ -184,7 +181,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|                 lMinIops = Long.parseLong(minIops); |                 lMinIops = Long.parseLong(minIops); | ||||||
|             } |             } | ||||||
|         } catch (Exception ex) { |         } catch (Exception ex) { | ||||||
|             s_logger.info("[ignored] error getting Min IOPS: " + ex.getLocalizedMessage()); |             LOGGER.info("[ignored] error getting Min IOPS: " + ex.getLocalizedMessage()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| @ -194,7 +191,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|                 lMaxIops = Long.parseLong(maxIops); |                 lMaxIops = Long.parseLong(maxIops); | ||||||
|             } |             } | ||||||
|         } catch (Exception ex) { |         } catch (Exception ex) { | ||||||
|             s_logger.info("[ignored] error getting Max IOPS: " + ex.getLocalizedMessage()); |             LOGGER.info("[ignored] error getting Max IOPS: " + ex.getLocalizedMessage()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| @ -204,7 +201,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|                 lBurstIops = Long.parseLong(burstIops); |                 lBurstIops = Long.parseLong(burstIops); | ||||||
|             } |             } | ||||||
|         } catch (Exception ex) { |         } 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) { |         if (lMinIops > lMaxIops) { | ||||||
| @ -266,14 +263,14 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|             parameters.setPath(iqn); |             parameters.setPath(iqn); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ClusterVO cluster = _clusterDao.findById(clusterId); |         ClusterVO cluster = clusterDao.findById(clusterId); | ||||||
| 
 | 
 | ||||||
|         GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); |         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(); |             String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); | ||||||
| 
 | 
 | ||||||
|             s_logger.debug(errMsg); |             LOGGER.debug(errMsg); | ||||||
| 
 | 
 | ||||||
|             throw new CloudRuntimeException(errMsg); |             throw new CloudRuntimeException(errMsg); | ||||||
|         } |         } | ||||||
| @ -282,21 +279,21 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             // this adds a row in the cloud.storage_pool table for this SolidFire volume |             // 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 |             // 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 |             // 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(); |             SolidFireUtil.SolidFireAccount sfAccount = sfCreateVolume.getAccount(); | ||||||
|             Account csAccount = CallContext.current().getCallingAccount(); |             Account csAccount = CallContext.current().getCallingAccount(); | ||||||
| 
 | 
 | ||||||
|             SolidFireUtil.updateCsDbWithSolidFireAccountInfo(csAccount.getId(), sfAccount, dataStore.getId(), _accountDetailsDao); |             SolidFireUtil.updateCsDbWithSolidFireAccountInfo(csAccount.getId(), sfAccount, dataStore.getId(), accountDetailsDao); | ||||||
|         } catch (Exception ex) { |         } catch (Exception ex) { | ||||||
|             if (dataStore != null) { |             if (dataStore != null) { | ||||||
|                 _primaryDataStoreDao.expunge(dataStore.getId()); |                 primaryDataStoreDao.expunge(dataStore.getId()); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             throw new CloudRuntimeException(ex.getMessage()); |             throw new CloudRuntimeException(ex.getMessage()); | ||||||
| @ -310,7 +307,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private HypervisorType getHypervisorTypeForCluster(long clusterId) { |     private HypervisorType getHypervisorTypeForCluster(long clusterId) { | ||||||
|         ClusterVO cluster = _clusterDao.findById(clusterId); |         ClusterVO cluster = clusterDao.findById(clusterId); | ||||||
| 
 | 
 | ||||||
|         if (cluster == null) { |         if (cluster == null) { | ||||||
|             throw new CloudRuntimeException("Cluster ID '" + clusterId + "' was not found in the database."); |             throw new CloudRuntimeException("Cluster ID '" + clusterId + "' was not found in the database."); | ||||||
| @ -354,7 +351,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|         try { |         try { | ||||||
|             Account csAccount = CallContext.current().getCallingAccount(); |             Account csAccount = CallContext.current().getCallingAccount(); | ||||||
|             long csAccountId = csAccount.getId(); |             long csAccountId = csAccount.getId(); | ||||||
|             AccountVO accountVo = _accountDao.findById(csAccountId); |             AccountVO accountVo = accountDao.findById(csAccountId); | ||||||
| 
 | 
 | ||||||
|             String sfAccountName = SolidFireUtil.getSolidFireAccountName(accountVo.getUuid(), csAccountId); |             String sfAccountName = SolidFireUtil.getSolidFireAccountName(accountVo.getUuid(), csAccountId); | ||||||
| 
 | 
 | ||||||
| @ -386,11 +383,11 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|         PrimaryDataStoreInfo primaryDataStoreInfo = (PrimaryDataStoreInfo)store; |         PrimaryDataStoreInfo primaryDataStoreInfo = (PrimaryDataStoreInfo)store; | ||||||
| 
 | 
 | ||||||
|         // check if there is at least one host up in this cluster |         // 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()); |                 primaryDataStoreInfo.getPodId(), primaryDataStoreInfo.getDataCenterId()); | ||||||
| 
 | 
 | ||||||
|         if (allHosts.isEmpty()) { |         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()); |             throw new CloudRuntimeException("No host up to associate a storage pool with in cluster " + primaryDataStoreInfo.getClusterId()); | ||||||
|         } |         } | ||||||
| @ -413,23 +410,23 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
| 
 | 
 | ||||||
|         for (HostVO host : allHosts) { |         for (HostVO host : allHosts) { | ||||||
|             try { |             try { | ||||||
|                 _storageMgr.connectHostToSharedPool(host.getId(), primaryDataStoreInfo.getId()); |                 storageMgr.connectHostToSharedPool(host.getId(), primaryDataStoreInfo.getId()); | ||||||
| 
 | 
 | ||||||
|                 poolHosts.add(host); |                 poolHosts.add(host); | ||||||
|             } catch (Exception e) { |             } 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()) { |         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"); |             throw new CloudRuntimeException("Failed to access storage pool"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         _primaryDataStoreHelper.attachCluster(store); |         primaryDataStoreHelper.attachCluster(store); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @ -444,31 +441,31 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
| 
 | 
 | ||||||
|             Map<String, String> details = new HashMap<>(); |             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()); |             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()); |             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()); |             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()); |             details.put(CreateStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue()); | ||||||
| 
 | 
 | ||||||
|             cmd.setDetails(details); |             cmd.setDetails(details); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Answer answer = _agentMgr.easySend(hostId, cmd); |         Answer answer = agentMgr.easySend(hostId, cmd); | ||||||
| 
 | 
 | ||||||
|         if (answer != null && answer.getResult()) { |         if (answer != null && answer.getResult()) { | ||||||
|             return true; |             return true; | ||||||
|         } else { |         } else { | ||||||
|             _primaryDataStoreDao.expunge(storagePool.getId()); |             primaryDataStoreDao.expunge(storagePool.getId()); | ||||||
| 
 | 
 | ||||||
|             final String msg; |             final String msg; | ||||||
| 
 | 
 | ||||||
| @ -478,7 +475,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|                 msg = "Cannot create storage pool through host '" + hostId + "' due to CreateStoragePoolCommand returns null"; |                 msg = "Cannot create storage pool through host '" + hostId + "' due to CreateStoragePoolCommand returns null"; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             s_logger.warn(msg); |             LOGGER.warn(msg); | ||||||
| 
 | 
 | ||||||
|             throw new CloudRuntimeException(msg); |             throw new CloudRuntimeException(msg); | ||||||
|         } |         } | ||||||
| @ -491,16 +488,16 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean maintain(DataStore dataStore) { |     public boolean maintain(DataStore dataStore) { | ||||||
|         _storagePoolAutomation.maintain(dataStore); |         storagePoolAutomation.maintain(dataStore); | ||||||
|         _primaryDataStoreHelper.maintain(dataStore); |         primaryDataStoreHelper.maintain(dataStore); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean cancelMaintain(DataStore store) { |     public boolean cancelMaintain(DataStore store) { | ||||||
|         _primaryDataStoreHelper.cancelMaintain(store); |         primaryDataStoreHelper.cancelMaintain(store); | ||||||
|         _storagePoolAutomation.cancelMaintain(store); |         storagePoolAutomation.cancelMaintain(store); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @ -508,7 +505,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|     // invoked to delete primary storage that is based on the SolidFire plug-in |     // invoked to delete primary storage that is based on the SolidFire plug-in | ||||||
|     @Override |     @Override | ||||||
|     public boolean deleteDataStore(DataStore dataStore) { |     public boolean deleteDataStore(DataStore dataStore) { | ||||||
|         List<StoragePoolHostVO> hostPoolRecords = _storagePoolHostDao.listByPoolId(dataStore.getId()); |         List<StoragePoolHostVO> hostPoolRecords = storagePoolHostDao.listByPoolId(dataStore.getId()); | ||||||
| 
 | 
 | ||||||
|         HypervisorType hypervisorType = null; |         HypervisorType hypervisorType = null; | ||||||
| 
 | 
 | ||||||
| @ -521,11 +518,11 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         StoragePool storagePool = (StoragePool)dataStore; |         StoragePool storagePool = (StoragePool)dataStore; | ||||||
|         StoragePoolVO storagePoolVO = _primaryDataStoreDao.findById(storagePool.getId()); |         StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId()); | ||||||
|         List<VMTemplateStoragePoolVO> unusedTemplatesInPool = _tmpltMgr.getUnusedTemplatesInPool(storagePoolVO); |         List<VMTemplateStoragePoolVO> unusedTemplatesInPool = tmpltMgr.getUnusedTemplatesInPool(storagePoolVO); | ||||||
| 
 | 
 | ||||||
|         for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) { |         for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) { | ||||||
|             _tmpltMgr.evictTemplateFromStoragePool(templatePoolVO); |             tmpltMgr.evictTemplateFromStoragePool(templatePoolVO); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Long clusterId = null; |         Long clusterId = null; | ||||||
| @ -539,31 +536,31 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
| 
 | 
 | ||||||
|                 Map<String, String> details = new HashMap<>(); |                 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()); |                 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()); |                 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()); |                 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()); |                 details.put(DeleteStoragePoolCommand.STORAGE_PORT, storagePoolDetail.getValue()); | ||||||
| 
 | 
 | ||||||
|                 deleteCmd.setDetails(details); |                 deleteCmd.setDetails(details); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             final Answer answer = _agentMgr.easySend(host.getHostId(), deleteCmd); |             final Answer answer = agentMgr.easySend(host.getHostId(), deleteCmd); | ||||||
| 
 | 
 | ||||||
|             if (answer != null && answer.getResult()) { |             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) { |                 if (hostVO != null) { | ||||||
|                     clusterId = hostVO.getClusterId(); |                     clusterId = hostVO.getClusterId(); | ||||||
| @ -574,29 +571,39 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
|                 if (answer != null) { |                 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 { |                 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) { |         if (clusterId != null) { | ||||||
|             ClusterVO cluster = _clusterDao.findById(clusterId); |             ClusterVO cluster = clusterDao.findById(clusterId); | ||||||
| 
 | 
 | ||||||
|             GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); |             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(); |                 String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); | ||||||
| 
 | 
 | ||||||
|                 s_logger.debug(errMsg); |                 LOGGER.debug(errMsg); | ||||||
| 
 | 
 | ||||||
|                 throw new CloudRuntimeException(errMsg); |                 throw new CloudRuntimeException(errMsg); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             try { |             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 { |             finally { | ||||||
|                 lock.unlock(); |                 lock.unlock(); | ||||||
| @ -610,16 +617,16 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
| 
 | 
 | ||||||
|         deleteSolidFireVolume(storagePool.getId()); |         deleteSolidFireVolume(storagePool.getId()); | ||||||
| 
 | 
 | ||||||
|         return _primaryDataStoreHelper.deletePrimaryDataStore(dataStore); |         return primaryDataStoreHelper.deletePrimaryDataStore(dataStore); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void handleTargetsForVMware(long hostId, long storagePoolId) { |     private void handleTargetsForVMware(long hostId, long storagePoolId) { | ||||||
|         HostVO host = _hostDao.findById(hostId); |         HostVO host = hostDao.findById(hostId); | ||||||
| 
 | 
 | ||||||
|         if (host.getHypervisorType() == HypervisorType.VMware) { |         if (host.getHypervisorType() == HypervisorType.VMware) { | ||||||
|             String storageAddress = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP).getValue(); |             String storageAddress = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP).getValue(); | ||||||
|             int storagePort = Integer.parseInt(_storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT).getValue()); |             int storagePort = Integer.parseInt(storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT).getValue()); | ||||||
|             String iqn = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN).getValue(); |             String iqn = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN).getValue(); | ||||||
| 
 | 
 | ||||||
|             ModifyTargetsCommand cmd = new ModifyTargetsCommand(); |             ModifyTargetsCommand cmd = new ModifyTargetsCommand(); | ||||||
| 
 | 
 | ||||||
| @ -644,39 +651,22 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { |     private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { | ||||||
|         Answer answer = _agentMgr.easySend(hostId, cmd); |         Answer answer = agentMgr.easySend(hostId, cmd); | ||||||
| 
 | 
 | ||||||
|         if (answer == null) { |         if (answer == null) { | ||||||
|             String msg = "Unable to get an answer to the modify targets command"; |             String msg = "Unable to get an answer to the modify targets command"; | ||||||
| 
 | 
 | ||||||
|             s_logger.warn(msg); |             LOGGER.warn(msg); | ||||||
|         } |         } | ||||||
|         else if (!answer.getResult()) { |         else if (!answer.getResult()) { | ||||||
|             String msg = "Unable to modify target on the following host: " + hostId; |             String msg = "Unable to modify target on the following host: " + hostId; | ||||||
| 
 | 
 | ||||||
|             s_logger.warn(msg); |             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); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void deleteSolidFireVolume(long storagePoolId) { |     private void deleteSolidFireVolume(long storagePoolId) { | ||||||
|         SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); |         SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); | ||||||
| 
 | 
 | ||||||
|         long sfVolumeId = getVolumeId(storagePoolId); |         long sfVolumeId = getVolumeId(storagePoolId); | ||||||
| 
 | 
 | ||||||
| @ -684,7 +674,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private long getVolumeId(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(); |         String volumeId = storagePoolDetail.getValue(); | ||||||
| 
 | 
 | ||||||
| @ -692,7 +682,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private long getIopsValue(long storagePoolId, String iopsKey) { |     private long getIopsValue(long storagePoolId, String iopsKey) { | ||||||
|         StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, iopsKey); |         StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, iopsKey); | ||||||
| 
 | 
 | ||||||
|         String iops = storagePoolDetail.getValue(); |         String iops = storagePoolDetail.getValue(); | ||||||
| 
 | 
 | ||||||
| @ -704,7 +694,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private HypervisorType getHypervisorType(long hostId) { |     private HypervisorType getHypervisorType(long hostId) { | ||||||
|         HostVO host = _hostDao.findById(hostId); |         HostVO host = hostDao.findById(hostId); | ||||||
| 
 | 
 | ||||||
|         if (host != null) { |         if (host != null) { | ||||||
|             return host.getHypervisorType(); |             return host.getHypervisorType(); | ||||||
| @ -729,7 +719,7 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
|         Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null; |         Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null; | ||||||
|         Long capacityIops = strCapacityIops != null ? Long.parseLong(strCapacityIops) : 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(); |         long size = capacityBytes != null ? capacityBytes : storagePool.getCapacityBytes(); | ||||||
| 
 | 
 | ||||||
| @ -764,16 +754,16 @@ public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStor | |||||||
| 
 | 
 | ||||||
|         SolidFireUtil.modifyVolume(sfConnection, getVolumeId(storagePool.getId()), size, null, minIops, maxIops, burstIops); |         SolidFireUtil.modifyVolume(sfConnection, getVolumeId(storagePool.getId()), size, null, minIops, maxIops, burstIops); | ||||||
| 
 | 
 | ||||||
|         SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), _primaryDataStoreDao, _storagePoolDetailsDao, minIops, maxIops, burstIops); |         SolidFireUtil.updateCsDbWithSolidFireIopsInfo(storagePool.getId(), primaryDataStoreDao, storagePoolDetailsDao, minIops, maxIops, burstIops); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void enableStoragePool(DataStore dataStore) { |     public void enableStoragePool(DataStore dataStore) { | ||||||
|         _primaryDataStoreHelper.enable(dataStore); |         primaryDataStoreHelper.enable(dataStore); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void disableStoragePool(DataStore dataStore) { |     public void disableStoragePool(DataStore dataStore) { | ||||||
|         _primaryDataStoreHelper.disable(dataStore); |         primaryDataStoreHelper.disable(dataStore); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -40,7 +40,6 @@ import com.cloud.agent.api.ModifyStoragePoolAnswer; | |||||||
| import com.cloud.agent.api.ModifyStoragePoolCommand; | import com.cloud.agent.api.ModifyStoragePoolCommand; | ||||||
| import com.cloud.agent.api.ModifyTargetsCommand; | import com.cloud.agent.api.ModifyTargetsCommand; | ||||||
| import com.cloud.alert.AlertManager; | import com.cloud.alert.AlertManager; | ||||||
| import com.cloud.dc.ClusterDetailsDao; |  | ||||||
| import com.cloud.dc.dao.ClusterDao; | import com.cloud.dc.dao.ClusterDao; | ||||||
| import com.cloud.host.HostVO; | import com.cloud.host.HostVO; | ||||||
| import com.cloud.host.dao.HostDao; | import com.cloud.host.dao.HostDao; | ||||||
| @ -56,31 +55,31 @@ import com.cloud.vm.VMInstanceVO; | |||||||
| import com.cloud.vm.dao.VMInstanceDao; | import com.cloud.vm.dao.VMInstanceDao; | ||||||
| 
 | 
 | ||||||
| public class SolidFireHostListener implements HypervisorHostListener { | public class SolidFireHostListener implements HypervisorHostListener { | ||||||
|     private static final Logger s_logger = Logger.getLogger(SolidFireHostListener.class); |     private static final Logger LOGGER = Logger.getLogger(SolidFireHostListener.class); | ||||||
| 
 | 
 | ||||||
|     @Inject private AgentManager _agentMgr; |     @Inject private AgentManager agentMgr; | ||||||
|     @Inject private AlertManager _alertMgr; |     @Inject private AlertManager alertMgr; | ||||||
|     @Inject private ClusterDao _clusterDao; |     @Inject private ClusterDao clusterDao; | ||||||
|     @Inject private ClusterDetailsDao _clusterDetailsDao; |     @Inject private DataStoreManager dataStoreMgr; | ||||||
|     @Inject private DataStoreManager _dataStoreMgr; |     @Inject private HostDao hostDao; | ||||||
|     @Inject private HostDao _hostDao; |     @Inject private PrimaryDataStoreDao storagePoolDao; | ||||||
|     @Inject private PrimaryDataStoreDao _storagePoolDao; |     @Inject private StoragePoolDetailsDao storagePoolDetailsDao; | ||||||
|     @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; |  | ||||||
|     @Inject private StoragePoolHostDao storagePoolHostDao; |     @Inject private StoragePoolHostDao storagePoolHostDao; | ||||||
|     @Inject private VMInstanceDao _vmDao; |     @Inject private VMInstanceDao vmDao; | ||||||
|     @Inject private VolumeDao _volumeDao; |     @Inject private VolumeDao volumeDao; | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean hostAdded(long hostId) { |     public boolean hostAdded(long hostId) { | ||||||
|         HostVO host = _hostDao.findById(hostId); |         HostVO host = hostDao.findById(hostId); | ||||||
| 
 | 
 | ||||||
|         if (host == null) { |         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; |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.PROVIDER_NAME, |         SolidFireUtil.hostAddedToCluster(hostId, host.getClusterId(), SolidFireUtil.PROVIDER_NAME, | ||||||
|                 _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); |                 clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); | ||||||
| 
 | 
 | ||||||
|         handleVMware(host, true, ModifyTargetsCommand.TargetTypeToRemove.NEITHER); |         handleVMware(host, true, ModifyTargetsCommand.TargetTypeToRemove.NEITHER); | ||||||
| 
 | 
 | ||||||
| @ -89,7 +88,7 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean hostConnect(long hostId, long storagePoolId) { |     public boolean hostConnect(long hostId, long storagePoolId) { | ||||||
|         HostVO host = _hostDao.findById(hostId); |         HostVO host = hostDao.findById(hostId); | ||||||
| 
 | 
 | ||||||
|         StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); |         StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); | ||||||
| 
 | 
 | ||||||
| @ -122,25 +121,25 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean hostAboutToBeRemoved(long hostId) { |     public boolean hostAboutToBeRemoved(long hostId) { | ||||||
|         return true; |         HostVO host = hostDao.findById(hostId); | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     @Override |         SolidFireUtil.hostRemovedFromCluster(hostId, host.getClusterId(), SolidFireUtil.PROVIDER_NAME, | ||||||
|     public boolean hostRemoved(long hostId, long clusterId) { |                 clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); | ||||||
|         SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.PROVIDER_NAME, |  | ||||||
|                 _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); |  | ||||||
| 
 |  | ||||||
|         HostVO host = _hostDao.findById(hostId); |  | ||||||
| 
 | 
 | ||||||
|         handleVMware(host, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); |         handleVMware(host, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean hostRemoved(long hostId, long clusterId) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private void handleXenServer(long clusterId, long hostId, long storagePoolId) { |     private void handleXenServer(long clusterId, long hostId, long storagePoolId) { | ||||||
|         List<String> storagePaths = getStoragePaths(clusterId, 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) { |         for (String storagePath : storagePaths) { | ||||||
|             ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); |             ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); | ||||||
| @ -153,7 +152,7 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
| 
 | 
 | ||||||
|     private void handleVMware(HostVO host, boolean add, ModifyTargetsCommand.TargetTypeToRemove targetTypeToRemove) { |     private void handleVMware(HostVO host, boolean add, ModifyTargetsCommand.TargetTypeToRemove targetTypeToRemove) { | ||||||
|         if (host != null && HypervisorType.VMware.equals(host.getHypervisorType())) { |         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) { |             if (storagePools != null && storagePools.size() > 0) { | ||||||
|                 List<Map<String, String>> targets = new ArrayList<>(); |                 List<Map<String, String>> targets = new ArrayList<>(); | ||||||
| @ -169,6 +168,7 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
|                 cmd.setTargets(targets); |                 cmd.setTargets(targets); | ||||||
|                 cmd.setAdd(add); |                 cmd.setAdd(add); | ||||||
|                 cmd.setTargetTypeToRemove(targetTypeToRemove); |                 cmd.setTargetTypeToRemove(targetTypeToRemove); | ||||||
|  |                 cmd.setRemoveAsync(true); | ||||||
| 
 | 
 | ||||||
|                 sendModifyTargetsCommand(cmd, host.getId()); |                 sendModifyTargetsCommand(cmd, host.getId()); | ||||||
|             } |             } | ||||||
| @ -176,7 +176,7 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void handleKVM(long hostId, long storagePoolId) { |     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); |         ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); | ||||||
| 
 | 
 | ||||||
| @ -187,19 +187,19 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
|         List<String> storagePaths = new ArrayList<>(); |         List<String> storagePaths = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|         // If you do not pass in null for the second parameter, you only get back applicable ROOT disks. |         // 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) { |         if (volumes != null) { | ||||||
|             for (VolumeVO volume : volumes) { |             for (VolumeVO volume : volumes) { | ||||||
|                 Long instanceId = volume.getInstanceId(); |                 Long instanceId = volume.getInstanceId(); | ||||||
| 
 | 
 | ||||||
|                 if (instanceId != null) { |                 if (instanceId != null) { | ||||||
|                     VMInstanceVO vmInstance = _vmDao.findById(instanceId); |                     VMInstanceVO vmInstance = vmDao.findById(instanceId); | ||||||
| 
 | 
 | ||||||
|                     Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); |                     Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); | ||||||
| 
 | 
 | ||||||
|                     if (hostIdForVm != null) { |                     if (hostIdForVm != null) { | ||||||
|                         HostVO hostForVm = _hostDao.findById(hostIdForVm); |                         HostVO hostForVm = hostDao.findById(hostIdForVm); | ||||||
| 
 | 
 | ||||||
|                         if (hostForVm != null && hostForVm.getClusterId().equals(clusterId)) { |                         if (hostForVm != null && hostForVm.getClusterId().equals(clusterId)) { | ||||||
|                             storagePaths.add(volume.get_iScsiName()); |                             storagePaths.add(volume.get_iScsiName()); | ||||||
| @ -215,22 +215,22 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
|     private List<Map<String, String>> getTargets(long clusterId, long storagePoolId) { |     private List<Map<String, String>> getTargets(long clusterId, long storagePoolId) { | ||||||
|         List<Map<String, String>> targets = new ArrayList<>(); |         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. |         // 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) { |         if (volumes != null) { | ||||||
|             for (VolumeVO volume : volumes) { |             for (VolumeVO volume : volumes) { | ||||||
|                 Long instanceId = volume.getInstanceId(); |                 Long instanceId = volume.getInstanceId(); | ||||||
| 
 | 
 | ||||||
|                 if (instanceId != null) { |                 if (instanceId != null) { | ||||||
|                     VMInstanceVO vmInstance = _vmDao.findById(instanceId); |                     VMInstanceVO vmInstance = vmDao.findById(instanceId); | ||||||
| 
 | 
 | ||||||
|                     Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); |                     Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); | ||||||
| 
 | 
 | ||||||
|                     if (hostIdForVm != null) { |                     if (hostIdForVm != null) { | ||||||
|                         HostVO hostForVm = _hostDao.findById(hostIdForVm); |                         HostVO hostForVm = hostDao.findById(hostIdForVm); | ||||||
| 
 | 
 | ||||||
|                         if (hostForVm.getClusterId().equals(clusterId)) { |                         if (hostForVm.getClusterId().equals(clusterId)) { | ||||||
|                             Map<String, String> details = new HashMap<>(); |                             Map<String, String> details = new HashMap<>(); | ||||||
| @ -250,7 +250,7 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { |     private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { | ||||||
|         Answer answer = _agentMgr.easySend(hostId, cmd); |         Answer answer = agentMgr.easySend(hostId, cmd); | ||||||
| 
 | 
 | ||||||
|         if (answer == null) { |         if (answer == null) { | ||||||
|             throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); |             throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); | ||||||
| @ -259,16 +259,16 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
|         if (!answer.getResult()) { |         if (!answer.getResult()) { | ||||||
|             String msg = "Unable to modify targets on the following host: " + hostId; |             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); |             throw new CloudRuntimeException(msg); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { |     private void sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { | ||||||
|         Answer answer = _agentMgr.easySend(hostId, cmd); |         Answer answer = agentMgr.easySend(hostId, cmd); | ||||||
| 
 | 
 | ||||||
|         if (answer == null) { |         if (answer == null) { | ||||||
|             throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command (" + storagePool.getId() + ")"); |             throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command (" + storagePool.getId() + ")"); | ||||||
| @ -277,7 +277,7 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
|         if (!answer.getResult()) { |         if (!answer.getResult()) { | ||||||
|             String msg = "Unable to attach storage pool " + storagePool.getId() + " to host " + hostId; |             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() + |             throw new CloudRuntimeException("Unable to establish a connection from agent to storage pool " + storagePool.getId() + " due to " + answer.getDetails() + | ||||||
|                 " (" + storagePool.getId() + ")"); |                 " (" + storagePool.getId() + ")"); | ||||||
| @ -285,6 +285,6 @@ public class SolidFireHostListener implements HypervisorHostListener { | |||||||
| 
 | 
 | ||||||
|         assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer expected ; Pool = " + storagePool.getId() + " Host = " + hostId; |         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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -40,7 +40,6 @@ import com.cloud.agent.api.ModifyStoragePoolAnswer; | |||||||
| import com.cloud.agent.api.ModifyStoragePoolCommand; | import com.cloud.agent.api.ModifyStoragePoolCommand; | ||||||
| import com.cloud.agent.api.ModifyTargetsCommand; | import com.cloud.agent.api.ModifyTargetsCommand; | ||||||
| import com.cloud.alert.AlertManager; | import com.cloud.alert.AlertManager; | ||||||
| import com.cloud.dc.ClusterDetailsDao; |  | ||||||
| import com.cloud.dc.dao.ClusterDao; | import com.cloud.dc.dao.ClusterDao; | ||||||
| import com.cloud.host.HostVO; | import com.cloud.host.HostVO; | ||||||
| import com.cloud.host.dao.HostDao; | import com.cloud.host.dao.HostDao; | ||||||
| @ -57,7 +56,6 @@ public class SolidFireSharedHostListener implements HypervisorHostListener { | |||||||
|     @Inject private AgentManager agentMgr; |     @Inject private AgentManager agentMgr; | ||||||
|     @Inject private AlertManager alertMgr; |     @Inject private AlertManager alertMgr; | ||||||
|     @Inject private ClusterDao clusterDao; |     @Inject private ClusterDao clusterDao; | ||||||
|     @Inject private ClusterDetailsDao clusterDetailsDao; |  | ||||||
|     @Inject private DataStoreManager dataStoreMgr; |     @Inject private DataStoreManager dataStoreMgr; | ||||||
|     @Inject private HostDao hostDao; |     @Inject private HostDao hostDao; | ||||||
|     @Inject private PrimaryDataStoreDao storagePoolDao; |     @Inject private PrimaryDataStoreDao storagePoolDao; | ||||||
| @ -69,14 +67,15 @@ public class SolidFireSharedHostListener implements HypervisorHostListener { | |||||||
|         HostVO host = hostDao.findById(hostId); |         HostVO host = hostDao.findById(hostId); | ||||||
| 
 | 
 | ||||||
|         if (host == null) { |         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; |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.SHARED_PROVIDER_NAME, |         SolidFireUtil.hostAddedToCluster(hostId, host.getClusterId(), SolidFireUtil.SHARED_PROVIDER_NAME, | ||||||
|                 clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); |                 clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); | ||||||
| 
 | 
 | ||||||
|         handleVMware(hostId, true, ModifyTargetsCommand.TargetTypeToRemove.NEITHER); |         handleVMware(host, true, ModifyTargetsCommand.TargetTypeToRemove.NEITHER); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @ -123,10 +122,10 @@ public class SolidFireSharedHostListener implements HypervisorHostListener { | |||||||
|     public boolean hostAboutToBeRemoved(long hostId) { |     public boolean hostAboutToBeRemoved(long hostId) { | ||||||
|         HostVO host = hostDao.findById(hostId); |         HostVO host = hostDao.findById(hostId); | ||||||
| 
 | 
 | ||||||
|         SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), false, SolidFireUtil.SHARED_PROVIDER_NAME, |         SolidFireUtil.hostRemovedFromCluster(hostId, host.getClusterId(), SolidFireUtil.SHARED_PROVIDER_NAME, | ||||||
|                 clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); |                 clusterDao, hostDao, storagePoolDao, storagePoolDetailsDao); | ||||||
| 
 | 
 | ||||||
|         handleVMware(hostId, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); |         handleVMware(host, false, ModifyTargetsCommand.TargetTypeToRemove.BOTH); | ||||||
| 
 | 
 | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @ -136,9 +135,7 @@ public class SolidFireSharedHostListener implements HypervisorHostListener { | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void handleVMware(long hostId, boolean add, ModifyTargetsCommand.TargetTypeToRemove targetTypeToRemove) { |     private void handleVMware(HostVO host, boolean add, ModifyTargetsCommand.TargetTypeToRemove targetTypeToRemove) { | ||||||
|         HostVO host = hostDao.findById(hostId); |  | ||||||
| 
 |  | ||||||
|         if (HypervisorType.VMware.equals(host.getHypervisorType())) { |         if (HypervisorType.VMware.equals(host.getHypervisorType())) { | ||||||
|             List<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME); |             List<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME); | ||||||
| 
 | 
 | ||||||
| @ -179,7 +176,7 @@ public class SolidFireSharedHostListener implements HypervisorHostListener { | |||||||
|                     cmd.setTargetTypeToRemove(targetTypeToRemove); |                     cmd.setTargetTypeToRemove(targetTypeToRemove); | ||||||
|                     cmd.setRemoveAsync(true); |                     cmd.setRemoveAsync(true); | ||||||
| 
 | 
 | ||||||
|                     sendModifyTargetsCommand(cmd, hostId); |                     sendModifyTargetsCommand(cmd, host.getId()); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -17,13 +17,16 @@ | |||||||
| package org.apache.cloudstack.storage.datastore.util; | package org.apache.cloudstack.storage.datastore.util; | ||||||
| 
 | 
 | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Collections; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  | import java.util.Random; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||||
|  | import java.util.UUID; | ||||||
| 
 | 
 | ||||||
|  | import org.apache.commons.lang3.ArrayUtils; | ||||||
| import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||||
| import org.apache.log4j.Logger; | import org.apache.log4j.Logger; | ||||||
| 
 | 
 | ||||||
| @ -32,8 +35,6 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; | |||||||
| import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; | import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; | ||||||
| import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; | 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.ClusterVO; | ||||||
| import com.cloud.dc.dao.ClusterDao; | import com.cloud.dc.dao.ClusterDao; | ||||||
| import com.cloud.host.Host; | import com.cloud.host.Host; | ||||||
| @ -44,11 +45,14 @@ import com.cloud.user.AccountDetailsDao; | |||||||
| import com.cloud.utils.db.GlobalLock; | import com.cloud.utils.db.GlobalLock; | ||||||
| import com.cloud.utils.exception.CloudRuntimeException; | import com.cloud.utils.exception.CloudRuntimeException; | ||||||
| 
 | 
 | ||||||
|  | import com.google.common.base.Preconditions; | ||||||
| import com.google.common.primitives.Longs; | import com.google.common.primitives.Longs; | ||||||
| 
 | 
 | ||||||
| import com.solidfire.client.ElementFactory; | import com.solidfire.client.ElementFactory; | ||||||
| import com.solidfire.element.api.Account; | import com.solidfire.element.api.Account; | ||||||
| import com.solidfire.element.api.AddAccountRequest; | 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.CloneVolumeRequest; | ||||||
| import com.solidfire.element.api.CloneVolumeResult; | import com.solidfire.element.api.CloneVolumeResult; | ||||||
| import com.solidfire.element.api.CreateSnapshotRequest; | import com.solidfire.element.api.CreateSnapshotRequest; | ||||||
| @ -62,9 +66,10 @@ import com.solidfire.element.api.GetAsyncResultRequest; | |||||||
| import com.solidfire.element.api.ListSnapshotsRequest; | import com.solidfire.element.api.ListSnapshotsRequest; | ||||||
| import com.solidfire.element.api.ListVolumeAccessGroupsRequest; | import com.solidfire.element.api.ListVolumeAccessGroupsRequest; | ||||||
| import com.solidfire.element.api.ListVolumesRequest; | import com.solidfire.element.api.ListVolumesRequest; | ||||||
| import com.solidfire.element.api.ModifyVolumeAccessGroupRequest; |  | ||||||
| import com.solidfire.element.api.ModifyVolumeRequest; | import com.solidfire.element.api.ModifyVolumeRequest; | ||||||
| import com.solidfire.element.api.QoS; | 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.RollbackToSnapshotRequest; | ||||||
| import com.solidfire.element.api.Snapshot; | import com.solidfire.element.api.Snapshot; | ||||||
| import com.solidfire.element.api.SolidFireElement; | import com.solidfire.element.api.SolidFireElement; | ||||||
| @ -75,12 +80,13 @@ import com.solidfire.jsvcgen.javautil.Optional; | |||||||
| import static org.apache.commons.lang.ArrayUtils.toPrimitive; | import static org.apache.commons.lang.ArrayUtils.toPrimitive; | ||||||
| 
 | 
 | ||||||
| public class SolidFireUtil { | 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 PROVIDER_NAME = "SolidFire"; | ||||||
|     public static final String SHARED_PROVIDER_NAME = "SolidFireShared"; |     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: "; |     public static final String LOG_PREFIX = "SolidFire: "; | ||||||
| 
 | 
 | ||||||
| @ -127,6 +133,8 @@ public class SolidFireUtil { | |||||||
|     public static final String DATASTORE_NAME = "datastoreName"; |     public static final String DATASTORE_NAME = "datastoreName"; | ||||||
|     public static final String IQN = "iqn"; |     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_VOLUME_SIZE = 1000000000; | ||||||
| 
 | 
 | ||||||
|     public static final long MIN_IOPS_PER_VOLUME = 100; |     public static final long MIN_IOPS_PER_VOLUME = 100; | ||||||
| @ -136,6 +144,9 @@ public class SolidFireUtil { | |||||||
|     private static final int DEFAULT_MANAGEMENT_PORT = 443; |     private static final int DEFAULT_MANAGEMENT_PORT = 443; | ||||||
|     private static final int DEFAULT_STORAGE_PORT = 3260; |     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 { |     public static class SolidFireConnection { | ||||||
|         private final String _managementVip; |         private final String _managementVip; | ||||||
|         private final int _managementPort; |         private final int _managementPort; | ||||||
| @ -300,7 +311,7 @@ public class SolidFireUtil { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static String getSolidFireAccountName(String csAccountUuid, long csAccountId) { |     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, |     public static void updateCsDbWithSolidFireIopsInfo(long storagePoolId, PrimaryDataStoreDao primaryDataStoreDao, | ||||||
| @ -344,17 +355,72 @@ public class SolidFireUtil { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static void hostAddedToOrRemovedFromCluster(long hostId, long clusterId, boolean added, String storageProvider, |     private static boolean isCloudStackOnlyVag(SolidFireConnection sfConnection, SolidFireVag sfVag) { | ||||||
|             ClusterDao clusterDao, ClusterDetailsDao clusterDetailsDao, PrimaryDataStoreDao storagePoolDao, |         long[] volumeIds = sfVag.getVolumeIds(); | ||||||
|             StoragePoolDetailsDao storagePoolDetailsDao, HostDao hostDao) { | 
 | ||||||
|  |         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); |         ClusterVO cluster = clusterDao.findById(clusterId); | ||||||
| 
 | 
 | ||||||
|         GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); |         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(); |             String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); | ||||||
| 
 | 
 | ||||||
|             s_logger.debug(errMsg); |             LOGGER.warn(errMsg); | ||||||
| 
 | 
 | ||||||
|             throw new CloudRuntimeException(errMsg); |             throw new CloudRuntimeException(errMsg); | ||||||
|         } |         } | ||||||
| @ -366,26 +432,20 @@ public class SolidFireUtil { | |||||||
|                 List<SolidFireUtil.SolidFireConnection> sfConnections = new ArrayList<>(); |                 List<SolidFireUtil.SolidFireConnection> sfConnections = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|                 for (StoragePoolVO storagePool : storagePools) { |                 for (StoragePoolVO storagePool : storagePools) { | ||||||
|                     ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePool.getId())); |                     if (!isStorageApplicableToZoneOrCluster(storagePool, clusterId, clusterDao)) { | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
| 
 | 
 | ||||||
|                     String vagId = clusterDetail != null ? clusterDetail.getValue() : null; |  | ||||||
| 
 |  | ||||||
|                     if (vagId != null) { |  | ||||||
|                     SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); |                     SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); | ||||||
| 
 | 
 | ||||||
|                     if (!sfConnections.contains(sfConnection)) { |                     if (!sfConnections.contains(sfConnection)) { | ||||||
|                         sfConnections.add(sfConnection); |                         sfConnections.add(sfConnection); | ||||||
| 
 | 
 | ||||||
|                             SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getVag(sfConnection, Long.parseLong(vagId)); |                         List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); | ||||||
|  |                         SolidFireVag sfVag = getVolumeAccessGroup(hostVO.getStorageUrl(), sfVags); | ||||||
| 
 | 
 | ||||||
|                             List<HostVO> hostsToAddOrRemove = new ArrayList<>(); |                         if (sfVag != null && isCloudStackOnlyVag(sfConnection, sfVag)) { | ||||||
|                             HostVO hostToAddOrRemove = hostDao.findByIdIncludingRemoved(hostId); |                             removeInitiatorsFromSolidFireVag(sfConnection, sfVag.getId(), new String[] { hostVO.getStorageUrl() }); | ||||||
| 
 |  | ||||||
|                             hostsToAddOrRemove.add(hostToAddOrRemove); |  | ||||||
| 
 |  | ||||||
|                             String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hostsToAddOrRemove), added); |  | ||||||
| 
 |  | ||||||
|                             SolidFireUtil.modifyVag(sfConnection, sfVag.getId(), hostIqns, sfVag.getVolumeIds()); |  | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -397,50 +457,337 @@ public class SolidFireUtil { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId, |     public static void hostAddedToCluster(long hostId, long clusterId, String storageProvider, ClusterDao clusterDao, HostDao hostDao, | ||||||
|                                                       String vagUuid, List<HostVO> hosts, ClusterDetailsDao clusterDetailsDao) { |                                           PrimaryDataStoreDao storagePoolDao, StoragePoolDetailsDao storagePoolDetailsDao) { | ||||||
|         if (hosts == null || hosts.isEmpty()) { |         HostVO hostVO = hostDao.findById(hostId); | ||||||
|             throw new CloudRuntimeException("There must be at least one host in the cluster."); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         long lVagId; |         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(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 { |         try { | ||||||
|             lVagId = SolidFireUtil.createVag(sfConnection, "CloudStack-" + vagUuid, |             List<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(storageProvider); | ||||||
|                 SolidFireUtil.getIqnsFromHosts(hosts), new long[] { sfVolumeId }); |  | ||||||
|         } |  | ||||||
|         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)) { |             if (storagePools != null && storagePools.size() > 0) { | ||||||
|                 throw new CloudRuntimeException(ex.getMessage()); |                 List<SolidFireUtil.SolidFireConnection> sfConnections = new ArrayList<>(); | ||||||
|  | 
 | ||||||
|  |                 for (StoragePoolVO storagePool : storagePools) { | ||||||
|  |                     if (!isStorageApplicableToZoneOrCluster(storagePool, clusterId, clusterDao)) { | ||||||
|  |                         continue; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|             // getCompatibleVag throws an exception if an existing VAG can't be located |                     SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); | ||||||
|             SolidFireUtil.SolidFireVag sfVag = getCompatibleVag(sfConnection, hosts); |  | ||||||
| 
 | 
 | ||||||
|             lVagId = sfVag.getId(); |                     if (!sfConnections.contains(sfConnection)) { | ||||||
|  |                         sfConnections.add(sfConnection); | ||||||
| 
 | 
 | ||||||
|             long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); |                         List<SolidFireUtil.SolidFireVag> sfVags = SolidFireUtil.getAllVags(sfConnection); | ||||||
|  |                         SolidFireVag sfVag = getVolumeAccessGroup(hostVO.getStorageUrl(), sfVags); | ||||||
| 
 | 
 | ||||||
|             SolidFireUtil.modifyVag(sfConnection, lVagId, sfVag.getInitiators(), volumeIds); |                         if (sfVag != null) { | ||||||
|  |                             placeVolumeIdsInVag(sfConnection, sfVags, sfVag, hostVO, hostDao); | ||||||
|  |                         } else { | ||||||
|  |                             handleVagForHost(sfConnection, sfVags, hostVO, hostDao); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         finally { | ||||||
|  |             lock.unlock(); | ||||||
|  |             lock.releaseRef(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|         ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId)); |     // 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()); | ||||||
| 
 | 
 | ||||||
|         clusterDetailsDao.persist(clusterDetail); |         if (hostVOs != null) { | ||||||
|  |             int numVags = 0; | ||||||
| 
 | 
 | ||||||
|         return lVagId; |             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 (>)"); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|     public static boolean hostsSupport_iScsi(List<HostVO> hosts) { |                         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)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 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<>(); | ||||||
|  | 
 | ||||||
|  |         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); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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()); | ||||||
|  | 
 | ||||||
|  |         if (!existingVolumeIds.contains(volumeId) && !newVolumeIds.contains(volumeId)) { | ||||||
|  |             newVolumeIds.add(volumeId); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static SolidFireVag getVagForRandomHostInCluster(List<SolidFireUtil.SolidFireVag> sfVags, Host host, HostDao hostDao) { | ||||||
|  |         List<HostVO> hostVOs = hostDao.findByClusterId(host.getClusterId()); | ||||||
|  | 
 | ||||||
|  |         if (hostVOs != null) { | ||||||
|  |             Collections.shuffle(hostVOs, RANDOM); | ||||||
|  | 
 | ||||||
|  |             for (HostVO hostVO : hostVOs) { | ||||||
|  |                 if (hostVO.getId() != host.getId() && hostSupports_iScsi(hostVO)) { | ||||||
|  |                     SolidFireVag sfVag = getVolumeAccessGroup(hostVO.getStorageUrl(), sfVags); | ||||||
|  | 
 | ||||||
|  |                     if (sfVag != null) { | ||||||
|  |                         return sfVag; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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); | ||||||
|  | 
 | ||||||
|  |             throw new CloudRuntimeException(errMsg); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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 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) { |         if (hosts == null || hosts.size() == 0) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for (Host host : hosts) { |         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; |                 return false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -448,14 +795,6 @@ public class SolidFireUtil { | |||||||
|         return true; |         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) { |     public static String getVagKey(long storagePoolId) { | ||||||
|         return "sfVolumeAccessGroup_" + storagePoolId; |         return "sfVolumeAccessGroup_" + storagePoolId; | ||||||
|     } |     } | ||||||
| @ -851,32 +1190,43 @@ public class SolidFireUtil { | |||||||
|         return getSolidFireElement(sfConnection).createVolumeAccessGroup(request).getVolumeAccessGroupID(); |         return getSolidFireElement(sfConnection).createVolumeAccessGroup(request).getVolumeAccessGroupID(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static void modifyVag(SolidFireConnection sfConnection, long vagId, String[] iqns, long[] volumeIds) { |     private static void addInitiatorsToSolidFireVag(SolidFireConnection sfConnection, long vagId, String[] initiators) { | ||||||
|         ModifyVolumeAccessGroupRequest request = ModifyVolumeAccessGroupRequest.builder() |         AddInitiatorsToVolumeAccessGroupRequest request = AddInitiatorsToVolumeAccessGroupRequest.builder() | ||||||
|                 .volumeAccessGroupID(vagId) |                 .volumeAccessGroupID(vagId) | ||||||
|                 .optionalInitiators(iqns) |                 .initiators(initiators) | ||||||
|                 .optionalVolumes(Longs.asList(volumeIds).toArray(new Long[volumeIds.length])) |  | ||||||
|                 .build(); |                 .build(); | ||||||
| 
 | 
 | ||||||
|         getSolidFireElement(sfConnection).modifyVolumeAccessGroup(request); |         getSolidFireElement(sfConnection).addInitiatorsToVolumeAccessGroup(request); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static SolidFireVag getVag(SolidFireConnection sfConnection, long vagId) |     private static void removeInitiatorsFromSolidFireVag(SolidFireConnection sfConnection, long vagId, String[] initiators) { | ||||||
|     { |         RemoveInitiatorsFromVolumeAccessGroupRequest request = RemoveInitiatorsFromVolumeAccessGroupRequest.builder() | ||||||
|         ListVolumeAccessGroupsRequest request = ListVolumeAccessGroupsRequest.builder() |                 .volumeAccessGroupID(vagId) | ||||||
|                 .optionalStartVolumeAccessGroupID(vagId) |                 .initiators(initiators) | ||||||
|                 .optionalLimit(1L) |  | ||||||
|                 .build(); |                 .build(); | ||||||
| 
 | 
 | ||||||
|         VolumeAccessGroup vag = getSolidFireElement(sfConnection).listVolumeAccessGroups(request).getVolumeAccessGroups()[0]; |         getSolidFireElement(sfConnection).removeInitiatorsFromVolumeAccessGroup(request); | ||||||
| 
 |  | ||||||
|         String[] vagIqns = vag.getInitiators(); |  | ||||||
|         long[] vagVolumeIds = toPrimitive(vag.getVolumes()); |  | ||||||
| 
 |  | ||||||
|         return new SolidFireVag(vagId, vagIqns, vagVolumeIds); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static List<SolidFireVag> getAllVags(SolidFireConnection sfConnection) |     private static void addVolumeIdsToSolidFireVag(SolidFireConnection sfConnection, long vagId, Long[] volumeIds) { | ||||||
|  |         AddVolumesToVolumeAccessGroupRequest request = AddVolumesToVolumeAccessGroupRequest.builder() | ||||||
|  |                 .volumeAccessGroupID(vagId) | ||||||
|  |                 .volumes(volumeIds) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         getSolidFireElement(sfConnection).addVolumesToVolumeAccessGroup(request); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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(); |         ListVolumeAccessGroupsRequest request = ListVolumeAccessGroupsRequest.builder().build(); | ||||||
| 
 | 
 | ||||||
| @ -980,113 +1330,6 @@ public class SolidFireUtil { | |||||||
|         return portNumber; |         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) { |     private static List<String> getStringArrayAsLowerCaseStringList(String[] aString) { | ||||||
|         List<String> lstLowerCaseString = new ArrayList<>(); |         List<String> lstLowerCaseString = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
| @ -1106,10 +1349,6 @@ public class SolidFireUtil { | |||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Map<String, Object> convertedMap = new HashMap<>(); |         return new HashMap<>(map); | ||||||
| 
 |  | ||||||
|         convertedMap.putAll(map); |  | ||||||
| 
 |  | ||||||
|         return convertedMap; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ from marvin.cloudstackTestCase import cloudstackTestCase | |||||||
| from marvin.lib.base import Account, ServiceOffering, User, Host, StoragePool, VirtualMachine | from marvin.lib.base import Account, ServiceOffering, User, Host, StoragePool, VirtualMachine | ||||||
| 
 | 
 | ||||||
| # common - commonly used methods for all tests are listed here | # 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. | # utils - utility classes for common cleanup, external library wrappers, etc. | ||||||
| from marvin.lib.utils import cleanup_resources | from marvin.lib.utils import cleanup_resources | ||||||
| @ -46,14 +46,15 @@ from marvin.lib.utils import cleanup_resources | |||||||
| # | # | ||||||
| # Running the tests: | # Running the tests: | ||||||
| #  Change the "hypervisor_type" variable to control which hypervisor type to test. | #  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 | #  If using XenServer, set a breakpoint on each test after the first one. When the breakpoint is hit, reset the | ||||||
| #   host to a snapshot state and re-start it. Once it's up and running, run the test code. | #   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. | #  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 XenServer, verify the "xen_server_master_hostname" variable is correct. | ||||||
| #  If using KVM, verify the "kvm_1_ip_address" variable is correct. | #  If using KVM, verify the "kvm_1_ip_address" variable is correct. | ||||||
| # | # | ||||||
| # Note: | # 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: | class TestData: | ||||||
| @ -95,18 +96,18 @@ class TestData: | |||||||
|     # modify to control which hypervisor type to test |     # modify to control which hypervisor type to test | ||||||
|     hypervisor_type = xenServer |     hypervisor_type = xenServer | ||||||
|     xen_server_master_hostname = "XenServer-6.5-1" |     xen_server_master_hostname = "XenServer-6.5-1" | ||||||
|     kvm_1_ip_address = "10.117.40.112" |     kvm_1_ip_address = "10.117.40.111" | ||||||
|     ip_address_of_new_xenserver_host = "10.117.40.107" |     ip_address_of_new_xenserver_host = "10.117.40.118" | ||||||
|     ip_address_of_new_kvm_host = "10.117.40.116" |     ip_address_of_new_kvm_host = "10.117.40.115" | ||||||
| 
 | 
 | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.testdata = { |         self.testdata = { | ||||||
|             TestData.solidFire: { |             TestData.solidFire: { | ||||||
|                 TestData.mvip: "10.117.40.120", |                 TestData.mvip: "10.117.78.225", | ||||||
|                 TestData.username: "admin", |                 TestData.username: "admin", | ||||||
|                 TestData.password: "admin", |                 TestData.password: "admin", | ||||||
|                 TestData.port: 443, |                 TestData.port: 443, | ||||||
|                 TestData.url: "https://10.117.40.120:443" |                 TestData.url: "https://10.117.78.225:443" | ||||||
|             }, |             }, | ||||||
|             TestData.kvm: { |             TestData.kvm: { | ||||||
|                 TestData.username: "root", |                 TestData.username: "root", | ||||||
| @ -147,7 +148,7 @@ class TestData: | |||||||
|             TestData.primaryStorage: { |             TestData.primaryStorage: { | ||||||
|                 TestData.name: "SolidFire-%d" % random.randint(0, 100), |                 TestData.name: "SolidFire-%d" % random.randint(0, 100), | ||||||
|                 TestData.scope: "ZONE", |                 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;" + |                        "clusterAdminUsername=admin;clusterAdminPassword=admin;" + | ||||||
|                        "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + |                        "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + | ||||||
|                        "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", |                        "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", | ||||||
| @ -160,7 +161,7 @@ class TestData: | |||||||
|             TestData.primaryStorage2: { |             TestData.primaryStorage2: { | ||||||
|                 TestData.name: "SolidFireShared-%d" % random.randint(0, 100), |                 TestData.name: "SolidFireShared-%d" % random.randint(0, 100), | ||||||
|                 TestData.scope: "CLUSTER", |                 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;" + |                        "clusterAdminUsername=admin;clusterAdminPassword=admin;" + | ||||||
|                        "minIops=5000;maxIops=50000;burstIops=75000", |                        "minIops=5000;maxIops=50000;burstIops=75000", | ||||||
|                 TestData.provider: "SolidFireShared", |                 TestData.provider: "SolidFireShared", | ||||||
| @ -454,6 +455,143 @@ class TestAddRemoveHosts(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         self._perform_add_remove_xenserver_host(primary_storage_2.id, sf_iscsi_name) |         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): |     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] |         xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sr_name)[0] | ||||||
| 
 | 
 | ||||||
| @ -463,7 +601,7 @@ class TestAddRemoveHosts(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         num_pbds = len(pbds) |         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() |         host_iscsi_iqns = self._get_xenserver_host_iscsi_iqns() | ||||||
| 
 | 
 | ||||||
| @ -604,7 +742,7 @@ class TestAddRemoveHosts(cloudstackTestCase): | |||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def _perform_add_remove_kvm_host(self, primary_storage_id): |     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] |         kvm_login = self.testdata[TestData.kvm] | ||||||
| 
 | 
 | ||||||
| @ -720,6 +858,14 @@ class TestAddRemoveHosts(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         return sql_result[0][0] |         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): |     def _get_xenserver_host_iscsi_iqns(self): | ||||||
|         hosts = self.xen_session.xenapi.host.get_all() |         hosts = self.xen_session.xenapi.host.get_all() | ||||||
| 
 | 
 | ||||||
| @ -767,20 +913,6 @@ class TestAddRemoveHosts(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         return result[len(searchFor):].strip() |         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): |     def _get_sf_vag(self, sf_vag_id): | ||||||
|         return self.sfe.list_volume_access_groups(sf_vag_id, 1).volume_access_groups[0] |         return self.sfe.list_volume_access_groups(sf_vag_id, 1).volume_access_groups[0] | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,7 +33,7 @@ from marvin.cloudstackTestCase import cloudstackTestCase | |||||||
| from marvin.lib.base import Account, ServiceOffering, StoragePool, User, VirtualMachine | from marvin.lib.base import Account, ServiceOffering, StoragePool, User, VirtualMachine | ||||||
| 
 | 
 | ||||||
| # common - commonly used methods for all tests are listed here | # 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. | # utils - utility classes for common cleanup, external library wrappers, etc. | ||||||
| from marvin.lib.utils import cleanup_resources | from marvin.lib.utils import cleanup_resources | ||||||
| @ -47,7 +47,7 @@ from marvin.lib.utils import cleanup_resources | |||||||
| #  If using XenServer, verify the "xen_server_hostname" variable is correct. | #  If using XenServer, verify the "xen_server_hostname" variable is correct. | ||||||
| # | # | ||||||
| # Note: | # 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(): | class TestData(): | ||||||
| @ -193,7 +193,6 @@ class TestCapacityManagement(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         # Get Resources from Cloud Infrastructure |         # Get Resources from Cloud Infrastructure | ||||||
|         cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) |         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.template = get_template(cls.apiClient, cls.zone.id, hypervisor=TestData.hypervisor_type) | ||||||
|         cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) |         cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ from nose.plugins.attrib import attr | |||||||
| from marvin.lib.base import Account, DiskOffering, ServiceOffering, Snapshot, StoragePool, Template, User, VirtualMachine, Volume | from marvin.lib.base import Account, DiskOffering, ServiceOffering, Snapshot, StoragePool, Template, User, VirtualMachine, Volume | ||||||
| 
 | 
 | ||||||
| # common - commonly used methods for all tests are listed here | # 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. | # utils - utility classes for common cleanup, external library wrappers, etc. | ||||||
| from marvin.lib.utils import cleanup_resources, wait_until | from marvin.lib.utils import cleanup_resources, wait_until | ||||||
| @ -87,16 +87,16 @@ class TestData(): | |||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.testdata = { |         self.testdata = { | ||||||
|             TestData.solidFire: { |             TestData.solidFire: { | ||||||
|                 TestData.mvip: "10.117.40.120", |                 TestData.mvip: "10.117.78.225", | ||||||
|                 TestData.username: "admin", |                 TestData.username: "admin", | ||||||
|                 TestData.password: "admin", |                 TestData.password: "admin", | ||||||
|                 TestData.port: 443, |                 TestData.port: 443, | ||||||
|                 TestData.url: "https://10.117.40.120:443" |                 TestData.url: "https://10.117.78.225:443" | ||||||
|             }, |             }, | ||||||
|             TestData.primaryStorage: { |             TestData.primaryStorage: { | ||||||
|                 "name": "SolidFire-%d" % random.randint(0, 100), |                 "name": "SolidFire-%d" % random.randint(0, 100), | ||||||
|                 TestData.scope: "ZONE", |                 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;" + |                        "clusterAdminUsername=admin;clusterAdminPassword=admin;" + | ||||||
|                        "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + |                        "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + | ||||||
|                        "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", |                        "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", | ||||||
| @ -155,7 +155,6 @@ class TestData(): | |||||||
|                 TestData.diskName: "test-volume-2", |                 TestData.diskName: "test-volume-2", | ||||||
|             }, |             }, | ||||||
|             TestData.zoneId: 1, |             TestData.zoneId: 1, | ||||||
|             TestData.clusterId: 1, |  | ||||||
|             TestData.domainId: 1, |             TestData.domainId: 1, | ||||||
|             TestData.url: "10.117.40.114" |             TestData.url: "10.117.40.114" | ||||||
|         } |         } | ||||||
| @ -198,7 +197,6 @@ class TestSnapshots(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         # Get Resources from Cloud Infrastructure |         # Get Resources from Cloud Infrastructure | ||||||
|         cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) |         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.template = get_template(cls.apiClient, cls.zone.id, hypervisor=TestData.hypervisor_type) | ||||||
|         cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) |         cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -185,7 +185,7 @@ class TestUploadDownload(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         # Get Resources from Cloud Infrastructure |         # Get Resources from Cloud Infrastructure | ||||||
|         cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId]) |         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.template = get_template(cls.apiClient, cls.zone.id, hypervisor=TestData.hypervisor_type) | ||||||
|         cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) |         cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId]) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -40,6 +40,9 @@ from marvin.lib.utils import cleanup_resources | |||||||
| #  Only one zone | #  Only one zone | ||||||
| #  Only one pod | #  Only one pod | ||||||
| #  Two clusters (have system VMs (including the VR) running on local or NFS storage) | #  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(): | class TestData(): | ||||||
| @ -81,6 +84,9 @@ class TestData(): | |||||||
|     xenServer = "xenserver" |     xenServer = "xenserver" | ||||||
|     zoneId = "zoneid" |     zoneId = "zoneid" | ||||||
| 
 | 
 | ||||||
|  |     xen_server_hostname_src = "XenServer-6.5-1" | ||||||
|  |     xen_server_hostname_dest = "XenServer-6.5-3" | ||||||
|  | 
 | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.testdata = { |         self.testdata = { | ||||||
|             TestData.solidFire: { |             TestData.solidFire: { | ||||||
| @ -233,7 +239,7 @@ class TestVMMigrationWithStorage(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         # Set up xenAPI connection |         # Set up xenAPI connection | ||||||
|         host_ip = "https://" + \ |         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 |         # Set up XenAPI connection | ||||||
|         cls.xen_session_1 = XenAPI.Session(host_ip) |         cls.xen_session_1 = XenAPI.Session(host_ip) | ||||||
| @ -242,7 +248,7 @@ class TestVMMigrationWithStorage(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         # Set up xenAPI connection |         # Set up xenAPI connection | ||||||
|         host_ip = "https://" + \ |         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 |         # Set up XenAPI connection | ||||||
|         cls.xen_session_2 = XenAPI.Session(host_ip) |         cls.xen_session_2 = XenAPI.Session(host_ip) | ||||||
| @ -532,9 +538,9 @@ class TestVMMigrationWithStorage(cloudstackTestCase): | |||||||
|         hosts = list_hosts(self.apiClient) |         hosts = list_hosts(self.apiClient) | ||||||
| 
 | 
 | ||||||
|         for host in hosts: |         for host in hosts: | ||||||
|             if host.name == "XenServer-6.5-1": |             if host.name == TestData.xen_server_hostname_src: | ||||||
|                 src_host = host |                 src_host = host | ||||||
|             elif host.name == "XenServer-6.5-3": |             elif host.name == TestData.xen_server_hostname_dest: | ||||||
|                 dest_host = host |                 dest_host = host | ||||||
| 
 | 
 | ||||||
|         self.assertIsNotNone(src_host, "Could not locate the source host") |         self.assertIsNotNone(src_host, "Could not locate the source host") | ||||||
|  | |||||||
| @ -44,6 +44,10 @@ from marvin.lib.utils import cleanup_resources | |||||||
| #  Only one pod | #  Only one pod | ||||||
| #  Only one cluster | #  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: | class TestData: | ||||||
|     account = "account" |     account = "account" | ||||||
| @ -74,6 +78,7 @@ class TestData: | |||||||
| 
 | 
 | ||||||
|     # modify to control which hypervisor type to test |     # modify to control which hypervisor type to test | ||||||
|     hypervisor_type = xenServer |     hypervisor_type = xenServer | ||||||
|  |     xen_server_hostname = "XenServer-6.5-1" | ||||||
| 
 | 
 | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.testdata = { |         self.testdata = { | ||||||
| @ -129,7 +134,7 @@ class TestData: | |||||||
|                 "customizediops": False, |                 "customizediops": False, | ||||||
|                 "miniops": "10000", |                 "miniops": "10000", | ||||||
|                 "maxiops": "15000", |                 "maxiops": "15000", | ||||||
|                 "hypervisorsnapshotreserve": 200, |                 "hypervisorsnapshotreserve": 400, | ||||||
|                 TestData.tags: TestData.storageTag |                 TestData.tags: TestData.storageTag | ||||||
|             }, |             }, | ||||||
|             TestData.diskOffering: { |             TestData.diskOffering: { | ||||||
| @ -139,7 +144,7 @@ class TestData: | |||||||
|                 "customizediops": False, |                 "customizediops": False, | ||||||
|                 "miniops": 300, |                 "miniops": 300, | ||||||
|                 "maxiops": 500, |                 "maxiops": 500, | ||||||
|                 "hypervisorsnapshotreserve": 200, |                 "hypervisorsnapshotreserve": 400, | ||||||
|                 TestData.tags: TestData.storageTag, |                 TestData.tags: TestData.storageTag, | ||||||
|                 "storagetype": "shared" |                 "storagetype": "shared" | ||||||
|             }, |             }, | ||||||
| @ -179,7 +184,7 @@ class TestVMSnapshots(cloudstackTestCase): | |||||||
| 
 | 
 | ||||||
|         # Set up XenAPI connection |         # Set up XenAPI connection | ||||||
|         host_ip = "https://" + \ |         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) |         cls.xen_session = XenAPI.Session(host_ip) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -51,7 +51,8 @@ from marvin.lib.utils import cleanup_resources | |||||||
| #  If using XenServer, change the "supports_cloning" variable to True or False as desired. | #  If using XenServer, change the "supports_cloning" variable to True or False as desired. | ||||||
| # | # | ||||||
| # Note: | # 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(): | class TestData(): | ||||||
| @ -79,6 +80,7 @@ class TestData(): | |||||||
|     tags = "tags" |     tags = "tags" | ||||||
|     templateCacheNameKvm = "centos55-x86-64" |     templateCacheNameKvm = "centos55-x86-64" | ||||||
|     templateCacheNameXenServer = "centos56-x86-64-xen" |     templateCacheNameXenServer = "centos56-x86-64-xen" | ||||||
|  |     # templateCacheNameXenServer = "centos65-x86-64-XenServer" | ||||||
|     testAccount = "testaccount" |     testAccount = "testaccount" | ||||||
|     url = "url" |     url = "url" | ||||||
|     user = "user" |     user = "user" | ||||||
| @ -91,17 +93,17 @@ class TestData(): | |||||||
|     zoneId = "zoneId" |     zoneId = "zoneId" | ||||||
| 
 | 
 | ||||||
|     # modify to control which hypervisor type to test |     # modify to control which hypervisor type to test | ||||||
|     hypervisor_type = kvm |     hypervisor_type = xenServer | ||||||
|     xen_server_hostname = "XenServer-6.5-1" |     xen_server_hostname = "XenServer-6.5-1" | ||||||
| 
 | 
 | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.testdata = { |         self.testdata = { | ||||||
|             TestData.solidFire: { |             TestData.solidFire: { | ||||||
|                 TestData.mvip: "10.117.40.120", |                 TestData.mvip: "10.117.78.225", | ||||||
|                 TestData.username: "admin", |                 TestData.username: "admin", | ||||||
|                 TestData.password: "admin", |                 TestData.password: "admin", | ||||||
|                 TestData.port: 443, |                 TestData.port: 443, | ||||||
|                 TestData.url: "https://10.117.40.120:443" |                 TestData.url: "https://10.117.78.225:443" | ||||||
|             }, |             }, | ||||||
|             TestData.kvm: { |             TestData.kvm: { | ||||||
|                 TestData.username: "root", |                 TestData.username: "root", | ||||||
| @ -135,7 +137,7 @@ class TestData(): | |||||||
|             TestData.primaryStorage: { |             TestData.primaryStorage: { | ||||||
|                 "name": "SolidFire-%d" % random.randint(0, 100), |                 "name": "SolidFire-%d" % random.randint(0, 100), | ||||||
|                 TestData.scope: "ZONE", |                 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;" + |                        "clusterAdminUsername=admin;clusterAdminPassword=admin;" + | ||||||
|                        "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + |                        "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" + | ||||||
|                        "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", |                        "clusterDefaultBurstIopsPercentOfMaxIops=1.5;", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user