hardware: Check inventory of shared CPUs for 'mixed' policy

If using the 'mixed' CPU policy then, by design, the instance is
consuming both "shared" and "dedicated" host CPUs. However, we were only
checking the latter. Fix this.

Change-Id: Ic21c918736e7046ad32a2b8a3330496ce42950b0
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
Closes-Bug: #1898272
This commit is contained in:
Stephen Finucane
2020-10-05 15:59:10 +01:00
parent 9e1fe29d76
commit 82528c83ac
3 changed files with 40 additions and 10 deletions

View File

@@ -323,11 +323,8 @@ class NUMAServersTest(NUMAServersTestBase):
}
flavor_id = self._create_flavor(vcpu=4, extra_spec=extra_spec)
# FIXME(stephenfin): This is bug #1898272. In real life, this
# configuration will result in a libvirt traceback due to attempting to
# pin the single shared instance vCPU to an empty set
# self._run_build_test(flavor_id, end_status='ERROR')
self._run_build_test(flavor_id)
# There shouldn't be any hosts available to satisfy this request
self._run_build_test(flavor_id, end_status='ERROR')
def test_create_server_with_dedicated_policy_old_configuration(self):
"""Create a server using the legacy extra spec and configuration.

View File

@@ -3926,6 +3926,29 @@ class CPUPinningCellTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase):
mock_log.warning.call_args[0][0],
)
def test_get_pinning_mixed_policy_bug_1898272(self):
"""A host cell must have sufficient dedicated *and* shared CPUs when
using the mixed policy.
"""
host_pin = objects.NUMACell(
id=0,
cpuset=set(),
pcpuset=set(range(4)),
memory=4096,
memory_usage=0,
pinned_cpus=set(),
siblings=[{0, 2}, {1, 3}],
mempages=[],
)
inst_pin = objects.InstanceNUMACell(
cpuset={0},
pcpuset={1, 2, 3},
memory=2048,
cpu_policy=fields.CPUAllocationPolicy.MIXED,
)
inst_topo = hw._numa_fit_instance_cell(host_pin, inst_pin)
self.assertIsNone(inst_topo)
class CPUPinningTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase):
def test_host_numa_fit_instance_to_host_single_cell(self):

View File

@@ -1121,7 +1121,12 @@ def _numa_fit_instance_cell(
'cpuset_reserved': cpuset_reserved
})
return None
else:
if instance_cell.cpu_policy in (
fields.CPUAllocationPolicy.SHARED,
fields.CPUAllocationPolicy.MIXED,
None,
):
required_cpus = len(instance_cell.cpuset)
if required_cpus > len(host_cell.cpuset):
LOG.debug('Not enough host cell CPUs to fit instance cell; '
@@ -1135,7 +1140,7 @@ def _numa_fit_instance_cell(
fields.CPUAllocationPolicy.DEDICATED,
fields.CPUAllocationPolicy.MIXED,
):
LOG.debug('Pinning has been requested')
LOG.debug('Instance has requested pinned CPUs')
required_cpus = len(instance_cell.pcpuset) + cpuset_reserved
if required_cpus > host_cell.avail_pcpus:
LOG.debug('Not enough available CPUs to schedule instance. '
@@ -1166,9 +1171,14 @@ def _numa_fit_instance_cell(
LOG.debug('Failed to map instance cell CPUs to host cell CPUs')
return None
elif limits:
LOG.debug('No pinning requested, considering limitations on usable cpu'
' and memory')
if instance_cell.cpu_policy in (
fields.CPUAllocationPolicy.SHARED,
fields.CPUAllocationPolicy.MIXED,
None,
) and limits:
LOG.debug(
'Instance has requested shared CPUs; considering limitations '
'on usable CPU and memory.')
cpu_usage = host_cell.cpu_usage + len(instance_cell.cpuset)
cpu_limit = len(host_cell.cpuset) * limits.cpu_allocation_ratio
if cpu_usage > cpu_limit: