Merge "libvirt: verify cpu bw policy capability for host"
This commit is contained in:
commit
b3879bd199
@ -2021,3 +2021,7 @@ class RequestSpecNotFound(NotFound):
|
||||
|
||||
class NMINotSupported(Invalid):
|
||||
msg_fmt = _("Injecting NMI is not supported")
|
||||
|
||||
|
||||
class UnsupportedHostCPUControlPolicy(Invalid):
|
||||
msg_fmt = _("Requested CPU control policy not supported by host")
|
||||
|
@ -1394,7 +1394,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
self.assertIsInstance(cfg.idmaps[1],
|
||||
vconfig.LibvirtConfigGuestGIDMap)
|
||||
|
||||
def test_get_guest_config_numa_host_instance_fits(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_numa_host_instance_fits(self, is_able):
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
|
||||
flavor = objects.Flavor(memory_mb=1, vcpus=2, root_gb=496,
|
||||
@ -1424,7 +1426,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(0, len(cfg.cputune.vcpupin))
|
||||
self.assertIsNone(cfg.cpu.numa)
|
||||
|
||||
def test_get_guest_config_numa_host_instance_no_fit(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_numa_host_instance_no_fit(self, is_able):
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
|
||||
flavor = objects.Flavor(memory_mb=4096, vcpus=4, root_gb=496,
|
||||
@ -1523,7 +1527,10 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
host_topology, inst_topology, numa_tune)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_get_guest_config_numa_host_instance_pci_no_numa_info(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_numa_host_instance_pci_no_numa_info(
|
||||
self, is_able):
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
|
||||
flavor = objects.Flavor(memory_mb=1, vcpus=2, root_gb=496,
|
||||
@ -1569,7 +1576,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(0, len(cfg.cputune.vcpupin))
|
||||
self.assertIsNone(cfg.cpu.numa)
|
||||
|
||||
def test_get_guest_config_numa_host_instance_2pci_no_fit(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_numa_host_instance_2pci_no_fit(self, is_able):
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
|
||||
flavor = objects.Flavor(memory_mb=4096, vcpus=4, root_gb=496,
|
||||
@ -1764,7 +1773,10 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
exception.NUMATopologyUnsupported,
|
||||
2048)
|
||||
|
||||
def test_get_guest_config_numa_host_instance_fit_w_cpu_pinset(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_numa_host_instance_fit_w_cpu_pinset(
|
||||
self, is_able):
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
|
||||
flavor = objects.Flavor(memory_mb=1024, vcpus=2, root_gb=496,
|
||||
@ -1802,7 +1814,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(0, len(cfg.cputune.vcpupin))
|
||||
self.assertIsNone(cfg.cpu.numa)
|
||||
|
||||
def test_get_guest_config_non_numa_host_instance_topo(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_non_numa_host_instance_topo(self, is_able):
|
||||
instance_topology = objects.InstanceNUMATopology(
|
||||
cells=[objects.InstanceNUMACell(
|
||||
id=0, cpuset=set([0]), memory=1024),
|
||||
@ -1848,7 +1862,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(instance_cell.memory * units.Ki,
|
||||
numa_cfg_cell.memory)
|
||||
|
||||
def test_get_guest_config_numa_host_instance_topo(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_numa_host_instance_topo(self, is_able):
|
||||
instance_topology = objects.InstanceNUMATopology(
|
||||
cells=[objects.InstanceNUMACell(
|
||||
id=1, cpuset=set([0, 1]), memory=1024, pagesize=None),
|
||||
@ -3906,7 +3922,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
[],
|
||||
image_meta, disk_info)
|
||||
|
||||
def test_guest_cpu_shares_with_multi_vcpu(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_guest_cpu_shares_with_multi_vcpu(self, is_able):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
@ -3924,7 +3942,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
|
||||
self.assertEqual(4096, cfg.cputune.shares)
|
||||
|
||||
def test_get_guest_config_with_cpu_quota(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_with_cpu_quota(self, is_able):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
@ -3944,7 +3964,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
self.assertEqual(10000, cfg.cputune.shares)
|
||||
self.assertEqual(20000, cfg.cputune.period)
|
||||
|
||||
def test_get_guest_config_with_bogus_cpu_quota(self):
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=True)
|
||||
def test_get_guest_config_with_bogus_cpu_quota(self, is_able):
|
||||
self.flags(virt_type='kvm', group='libvirt')
|
||||
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
@ -3962,6 +3984,17 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
drvr._get_guest_config,
|
||||
instance_ref, [], image_meta, disk_info)
|
||||
|
||||
@mock.patch.object(
|
||||
host.Host, "is_cpu_control_policy_capable", return_value=False)
|
||||
def test_get_update_guest_cputune(self, is_able):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
instance_ref.flavor.extra_specs = {'quota:cpu_shares': '10000',
|
||||
'quota:cpu_period': '20000'}
|
||||
self.assertRaises(
|
||||
exception.UnsupportedHostCPUControlPolicy,
|
||||
drvr._update_guest_cputune, {}, instance_ref.flavor, "kvm")
|
||||
|
||||
def _test_get_guest_config_sysinfo_serial(self, expected_serial):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
|
||||
|
@ -874,6 +874,24 @@ Active: 8381604 kB
|
||||
self.host.compare_cpu("cpuxml")
|
||||
mock_compareCPU.assert_called_once_with("cpuxml", 0)
|
||||
|
||||
def test_is_cpu_control_policy_capable_ok(self):
|
||||
m = mock.mock_open(
|
||||
read_data="""cg /cgroup/cpu,cpuacct cg opt1,cpu,opt3 0 0
|
||||
cg /cgroup/memory cg opt1,opt2 0 0
|
||||
""")
|
||||
with mock.patch(
|
||||
"six.moves.builtins.open", m, create=True):
|
||||
self.assertTrue(self.host.is_cpu_control_policy_capable())
|
||||
|
||||
def test_is_cpu_control_policy_capable_ko(self):
|
||||
m = mock.mock_open(
|
||||
read_data="""cg /cgroup/cpu,cpuacct cg opt1,opt2,opt3 0 0
|
||||
cg /cgroup/memory cg opt1,opt2 0 0
|
||||
""")
|
||||
with mock.patch(
|
||||
"six.moves.builtins.open", m, create=True):
|
||||
self.assertFalse(self.host.is_cpu_control_policy_capable())
|
||||
|
||||
|
||||
class DomainJobInfoTestCase(test.NoDBTestCase):
|
||||
|
||||
|
@ -3548,19 +3548,29 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
return id_maps
|
||||
|
||||
def _update_guest_cputune(self, guest, flavor, virt_type):
|
||||
if virt_type in ('lxc', 'kvm', 'qemu'):
|
||||
if guest.cputune is None:
|
||||
guest.cputune = vconfig.LibvirtConfigGuestCPUTune()
|
||||
is_able = self._host.is_cpu_control_policy_capable()
|
||||
|
||||
cputuning = ['shares', 'period', 'quota']
|
||||
wants_cputune = any([k for k in cputuning
|
||||
if "quota:cpu_" + k in flavor.extra_specs.keys()])
|
||||
|
||||
if wants_cputune and not is_able:
|
||||
raise exception.UnsupportedHostCPUControlPolicy()
|
||||
|
||||
if not is_able or virt_type not in ('lxc', 'kvm', 'qemu'):
|
||||
return
|
||||
|
||||
if guest.cputune is None:
|
||||
guest.cputune = vconfig.LibvirtConfigGuestCPUTune()
|
||||
# Setting the default cpu.shares value to be a value
|
||||
# dependent on the number of vcpus
|
||||
guest.cputune.shares = 1024 * guest.vcpus
|
||||
guest.cputune.shares = 1024 * guest.vcpus
|
||||
|
||||
cputuning = ['shares', 'period', 'quota']
|
||||
for name in cputuning:
|
||||
key = "quota:cpu_" + name
|
||||
if key in flavor.extra_specs:
|
||||
setattr(guest.cputune, name,
|
||||
int(flavor.extra_specs[key]))
|
||||
for name in cputuning:
|
||||
key = "quota:cpu_" + name
|
||||
if key in flavor.extra_specs:
|
||||
setattr(guest.cputune, name,
|
||||
int(flavor.extra_specs[key]))
|
||||
|
||||
def _get_cpu_numa_config_from_instance(self, instance_numa_topology,
|
||||
wants_hugepages):
|
||||
|
@ -995,3 +995,17 @@ class Host(object):
|
||||
def compare_cpu(self, xmlDesc, flags=0):
|
||||
"""Compares the given CPU description with the host CPU."""
|
||||
return self.get_connection().compareCPU(xmlDesc, flags)
|
||||
|
||||
def is_cpu_control_policy_capable(self):
|
||||
"""Returns whether kernel configuration CGROUP_SCHED is enabled
|
||||
|
||||
CONFIG_CGROUP_SCHED may be disabled in some kernel configs to
|
||||
improve scheduler latency.
|
||||
"""
|
||||
with open("/proc/self/mounts", "r") as fd:
|
||||
for line in fd.readlines():
|
||||
# mount options and split options
|
||||
bits = line.split()[3].split(",")
|
||||
if "cpu" in bits:
|
||||
return True
|
||||
return False
|
||||
|
Loading…
Reference in New Issue
Block a user