package org.ovirt.engine.core.bll.scheduling.policyunits; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.mockito.Mock; import org.ovirt.engine.core.bll.DbDependentTestBase; import org.ovirt.engine.core.bll.scheduling.PolicyUnitParameter; import org.ovirt.engine.core.bll.scheduling.pending.PendingResourceManager; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.OriginType; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.scheduling.PerHostMessages; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.utils.MockConfigRule; public class HostedEngineMemoryReservationFilterPolicyUnitTest extends DbDependentTestBase { @ClassRule public static MockConfigRule configRule = new MockConfigRule(); private Cluster cluster; private Guid clusterId; private List<VDS> hosts; private VM vm; private VM hostedEngine; private PendingResourceManager pendingResourceManager; private Map<String, String> parameters; private PerHostMessages messages; // Unit under test HostedEngineMemoryReservationFilterPolicyUnit policyUnit; @Mock private VmDao vmDao; @Before public void setUp() throws Exception { Cluster cluster = new Cluster(); clusterId = Guid.newGuid(); cluster.setId(clusterId); pendingResourceManager = new PendingResourceManager(); vm = new VM(); vm.setId(Guid.newGuid()); vm.setClusterId(clusterId); vm.setVmMemSizeMb(1024); hosts = new ArrayList<>(); hosts.add(prepareHost("A", 8192, true, 2400, false)); hosts.add(prepareHost("B", 8192, true, 2400, false)); hosts.add(prepareHost("C", 8192, true, 2400, false)); hosts.add(prepareHost("D", 8192, true, 2400, false)); hosts.add(prepareHost("E", 8192, true, 2400, false)); hostedEngine = new VM(); hostedEngine.setOrigin(OriginType.HOSTED_ENGINE); hostedEngine.setVmMemSizeMb(4096); hostedEngine.setId(Guid.newGuid()); hostedEngine.setClusterId(clusterId); hostedEngine.setRunOnVds(hosts.get(0).getId()); policyUnit = new HostedEngineMemoryReservationFilterPolicyUnit(null, pendingResourceManager); parameters = new HashMap<>(); parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "0"); messages = new PerHostMessages(); when(DbFacade.getInstance().getVmDao()).thenReturn(vmDao); doReturn(hostedEngine).when(vmDao).getHostedEngineVm(); } @Test public void testNoHosts() throws Exception { List<VDS> result = policyUnit.filter(cluster, new ArrayList<VDS>(), vm, parameters, messages); assertEquals(0, result.size()); } @Test public void testWithNoRequiredSpares() throws Exception { List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } @Test public void testWithEnoughSpares() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "5"); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } /** * Test a scenario where more spares than available hosts * is needed. * * All spares have enough memory to accomodate both the VM and the engine * and so all should be available for further evaluation. */ @Test public void testWithoutEnoughSpares() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "6"); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } /** * Test a scenario where more spares than hosts with enough * memory to run HA + vm is needed. * * Only the host where the engine is currently running should be * a good enough host for another VM. */ @Test public void testWithoutEnoughSparesFullMemory() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "5"); hostedEngine.setVmMemSizeMb(7000); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(1, result.size()); assertEquals("A", result.get(0).getName()); } /** * Test a scenario where there is no hosted engine deployment, but the situation * would cause host removal under hosted engine cluster. * * All hosts should be returned. */ @Test public void testNoHostedEngine() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "5"); hostedEngine.setVmMemSizeMb(7000); hostedEngine.setOrigin(OriginType.OVIRT); doReturn(null).when(vmDao).getHostedEngineVm(); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } /** * Test a scenario where there is hosted engine deployment, the situation * would cause host removal under hosted engine cluster, but the HE VM * belongs to a different cluster. * * All hosts should be returned. */ @Test public void testDifferentCluster() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "5"); hostedEngine.setVmMemSizeMb(7000); hostedEngine.setClusterId(Guid.SYSTEM); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } /** * Test a scenario where there are enough spares, but some hosts * do not have enough memory for the engine VM. * * 1 host currently hosts the HE - node 0 * 2 hosts act as spares with enough memory for the vm - nodes 1 and 2 * 2 hosts have enough memory for the vm, but not for HE = nodes 3 and 4 * * Only one spare is required so all hosts can be used as candidates for * running the vm. * * All hosts should be returned. */ @Test public void testWithEnoughSparesMemory() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "1"); hostedEngine.setVmMemSizeMb(7000); hosts.get(3).setPhysicalMemMb(2048); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } /** * Test a scenario where there are the exact amount of spares, and some hosts * do not have enough memory for the engine VM. * * Three hosts (2 + the current host for HE VM) should be returned */ @Test public void testExactSparesMemory() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "2"); hostedEngine.setVmMemSizeMb(7000); hosts.get(3).setPhysicalMemMb(2048); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(3, result.size()); } /** * Test a scenario where there are not enough spares, some hosts * do not have enough memory for the engine VM. * * Three hosts (2 + the current host for HE VM) should be returned */ @Test public void testWithoutEnoughSparesMemory() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "3"); hostedEngine.setVmMemSizeMb(7000); hosts.get(3).setPhysicalMemMb(2048); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(3, result.size()); } /** * Test a scenario where there are not enough spares, some hosts * do not have enough memory for the engine VM and one host is not * HE enabled. * * Four hosts (3 + the current host for HE VM) should be returned */ @Test public void testWithNonHEHost() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "3"); hostedEngine.setVmMemSizeMb(7000); hosts.get(2).setHighlyAvailableIsActive(false); hosts.get(3).setPhysicalMemMb(2048); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(4, result.size()); } /** * Test a scenario where there are not enough spares, some hosts * do not have enough memory for the engine VM and one host is not * ready and has HE score 0. * * Four hosts (3 + the current host for HE VM) should be returned */ @Test public void testWith0ScoreHost() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "3"); hostedEngine.setVmMemSizeMb(7000); hosts.get(2).setHighlyAvailableScore(0); hosts.get(3).setPhysicalMemMb(2048); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(4, result.size()); } /** * Test a scenario where there are not enough spares, some hosts * do not have enough memory for the engine VM and one host is not * ready and has HE score 0. * * The spare host is capable of running HE and VM together though. * * All hosts should be returned */ @Test public void testWith0ScoreHostAndEnoughMemoryForTwo() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "3"); hostedEngine.setVmMemSizeMb(5000); hosts.get(2).setHighlyAvailableScore(0); hosts.get(3).setPhysicalMemMb(2048); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } /** * Test a scenario where there are not enough spares, some hosts * do not have enough memory for the engine VM and one host is not * ready and has HE score 0. * * One spare host is capable of running HE and VM together and the second * one is not. * * Four hosts should be returned (one spare does not have enough mem * for the additional VM). */ @Test public void testWith0ScoreHostAndSomeHaveEnoughMemoryForTwo() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "3"); hostedEngine.setVmMemSizeMb(5000); hosts.get(2).setHighlyAvailableScore(0); hosts.get(3).setPhysicalMemMb(6000); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(4, result.size()); } /** * Test a scenario where there are not enough spares, some hosts * do not have enough memory for the engine VM and one host is * in local maintenance. * * One spare host is capable of running HE and VM together and the second * one is not. * * Four hosts should be returned (one spare does not have enough mem * for the additional VM). */ @Test public void testWithMaintenancedHostAndSomeHaveEnoughMemoryForTwo() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "3"); hostedEngine.setVmMemSizeMb(5000); hosts.get(2).setHighlyAvailableLocalMaintenance(true); hosts.get(3).setPhysicalMemMb(6000); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(4, result.size()); } /** * Test a scenario when engine VM is scheduled and there are not enough spares, * some hosts do not have enough memory for the engine VM and one host is * in local maintenance. * * One spare host is capable of running HE and VM together and the second * one is not. * * All hosts should be returned. */ @Test public void testStartingTheEngineWithNotEnoughSpares() throws Exception { parameters.put(PolicyUnitParameter.HE_SPARES_COUNT.getDbName(), "3"); hostedEngine.setVmMemSizeMb(5000); hosts.get(2).setHighlyAvailableLocalMaintenance(true); hosts.get(3).setPhysicalMemMb(7000); hosts.get(4).setPhysicalMemMb(2048); List<VDS> result = policyUnit.filter(cluster, hosts, hostedEngine, parameters, messages); assertEquals(5, result.size()); } /** * Test a scenario where one host was placed to local maintenance. * It should not affect the result with regards to scheduling * arbitrary VMs. */ @Test public void testHostInMaintenance() throws Exception { hosts.get(0).setHighlyAvailableLocalMaintenance(true); List<VDS> result = policyUnit.filter(cluster, hosts, vm, parameters, messages); assertEquals(5, result.size()); } private VDS prepareHost(String name, int freeMemoryMb, boolean heEnabled, int heScore, boolean localMaintnance) { VDS host = new VDS(); host.setId(Guid.newGuid()); host.setClusterId(clusterId); host.setVdsName(name); host.setPhysicalMemMb(freeMemoryMb); host.setMemAvailable((long) freeMemoryMb); host.setMemCommited(0); host.setMemShared(0L); host.setReservedMem(128); host.setGuestOverhead(64); host.setHighlyAvailableIsActive(heEnabled); host.setHighlyAvailableScore(heScore); host.setHighlyAvailableLocalMaintenance(localMaintnance); host.setMaxVdsMemoryOverCommit(100); return host; } }