[CLOUDSTACK-10128] Simplify the search for host to execute command

This commit is contained in:
Rafael Weingärtner 2018-01-11 09:14:34 -02:00
parent 7ca4582a85
commit 1c8bbddb04
7 changed files with 52 additions and 83 deletions

View File

@ -19,13 +19,12 @@ package com.cloud.host.dao;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import com.cloud.host.Host; import com.cloud.host.Host;
import com.cloud.host.Host.Type; import com.cloud.host.Host.Type;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.host.Status; import com.cloud.host.Status;
import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.info.RunningHostCountInfo; import com.cloud.info.RunningHostCountInfo;
import com.cloud.resource.ResourceState; import com.cloud.resource.ResourceState;
import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.GenericDao;
@ -99,14 +98,13 @@ public interface HostDao extends GenericDao<HostVO, Long>, StateDao<Status, Stat
HostVO findByIp(String ip); HostVO findByIp(String ip);
/** /**
* This method will look for a host that is of the same hypervisor and same zone as the storage pool where the volume of the Snapshot is stored. * This method will look for a host that is of the same hypervisor and zone as indicated in its parameters.
* <ul> * <ul>
* <li>(this is applicable only for XenServer) If the storage pool is managed, then we will look for a host that has the property 'supportsResign' in cloud.cluster_details
* <li>We give priority to 'Enabled' hosts, but if no 'Enabled' hosts are found, we use 'Disabled' hosts * <li>We give priority to 'Enabled' hosts, but if no 'Enabled' hosts are found, we use 'Disabled' hosts
* <li>If no host is found, we throw a runtime exception * <li>If no host is found, we throw a runtime exception
* </ul> * </ul>
* *
* Side note: this method is currently only used in XenServerGuru; therefore, it was designed to meet XenServer deployment scenarios requirements. * Side note: this method is currently only used in XenServerGuru; therefore, it was designed to meet XenServer deployment scenarios requirements.
*/ */
HostVO findHostToOperateOnSnapshotBasedOnStoragePool(StoragePoolVO storagePoolVO); HostVO findHostInZoneToExecuteCommand(long zoneId, HypervisorType hypervisorType);
} }

View File

@ -24,14 +24,13 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.TimeZone; import java.util.TimeZone;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.inject.Inject; import javax.inject.Inject;
import javax.persistence.TableGenerator; import javax.persistence.TableGenerator;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -50,6 +49,7 @@ import com.cloud.host.HostVO;
import com.cloud.host.Status; import com.cloud.host.Status;
import com.cloud.host.Status.Event; import com.cloud.host.Status.Event;
import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.info.RunningHostCountInfo; import com.cloud.info.RunningHostCountInfo;
import com.cloud.org.Grouping; import com.cloud.org.Grouping;
import com.cloud.org.Managed; import com.cloud.org.Managed;
@ -1168,25 +1168,23 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
return listBy(sc); return listBy(sc);
} }
String sqlFindHostConnectedToStoragePoolToExecuteCommand = "select h.id from storage_pool pool " String sqlFindHostInZoneToExecuteCommand = "Select id from host "
+ " join cluster c on pool.cluster_id = c.id " + " where type = 'Routing' and hypervisor_type = ? and data_center_id = ? and status = 'Up' "
+ " %s " + " and resource_state = '%s' "
+ " join host h on h.data_center_id = c.data_center_id and h.hypervisor_type = c.hypervisor_type" + " ORDER by rand() limit 1";
+ " where pool.id = ? and h.status = 'Up' and h.type = 'Routing' and resource_state = '%s' "
+ " ORDER by rand() limit 1 ";
@Override @Override
public HostVO findHostToOperateOnSnapshotBasedOnStoragePool(StoragePoolVO storagePoolVO) { public HostVO findHostInZoneToExecuteCommand(long zoneId, HypervisorType hypervisorType) {
try (TransactionLegacy tx = TransactionLegacy.currentTxn()) { try (TransactionLegacy tx = TransactionLegacy.currentTxn()) {
String sql = createSqlFindHostConnectedToStoragePoolToExecuteCommand(storagePoolVO, false); String sql = createSqlFindHostToExecuteCommand(false);
ResultSet rs = executeSqlGetResultSetForMethodFindHostToOperateBasedOnStoragePool(storagePoolVO, tx, sql); ResultSet rs = executeSqlGetResultsetForMethodFindHostInZoneToExecuteCommand(hypervisorType, zoneId, tx, sql);
if (rs.next()) { if (rs.next()) {
return findById(rs.getLong("id")); return findById(rs.getLong("id"));
} }
sql = createSqlFindHostConnectedToStoragePoolToExecuteCommand(storagePoolVO, true); sql = createSqlFindHostToExecuteCommand(true);
rs = executeSqlGetResultSetForMethodFindHostToOperateBasedOnStoragePool(storagePoolVO, tx, sql); rs = executeSqlGetResultsetForMethodFindHostInZoneToExecuteCommand(hypervisorType, zoneId, tx, sql);
if (!rs.next()) { if (!rs.next()) {
throw new CloudRuntimeException(String.format("Could not find a host connected to the storage pool [storagepool=%d]. ", storagePoolVO.getId())); throw new CloudRuntimeException(String.format("Could not find a host in zone [zoneId=%d] to operate on. ", zoneId));
} }
return findById(rs.getLong("id")); return findById(rs.getLong("id"));
} catch (SQLException e) { } catch (SQLException e) {
@ -1194,21 +1192,18 @@ public class HostDaoImpl extends GenericDaoBase<HostVO, Long> implements HostDao
} }
} }
private ResultSet executeSqlGetResultSetForMethodFindHostToOperateBasedOnStoragePool(StoragePoolVO storagePoolVO, TransactionLegacy tx, String sql) throws SQLException { private ResultSet executeSqlGetResultsetForMethodFindHostInZoneToExecuteCommand(HypervisorType hypervisorType, long zoneId, TransactionLegacy tx, String sql) throws SQLException {
PreparedStatement pstmt = tx.prepareAutoCloseStatement(sql); PreparedStatement pstmt = tx.prepareAutoCloseStatement(sql);
pstmt.setLong(1, storagePoolVO.getId()); pstmt.setString(1, Objects.toString(hypervisorType));
pstmt.setLong(2, zoneId);
return pstmt.executeQuery(); return pstmt.executeQuery();
} }
private String createSqlFindHostConnectedToStoragePoolToExecuteCommand(StoragePoolVO storagePoolVO, boolean useDisabledHosts) { private String createSqlFindHostToExecuteCommand(boolean useDisabledHosts) {
String hostResourceStatus = "Enabled"; String hostResourceStatus = "Enabled";
if (useDisabledHosts) { if (useDisabledHosts) {
hostResourceStatus = "Disabled"; hostResourceStatus = "Disabled";
} }
String joinForManagedStorage = StringUtils.EMPTY; return String.format(sqlFindHostInZoneToExecuteCommand, hostResourceStatus);
if (storagePoolVO.isManaged()) {
joinForManagedStorage = " join cluster_details cd on cd.cluster_id = c.id and cd.name = 'supportsResign' and cd.value = 'true' ";
}
return String.format(sqlFindHostConnectedToStoragePoolToExecuteCommand, joinForManagedStorage, hostResourceStatus);
} }
} }

View File

@ -123,11 +123,4 @@ public interface PrimaryDataStoreDao extends GenericDao<StoragePoolVO, Long> {
List<StoragePoolVO> listLocalStoragePoolByPath(long datacenterId, String path); List<StoragePoolVO> listLocalStoragePoolByPath(long datacenterId, String path);
void deletePoolTags(long poolId); void deletePoolTags(long poolId);
/**
* Looks for a storage pool where the original volume of the snapshot was taken.
* Even if the volume has already been deleted, we will return the last storage pool where it was stored.
*/
StoragePoolVO findStoragePoolForSnapshot(long snapshotId);
} }

View File

@ -554,25 +554,4 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase<StoragePoolVO, Long>
public void deletePoolTags(long poolId) { public void deletePoolTags(long poolId) {
_tagsDao.deleteTags(poolId); _tagsDao.deleteTags(poolId);
} }
private String sqlIsSnapshotStoragePoolManaged = "select pool.id from snapshots s "
+ " join volumes v on v.id = s.volume_id "
+ " join storage_pool pool on pool.id = v.pool_id "
+ " where s.id = ?";
@Override
public StoragePoolVO findStoragePoolForSnapshot(long snapshotId) {
try (TransactionLegacy tx = TransactionLegacy.currentTxn();
PreparedStatement pstmt = tx.prepareAutoCloseStatement(sqlIsSnapshotStoragePoolManaged);) {
pstmt.setLong(1, snapshotId);
ResultSet rs = pstmt.executeQuery();
if (!rs.next()) {
throw new CloudRuntimeException(String.format("Could not find a storage pool for snapshot [snapshotId=%d]. ", snapshotId));
}
long storagePoolId = rs.getLong("id");
return findById(storagePoolId);
} catch (SQLException e) {
throw new CloudRuntimeException(e);
}
}
} }

View File

@ -202,9 +202,9 @@ public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru,
logger.debug("We are returning the default host to execute commands because the source and destination objects are not snapshot and template respectively."); logger.debug("We are returning the default host to execute commands because the source and destination objects are not snapshot and template respectively.");
return defaultHostToExecuteCommands; return defaultHostToExecuteCommands;
} }
long snapshotId = srcData.getId(); HostVO defaultHostToExecuteCommand = hostDao.findById(hostId);
StoragePoolVO storagePoolVO = storagePoolDao.findStoragePoolForSnapshot(snapshotId);
HostVO hostCandidateToExecutedCommand = hostDao.findHostToOperateOnSnapshotBasedOnStoragePool(storagePoolVO); HostVO hostCandidateToExecutedCommand = hostDao.findHostInZoneToExecuteCommand(defaultHostToExecuteCommand.getDataCenterId(), srcData.getHypervisorType());
hostDao.loadDetails(hostCandidateToExecutedCommand); hostDao.loadDetails(hostCandidateToExecutedCommand);
String hypervisorVersion = hostCandidateToExecutedCommand.getHypervisorVersion(); String hypervisorVersion = hostCandidateToExecutedCommand.getHypervisorVersion();
if (StringUtils.isBlank(hypervisorVersion)) { if (StringUtils.isBlank(hypervisorVersion)) {
@ -219,9 +219,7 @@ public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru,
String snapshotHotFixVersion = hostCandidateToExecutedCommand.getDetail(XenserverConfigs.XS620HotFix); String snapshotHotFixVersion = hostCandidateToExecutedCommand.getDetail(XenserverConfigs.XS620HotFix);
boolean isXenServer620 = StringUtils.equals(hypervisorVersion, "6.2.0"); boolean isXenServer620 = StringUtils.equals(hypervisorVersion, "6.2.0");
if (isXenServer620 && !StringUtils.equalsIgnoreCase(XenserverConfigs.XSHotFix62ESP1004, snapshotHotFixVersion)) { if (isXenServer620 && !StringUtils.equalsIgnoreCase(XenserverConfigs.XSHotFix62ESP1004, snapshotHotFixVersion)) {
logger.debug(String.format( logger.debug(String.format("We are returning the default host to execute commands because the hypervisor version is not 6.2.0 with hotfix ESP1004 [hypervisorVersion=%s, hotfixVersion=%s]", hypervisorVersion, snapshotHotFixVersion));
"We are returning the default host to execute commands because the hypervisor version is not 6.2.0 with hotfix ESP1004 [hypervisorVersion=%s, hotfixVersion=%s]",
hypervisorVersion, snapshotHotFixVersion));
return defaultHostToExecuteCommands; return defaultHostToExecuteCommands;
} }
logger.debug(String.format("We are changing the hostId to executed command from %d to %d.", hostId, hostCandidateToExecutedCommand.getId())); logger.debug(String.format("We are changing the hostId to executed command from %d to %d.", hostId, hostCandidateToExecutedCommand.getId()));

View File

@ -21,7 +21,6 @@ import org.apache.cloudstack.hypervisor.xenserver.XenserverConfigs;
import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -54,8 +53,6 @@ public class XenServerGuruTest {
@Mock @Mock
private PrimaryDataStoreDao storagePoolDao; private PrimaryDataStoreDao storagePoolDao;
private Long defaultHostId = 1l;
@Mock @Mock
private CopyCommand copyCommandMock; private CopyCommand copyCommandMock;
@ -65,23 +62,31 @@ public class XenServerGuruTest {
@Mock @Mock
private DataTO destinationDataMock; private DataTO destinationDataMock;
@Mock private Long defaultHostId = 1l;
private HostVO hostMock;
@Mock @Mock
private StoragePoolVO storagePoolMock; private HostVO defaultHost;
@Mock
private HostVO changedHost;
private Long changedHostId = 12l; private Long changedHostId = 12l;
private long snapshotId = 5l; private long zoneId = 100l;
@Before @Before
public void beforeTest() { public void beforeTest() {
Mockito.when(sourceDataMock.getHypervisorType()).thenReturn(HypervisorType.XenServer);
Mockito.when(copyCommandMock.getSrcTO()).thenReturn(sourceDataMock); Mockito.when(copyCommandMock.getSrcTO()).thenReturn(sourceDataMock);
Mockito.when(copyCommandMock.getDestTO()).thenReturn(destinationDataMock); Mockito.when(copyCommandMock.getDestTO()).thenReturn(destinationDataMock);
Mockito.when(hostMock.getId()).thenReturn(changedHostId);
Mockito.when(sourceDataMock.getId()).thenReturn(snapshotId); Mockito.when(changedHost.getId()).thenReturn(changedHostId);
Mockito.when(storagePoolDao.findStoragePoolForSnapshot(snapshotId)).thenReturn(storagePoolMock); Mockito.when(defaultHost.getId()).thenReturn(defaultHostId);
Mockito.when(defaultHost.getDataCenterId()).thenReturn(zoneId);
Mockito.when(hostDaoMock.findById(defaultHostId)).thenReturn(defaultHost);
Mockito.when(hostDaoMock.findById(changedHostId)).thenReturn(changedHost);
} }
@Test @Test
@ -162,8 +167,8 @@ public class XenServerGuruTest {
configureSourceAndDestinationDataMockDataStoreAsNfsToType(); configureSourceAndDestinationDataMockDataStoreAsNfsToType();
configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate(); configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate();
Mockito.when(hostMock.getHypervisorVersion()).thenReturn(StringUtils.EMPTY); Mockito.when(changedHost.getHypervisorVersion()).thenReturn(StringUtils.EMPTY);
Mockito.when(hostDaoMock.findHostToOperateOnSnapshotBasedOnStoragePool(storagePoolMock)).thenReturn(hostMock); Mockito.when(hostDaoMock.findHostInZoneToExecuteCommand(zoneId, HypervisorType.XenServer)).thenReturn(changedHost);
Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock); Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock);
@ -181,8 +186,8 @@ public class XenServerGuruTest {
configureSourceAndDestinationDataMockDataStoreAsNfsToType(); configureSourceAndDestinationDataMockDataStoreAsNfsToType();
configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate(); configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate();
Mockito.when(hostMock.getHypervisorVersion()).thenReturn("6.1.0"); Mockito.when(changedHost.getHypervisorVersion()).thenReturn("6.1.0");
Mockito.when(hostDaoMock.findHostToOperateOnSnapshotBasedOnStoragePool(storagePoolMock)).thenReturn(hostMock); Mockito.when(hostDaoMock.findHostInZoneToExecuteCommand(zoneId, HypervisorType.XenServer)).thenReturn(changedHost);
Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock); Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock);
@ -194,8 +199,8 @@ public class XenServerGuruTest {
configureSourceAndDestinationDataMockDataStoreAsNfsToType(); configureSourceAndDestinationDataMockDataStoreAsNfsToType();
configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate(); configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate();
Mockito.when(hostMock.getHypervisorVersion()).thenReturn("6.2.0"); Mockito.when(changedHost.getHypervisorVersion()).thenReturn("6.2.0");
Mockito.when(hostDaoMock.findHostToOperateOnSnapshotBasedOnStoragePool(storagePoolMock)).thenReturn(hostMock); Mockito.when(hostDaoMock.findHostInZoneToExecuteCommand(zoneId, HypervisorType.XenServer)).thenReturn(changedHost);
Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock); Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock);
@ -207,10 +212,10 @@ public class XenServerGuruTest {
configureSourceAndDestinationDataMockDataStoreAsNfsToType(); configureSourceAndDestinationDataMockDataStoreAsNfsToType();
configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate(); configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate();
Mockito.when(hostMock.getHypervisorVersion()).thenReturn("6.2.0"); Mockito.when(changedHost.getHypervisorVersion()).thenReturn("6.2.0");
Mockito.when(hostMock.getDetail(XenserverConfigs.XS620HotFix)).thenReturn(XenserverConfigs.XSHotFix62ESP1004); Mockito.when(changedHost.getDetail(XenserverConfigs.XS620HotFix)).thenReturn(XenserverConfigs.XSHotFix62ESP1004);
Mockito.when(hostDaoMock.findHostToOperateOnSnapshotBasedOnStoragePool(storagePoolMock)).thenReturn(hostMock); Mockito.when(hostDaoMock.findHostInZoneToExecuteCommand(zoneId, HypervisorType.XenServer)).thenReturn(changedHost);
Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock); Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock);
@ -223,9 +228,9 @@ public class XenServerGuruTest {
configureSourceAndDestinationDataMockDataStoreAsNfsToType(); configureSourceAndDestinationDataMockDataStoreAsNfsToType();
configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate(); configureSourceHypervisorAsXenServerAndSourceTypeAsSnapshotAndDestinationTypeAsTemplate();
Mockito.when(hostMock.getHypervisorVersion()).thenReturn("6.5.0"); Mockito.when(changedHost.getHypervisorVersion()).thenReturn("6.5.0");
Mockito.when(hostDaoMock.findHostToOperateOnSnapshotBasedOnStoragePool(storagePoolMock)).thenReturn(hostMock); Mockito.when(hostDaoMock.findHostInZoneToExecuteCommand(zoneId, HypervisorType.XenServer)).thenReturn(changedHost);
Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock); Pair<Boolean, Long> pairHostToExecuteCommand = xenServerGuru.getCommandHostDelegation(defaultHostId, copyCommandMock);

View File

@ -22,3 +22,4 @@ cloudmonkey
# Install the SolidFire SDK for Python # Install the SolidFire SDK for Python
solidfire-sdk-python solidfire-sdk-python