diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 8e9ec450b1ed..f1ab9cd1ff95 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1672,10 +1672,13 @@ protected boolean sendStop(final VirtualMachineGuru guru, final VirtualMachinePr } guru.finalizeStop(profile, answer); + + final UserVmVO userVm = _userVmDao.findById(vm.getId()); if (vm.getType() == VirtualMachine.Type.User) { - final UserVmVO userVm = _userVmDao.findById(vm.getId()); - userVm.setPowerState(PowerState.PowerOff); - _userVmDao.update(userVm.getId(), userVm); + if (userVm != null){ + userVm.setPowerState(PowerState.PowerOff); + _userVmDao.update(userVm.getId(), userVm); + } } } else { s_logger.error("Invalid answer received in response to a StopCommand for " + vm.getInstanceName()); diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java index 09b4b1ab3853..6a903e4235a4 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java @@ -25,10 +25,16 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import javax.inject.Inject; +import com.cloud.dc.DedicatedResourceVO; +import com.cloud.dc.dao.DedicatedResourceDao; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; @@ -64,6 +70,8 @@ public class DefaultEndPointSelector implements EndPointSelector { private static final Logger s_logger = Logger.getLogger(DefaultEndPointSelector.class); @Inject private HostDao hostDao; + @Inject + private DedicatedResourceDao dedicatedResourceDao; private final String findOneHostOnPrimaryStorage = "select t.id from " + "(select h.id, cd.value " + "from host h join storage_pool_host_ref s on h.id = s.host_id " @@ -115,6 +123,8 @@ protected EndPoint findEndPointInScope(Scope scope, String sqlBase, Long poolId) StringBuilder sbuilder = new StringBuilder(); sbuilder.append(sqlBase); + List dedicatedHosts = new ArrayList(); + if (scope != null) { if (scope.getScopeType() == ScopeType.HOST) { sbuilder.append(" and h.id = "); @@ -122,15 +132,23 @@ protected EndPoint findEndPointInScope(Scope scope, String sqlBase, Long poolId) } else if (scope.getScopeType() == ScopeType.CLUSTER) { sbuilder.append(" and h.cluster_id = "); sbuilder.append(scope.getScopeId()); + dedicatedHosts = dedicatedResourceDao.findHostsByCluster(scope.getScopeId()); } else if (scope.getScopeType() == ScopeType.ZONE) { sbuilder.append(" and h.data_center_id = "); sbuilder.append(scope.getScopeId()); + dedicatedHosts = dedicatedResourceDao.findHostsByZone(scope.getScopeId()); } + } else { + dedicatedHosts = dedicatedResourceDao.listAllHosts(); } // TODO: order by rand() is slow if there are lot of hosts sbuilder.append(") t where t.value<>'true' or t.value is null"); //Added for exclude cluster's subquery - sbuilder.append(" ORDER by rand() limit 1"); + sbuilder.append(" ORDER by "); + if (dedicatedHosts.size() > 0) { + moveDedicatedHostsToLowerPriority(sbuilder, dedicatedHosts); + } + sbuilder.append(" rand() limit 1"); String sql = sbuilder.toString(); HostVO host = null; TransactionLegacy txn = TransactionLegacy.currentTxn(); @@ -154,6 +172,42 @@ protected EndPoint findEndPointInScope(Scope scope, String sqlBase, Long poolId) return RemoteHostEndPoint.getHypervisorHostEndPoint(host); } + private void moveDedicatedHostsToLowerPriority(StringBuilder sbuilder, List dedicatedHosts) { + + // Check if we have a call context + final CallContext context = CallContext.current(); + if (context != null) { + Account account = context.getCallingAccount(); + if (account != null) { + // Remove hosts for this account. Only leave hosts dedicated to other accounts in the lower priority list. + Pair, Integer> hostIds = dedicatedResourceDao.searchDedicatedHosts(null, null, account.getId(), null, null); + List accountDedicatedHosts = hostIds.first(); + for (DedicatedResourceVO accountDedicatedResource: accountDedicatedHosts){ + Iterator dedicatedHostsIterator = dedicatedHosts.iterator(); + while (dedicatedHostsIterator.hasNext()) { + if (dedicatedHostsIterator.next() == accountDedicatedResource.getHostId()) { + dedicatedHostsIterator.remove(); + } + } + } + } + } + + if (dedicatedHosts.size() > 0) { + Collections.shuffle(dedicatedHosts); // Randomize dedicated hosts as well. + sbuilder.append("field(t.id, "); + int hostIndex = 0; + for (Long hostId: dedicatedHosts) { // put dedicated hosts at the end of the result set + sbuilder.append("'" + hostId + "'"); + hostIndex++; + if (hostIndex < dedicatedHosts.size()){ + sbuilder.append(","); + } + } + sbuilder.append(")," ); + } + } + protected EndPoint findEndPointForImageMove(DataStore srcStore, DataStore destStore) { // find any xenserver/kvm host in the scope Scope srcScope = srcStore.getScope(); diff --git a/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDao.java b/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDao.java index 7c41439b1ec0..3527ef7638e2 100644 --- a/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDao.java +++ b/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDao.java @@ -55,4 +55,7 @@ public interface DedicatedResourceDao extends GenericDao listByAffinityGroupId(Long affinityGroupId); + List findHostsByCluster(Long clusterId); + + List findHostsByZone(Long zoneId); } \ No newline at end of file diff --git a/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDaoImpl.java b/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDaoImpl.java index c406755f9945..c10ef2dc25fc 100644 --- a/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDaoImpl.java +++ b/server/src/main/java/com/cloud/dc/dao/DedicatedResourceDaoImpl.java @@ -16,9 +16,14 @@ // under the License. package com.cloud.dc.dao; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.utils.db.Filter; import org.springframework.stereotype.Component; @@ -32,10 +37,17 @@ import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.db.JoinBuilder; + +import javax.inject.Inject; @Component @DB public class DedicatedResourceDaoImpl extends GenericDaoBase implements DedicatedResourceDao { + + @Inject + protected HostDao hostDao; + protected final SearchBuilder ZoneSearch; protected final SearchBuilder PodSearch; protected final SearchBuilder ClusterSearch; @@ -64,6 +76,8 @@ public class DedicatedResourceDaoImpl extends GenericDaoBase ListPodsSearch; protected GenericSearchBuilder ListClustersSearch; protected GenericSearchBuilder ListHostsSearch; + protected SearchBuilder ListHostsByCluster; + protected SearchBuilder ListHostsByZone; protected DedicatedResourceDaoImpl() { PodSearch = createSearchBuilder(); @@ -369,4 +383,49 @@ public List listByAffinityGroupId(Long affinityGroupId) { sc.setParameters("affinityGroupId", affinityGroupId); return listBy(sc); } + + @Override + public boolean configure(String name, Map params) { + ListHostsByCluster = createSearchBuilder(); + SearchBuilder clusterHostsSB = hostDao.createSearchBuilder(); + clusterHostsSB.and("cluster_id", clusterHostsSB.entity().getClusterId(), Op.EQ); + clusterHostsSB.and("type", clusterHostsSB.entity().getType(), Op.EQ); + ListHostsByCluster.join("clusterHostsSB", clusterHostsSB, clusterHostsSB.entity().getId(), ListHostsByCluster.entity().getHostId(), JoinBuilder.JoinType.INNER); + ListHostsByCluster.done(); + + ListHostsByZone = createSearchBuilder(); + SearchBuilder zoneHostsSB = hostDao.createSearchBuilder(); + zoneHostsSB = hostDao.createSearchBuilder(); + zoneHostsSB.and("zone_id", zoneHostsSB.entity().getDataCenterId(), Op.EQ); + zoneHostsSB.and("type", zoneHostsSB.entity().getType(), Op.EQ); + ListHostsByZone.join("zoneHostsSB", zoneHostsSB, zoneHostsSB.entity().getId(), ListHostsByZone.entity().getHostId(), JoinBuilder.JoinType.INNER); + ListHostsByZone.done(); + return true; + } + + @Override + public List findHostsByCluster(Long clusterId) { + List hosts = new ArrayList<>(); + SearchCriteria sc = ListHostsByCluster.create(); + sc.setJoinParameters("clusterHostsSB", "type", Host.Type.Routing); + sc.setJoinParameters("clusterHostsSB","cluster_id", clusterId); + List results = customSearch(sc, null); + for (DedicatedResourceVO dedicatedResourceVO: results){ + hosts.add(dedicatedResourceVO.getHostId()); + } + return hosts; + } + + @Override + public List findHostsByZone(Long zoneId) { + List hosts = new ArrayList<>(); + SearchCriteria sc = ListHostsByZone.create(); + sc.setJoinParameters("zoneHostsSB", "type", Host.Type.Routing); + sc.setJoinParameters("zoneHostsSB","zone_id", zoneId); + List results = customSearch(sc, null); + for (DedicatedResourceVO dedicatedResourceVO: results){ + hosts.add(dedicatedResourceVO.getHostId()); + } + return hosts; + } }