diff --git a/README.md b/README.md index f9ace2e1..96a311ab 100644 --- a/README.md +++ b/README.md @@ -534,6 +534,7 @@ A rollback leaves the clone on a detached HEAD at the restored commit; the updat - A VM that vanishes from its compute keeps its owners for `INSTANCE_OWNERSHIP_RETENTION_DAYS` (30) in case the same UUID comes back; superusers list and remove these records on the "Removed VMs" admin page. - The log rotates (10 MB × 5) in `data/webvirtcloud.log`. - A disk can be grown while its VM runs or is paused, not only when it is shut off. +- Enabling vCPU hot plug keeps the VM's current vCPU count (it enabled all of them up to the maximum). - A host's CPU graph shows the average since its previous point (normally 5 s) instead of a 1 s sample taken while a worker waits. - A VM's stats are polled every 5 s like the host graph, the first point as soon as the tab opens; each point is the average since the previous one, disk rates in MB/s (they were MiB/s labelled Mb/s); a counter the host does not report shows a gap instead of 0. - An ISO uploads to an SSH compute about 3.5 times faster (SFTP writes no longer wait for each 32 KiB); a failed write still fails the upload. diff --git a/instances/test_live_xml_effects.py b/instances/test_live_xml_effects.py index cf1b7b55..52e96fa1 100644 --- a/instances/test_live_xml_effects.py +++ b/instances/test_live_xml_effects.py @@ -278,3 +278,17 @@ class LiveXmlEffectsTestCase(SimpleTestCase): def test_edits_of_a_paused_vm(self): self.check(running=True, paused=True) + + def test_enabling_vcpu_hotplug_keeps_the_current_vcpus(self): + try: + dom, vm = self.vm(running=False) + vm.resize_cpu("2", "4") + vm.set_vcpu_hotplug(True) + after = self.persistent(dom) + self.assertEqual((after.findtext("vcpu"), first(after, "vcpu/@current")), ("4", "2")) + self.assertEqual(after.xpath("vcpus/vcpu/@enabled"), ["yes", "yes", "no", "no"]) + self.assertEqual(after.xpath("vcpus/vcpu/@hotpluggable"), ["no", "yes", "yes", "yes"]) + dom.create() + self.assertEqual(dom.vcpusFlags(libvirt.VIR_DOMAIN_AFFECT_LIVE), 2) + finally: + livetest.cleanup(self.conn) diff --git a/vrtManager/instance.py b/vrtManager/instance.py index 32f53373..8883c7d2 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -1105,8 +1105,9 @@ class wvmInstance(wvmConnect): self.instance.setVcpu(str(cpu_id), enabled) def set_vcpu_hotplug(self, status, vcpus_hotplug=0): - """vcpus_hotplug = 0 make all vpus hotpluggable""" - vcpus_hotplug = int(self.get_vcpu()) if vcpus_hotplug == 0 else vcpus_hotplug + """vcpus_hotplug: the vCPUs enabled at boot, 0 keeps the current ones; + libvirt adds the rest up to the maximum as disabled hotpluggable vCPUs""" + vcpus_hotplug = self.get_cur_vcpu() if vcpus_hotplug == 0 else vcpus_hotplug if self.get_status() == 5: # shutoff if status: xml = """ """ diff --git a/vrtManager/test_device_edits.py b/vrtManager/test_device_edits.py index 6bd15652..44512ad4 100644 --- a/vrtManager/test_device_edits.py +++ b/vrtManager/test_device_edits.py @@ -1,7 +1,8 @@ """Device edits of a VM: each definition is changed as it describes the device, every NIC type can be a boot device, posted values stay values, and definition changes go through _defineXML. An active VM's memory is resized -by balloon, a stopped one's in its definition.""" +by balloon, a stopped one's in its definition. Enabling vCPU hot plug keeps +the vCPUs enabled at boot.""" import unittest from unittest.mock import MagicMock @@ -65,6 +66,15 @@ class DetachDiskTestCase(unittest.TestCase): p.instance.detachDeviceFlags.assert_not_called() +class VcpuHotplugTestCase(unittest.TestCase): + def test_enabling_hotplug_keeps_the_current_vcpus_enabled(self): + p = proxy(active=False) + p.instance.info.return_value = [5] + p._XMLDesc = lambda flags: "4" + p.set_vcpu_hotplug(True) + self.assertEqual(defined(p).xpath("vcpus/vcpu/@enabled"), ["yes", "yes"]) + + class DeviceEditsTestCase(unittest.TestCase): def test_a_block_volume_is_attached_by_its_device_path(self): p = proxy(active=False)