Skip to content

Commit ad7ed7a

Browse files
committed
Merge pull request #847 from kishankavala/CLOUDSTACK-8880
Bug-ID: CLOUDSTACK-8880: calculate free memory on host before deploying Vm. free memory = total memory - (all vm memory)With memory over-provisioning set to 1, when mgmt server starts VMs in parallel on one host, then the memory allocated on that kvm can be larger than the actual physcial memory of the kvm host. Fixed by checking free memory on host before starting Vm. Added test case to check memory usage on Host. Verified Vm deploy on Host with enough capacity and also without capacity * pr/847: Bug-ID: CLOUDSTACK-8880: calculate free memory on host before deploying Vm. free memory = total memory - (all vm memory) Signed-off-by: Rajani Karuturi <rajani.karuturi@accelerite.com>
2 parents 3f0fbf2 + 9a02190 commit ad7ed7a

File tree

3 files changed

+96
-3
lines changed

3 files changed

+96
-3
lines changed

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
268268
protected int _rngRateBytes = 2048;
269269
private File _qemuSocketsPath;
270270
private final String _qemuGuestAgentSocketName = "org.qemu.guest_agent.0";
271+
private long _totalMemory;
271272

272273
private final Map <String, String> _pifs = new HashMap<String, String>();
273274
private final Map<String, VmStats> _vmStats = new ConcurrentHashMap<String, VmStats>();
@@ -2453,6 +2454,7 @@ private Map<String, String> getVersionStrings() {
24532454
public StartupCommand[] initialize() {
24542455

24552456
final List<Object> info = getHostInfo();
2457+
_totalMemory = (Long)info.get(2);
24562458

24572459
final StartupRoutingCommand cmd =
24582460
new StartupRoutingCommand((Integer)info.get(0), (Long)info.get(1), (Long)info.get(2), (Long)info.get(4), (String)info.get(3), _hypervisorType,
@@ -3586,4 +3588,8 @@ public void restoreVMSnapshotMetadata(Domain dm, String vmName, List<Ternary<Str
35863588
}
35873589
}
35883590
}
3591+
3592+
public long getTotalMemory() {
3593+
return _totalMemory;
3594+
}
35893595
}

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStartCommandWrapper.java

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import org.apache.log4j.Logger;
2626
import org.libvirt.Connect;
27+
import org.libvirt.Domain;
2728
import org.libvirt.DomainInfo.DomainState;
2829
import org.libvirt.LibvirtException;
2930

@@ -60,6 +61,17 @@ public Answer execute(final StartCommand command, final LibvirtComputingResource
6061
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
6162
Connect conn = null;
6263
try {
64+
65+
vm = libvirtComputingResource.createVMFromSpec(vmSpec);
66+
conn = libvirtUtilitiesHelper.getConnectionByType(vm.getHvsType());
67+
68+
Long remainingMem = getFreeMemory(conn, libvirtComputingResource);
69+
if (remainingMem == null){
70+
return new StartAnswer(command, "failed to get free memory");
71+
} else if (remainingMem < vmSpec.getMinRam()) {
72+
return new StartAnswer(command, "Not enough memory on the host, remaining: " + remainingMem + ", asking: " + vmSpec.getMinRam());
73+
}
74+
6375
final NicTO[] nics = vmSpec.getNics();
6476

6577
for (final NicTO nic : nics) {
@@ -68,8 +80,6 @@ public Answer execute(final StartCommand command, final LibvirtComputingResource
6880
}
6981
}
7082

71-
vm = libvirtComputingResource.createVMFromSpec(vmSpec);
72-
conn = libvirtUtilitiesHelper.getConnectionByType(vm.getHvsType());
7383
libvirtComputingResource.createVbd(conn, vmSpec, vmName, vm);
7484

7585
if (!storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec)) {
@@ -150,4 +160,22 @@ public Answer execute(final StartCommand command, final LibvirtComputingResource
150160
}
151161
}
152162
}
153-
}
163+
164+
private Long getFreeMemory(final Connect conn, final LibvirtComputingResource libvirtComputingResource){
165+
try {
166+
long allocatedMem = 0;
167+
int[] ids = conn.listDomains();
168+
for(int id :ids) {
169+
Domain dm = conn.domainLookupByID(id);
170+
allocatedMem += dm.getMaxMemory() * 1024L;
171+
s_logger.debug("vm: " + dm.getName() + " mem: " + dm.getMaxMemory() * 1024L);
172+
}
173+
Long remainingMem = libvirtComputingResource.getTotalMemory() - allocatedMem;
174+
s_logger.debug("remaining mem" + remainingMem);
175+
return remainingMem;
176+
} catch (Exception e) {
177+
s_logger.debug("failed to get free memory", e);
178+
return null;
179+
}
180+
}
181+
}

plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4855,6 +4855,7 @@ public void testStartCommand() {
48554855

48564856
final NicTO nic = Mockito.mock(NicTO.class);
48574857
final NicTO[] nics = new NicTO[]{nic};
4858+
final int[] vms = new int[0];
48584859

48594860
final String vmName = "Test";
48604861
final String controlIp = "127.0.0.1";
@@ -4868,6 +4869,7 @@ public void testStartCommand() {
48684869
when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper);
48694870
try {
48704871
when(libvirtUtilitiesHelper.getConnectionByType(vmDef.getHvsType())).thenReturn(conn);
4872+
when(conn.listDomains()).thenReturn(vms);
48714873
doNothing().when(libvirtComputingResource).createVbd(conn, vmSpec, vmName, vmDef);
48724874
} catch (final LibvirtException e) {
48734875
fail(e.getMessage());
@@ -4927,6 +4929,7 @@ public void testStartCommandIsolationEc2() {
49274929

49284930
final NicTO nic = Mockito.mock(NicTO.class);
49294931
final NicTO[] nics = new NicTO[]{nic};
4932+
final int[] vms = new int[0];
49304933

49314934
final String vmName = "Test";
49324935
final String controlIp = "127.0.0.1";
@@ -4940,6 +4943,7 @@ public void testStartCommandIsolationEc2() {
49404943
when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper);
49414944
try {
49424945
when(libvirtUtilitiesHelper.getConnectionByType(vmDef.getHvsType())).thenReturn(conn);
4946+
when(conn.listDomains()).thenReturn(vms);
49434947
doNothing().when(libvirtComputingResource).createVbd(conn, vmSpec, vmName, vmDef);
49444948
} catch (final LibvirtException e) {
49454949
fail(e.getMessage());
@@ -4989,6 +4993,61 @@ public void testStartCommandIsolationEc2() {
49894993
}
49904994
}
49914995

4996+
@Test
4997+
public void testStartCommandHostMemory() {
4998+
final VirtualMachineTO vmSpec = Mockito.mock(VirtualMachineTO.class);
4999+
final com.cloud.host.Host host = Mockito.mock(com.cloud.host.Host.class);
5000+
final boolean executeInSequence = false;
5001+
5002+
final StartCommand command = new StartCommand(vmSpec, host, executeInSequence);
5003+
5004+
final KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class);
5005+
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class);
5006+
final Connect conn = Mockito.mock(Connect.class);
5007+
final LibvirtVMDef vmDef = Mockito.mock(LibvirtVMDef.class);
5008+
5009+
final NicTO nic = Mockito.mock(NicTO.class);
5010+
final NicTO[] nics = new NicTO[]{nic};
5011+
int vmId = 1;
5012+
final int[] vms = new int[]{vmId};
5013+
final Domain dm = Mockito.mock(Domain.class);
5014+
5015+
final String vmName = "Test";
5016+
5017+
when(libvirtComputingResource.getStoragePoolMgr()).thenReturn(storagePoolMgr);
5018+
when(vmSpec.getNics()).thenReturn(nics);
5019+
when(vmSpec.getType()).thenReturn(VirtualMachine.Type.User);
5020+
when(vmSpec.getName()).thenReturn(vmName);
5021+
when(vmSpec.getMaxRam()).thenReturn(512L);
5022+
when(libvirtComputingResource.createVMFromSpec(vmSpec)).thenReturn(vmDef);
5023+
5024+
when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper);
5025+
try {
5026+
when(libvirtUtilitiesHelper.getConnectionByType(vmDef.getHvsType())).thenReturn(conn);
5027+
when(conn.listDomains()).thenReturn(vms);
5028+
when(conn.domainLookupByID(vmId)).thenReturn(dm);
5029+
when(dm.getMaxMemory()).thenReturn(1024L);
5030+
when(dm.getName()).thenReturn(vmName);
5031+
when(libvirtComputingResource.getTotalMemory()).thenReturn(2048*1024L);
5032+
doNothing().when(libvirtComputingResource).createVbd(conn, vmSpec, vmName, vmDef);
5033+
} catch (final LibvirtException e) {
5034+
fail(e.getMessage());
5035+
} catch (final InternalErrorException e) {
5036+
fail(e.getMessage());
5037+
} catch (final URISyntaxException e) {
5038+
fail(e.getMessage());
5039+
}
5040+
5041+
when(storagePoolMgr.connectPhysicalDisksViaVmSpec(vmSpec)).thenReturn(true);
5042+
5043+
final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
5044+
assertNotNull(wrapper);
5045+
5046+
final Answer answer = wrapper.execute(command, libvirtComputingResource);
5047+
assertTrue(answer.getResult());
5048+
}
5049+
5050+
49925051
@Test
49935052
public void testUpdateHostPasswordCommand() {
49945053
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class);

0 commit comments

Comments
 (0)