Skip to content

Commit ee181da

Browse files
committed
Calculate memory_mb_max_unit based on instance's memory_mb
Previously the memory_mb_max_unit was relying on the overallMemoryUsage reported by the ESXi, which was wrong, because the host could still have a big VM with reserved memory, that was not consuming any RAM and thus not reflected in the memory usage. We are now looking for the instances spawned on that ESXi and subtract their configured memory_mb from the total RAM capacity of the host, resulting in a realistic memory_mb_max_unit. Change-Id: I72821c97d80f9f675dca943d65f94e36824d81b6
1 parent 0e9c005 commit ee181da

File tree

3 files changed

+60
-8
lines changed

3 files changed

+60
-8
lines changed

nova/tests/unit/virt/vmwareapi/test_driver_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,8 +2377,8 @@ def test_get_available_resource(self):
23772377
stats['supported_instances'])
23782378
memory_mbmax_unit = stats['stats']['memory_mb_max_unit']
23792379
vcpus_max_unit = stats['stats']['vcpus_max_unit']
2380-
# memory_mb_used = fake.HostSystem.overallMemoryUsage = 500
2381-
self.assertEqual(memory_mbmax_unit, 1024 - 500)
2380+
# memory_mb_used = fake.HostSystem.hardware.memorySize = 1024
2381+
self.assertEqual(memory_mbmax_unit, 1024)
23822382
# vcpus_max_unit = fake.HostSystem.summary.hardware.numCpuThreads
23832383
self.assertEqual(vcpus_max_unit, 16)
23842384

nova/virt/vmwareapi/driver.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,10 @@ def _get_cluster_stats(self, host_stats):
405405
# memory_mb_max_unit represents the free memory of the freest host
406406
# available in the cluster. Can be used by the scheduler to determine
407407
# if the cluster can accommodate a big VM.
408-
memory_mb_max_unit = 0
408+
# It's calculated by looking at the configured memoryMB of each instance
409+
# in that host, not taking into account the actual memory usage.
410+
memory_mb_max_unit = max(
411+
mem for mem in self._vmops.get_available_memory_per_host().values())
409412
# vcpus_max_unit represents the vCPUs of a physical node from the
410413
# cluster. It can be used to determine if a VM can be powered-on in
411414
# this cluster, by comparing its flavor.vcpus to this value.
@@ -414,11 +417,6 @@ def _get_cluster_stats(self, host_stats):
414417
# Skip the cluster node
415418
if nodename == self._nodename:
416419
continue
417-
memory_mb_free = (resources['memory_mb'] -
418-
resources['memory_mb_used'])
419-
if memory_mb_max_unit < memory_mb_free:
420-
memory_mb_max_unit = memory_mb_free
421-
422420
vcpus = resources['vcpus']
423421
if vcpus_max_unit < vcpus:
424422
vcpus_max_unit = vcpus

nova/virt/vmwareapi/vmops.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"""
1919
Class for VM tasks like spawn, snapshot, suspend, resume etc.
2020
"""
21+
import collections
2122

2223
import contextlib
2324
import copy
@@ -4808,3 +4809,56 @@ def check_can_live_migrate_source(self, instance):
48084809
raise exception.MigrationPreCheckError(
48094810
reason=("Found non-configdrive CD-ROM. "
48104811
"Can only migrate configdrive"))
4812+
4813+
def get_available_memory_per_host(self):
4814+
"""Retrieve per-host available RAM.
4815+
4816+
The value is calculated by subtracting the total configured
4817+
memory_mb of the instances residing on that host from the
4818+
total memory size of the host.
4819+
4820+
Returns a dict containing available RAM information per host.
4821+
{
4822+
"host-ref-value": 1024
4823+
}
4824+
"""
4825+
(host_mors, _) = vm_util.get_hosts_and_reservations_for_cluster(
4826+
self._session, self._cluster)
4827+
4828+
ram_per_host = {}
4829+
# initialize ram_per_host with the hosts in the expected state
4830+
# and their total memorySize.
4831+
result = self._session._call_method(vim_util,
4832+
"get_properties_for_a_collection_of_objects",
4833+
"HostSystem", host_mors,
4834+
["summary.runtime", "summary.hardware"])
4835+
with vutil.WithRetrieval(self._session.vim, result) as objects:
4836+
for obj in objects:
4837+
host_props = vutil.propset_dict(obj.propSet)
4838+
runtime_summary = host_props['summary.runtime']
4839+
if (runtime_summary.inMaintenanceMode or
4840+
runtime_summary.connectionState != "connected"):
4841+
continue
4842+
host_ref_value = vutil.get_moref_value(obj.obj)
4843+
hardware_summary = host_props.get("summary.hardware")
4844+
mem_size = getattr(hardware_summary, "memorySize", 0)
4845+
ram_per_host[host_ref_value] = mem_size // units.Mi
4846+
4847+
props = ['config.hardware.memoryMB', 'runtime.host']
4848+
vms = self._list_instances_in_cluster(additional_properties=props)
4849+
4850+
for (vm_uuid, vm_props) in vms:
4851+
host_obj = vm_props.get('runtime.host')
4852+
if not host_obj:
4853+
continue
4854+
host_ref_value = vutil.get_moref_value(host_obj)
4855+
if host_ref_value not in ram_per_host:
4856+
continue
4857+
4858+
vm_mb = vm_props.get('config.hardware.memoryMB', 0)
4859+
4860+
# make sure the minimum available memory >= 0
4861+
ram_per_host[host_ref_value] = \
4862+
max(ram_per_host[host_ref_value] - vm_mb, 0)
4863+
4864+
return ram_per_host

0 commit comments

Comments
 (0)