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