mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 11:46:49 +00:00
feat(instances): a VM's options in one list, each saved when it can be
Settings > Options was four forms under bold sentences, most of them disabled while the VM ran. The owner chose this layout from three rendered options: one list, each row a setting with its description on the left and its control on the right: VM details (title, description), Template, primary video model, QEMU guest agent. vCPU hot plug moved to Resize > CPU, next to the vCPU counts. Codex reviewed the four forms; these are fixed: - Title, description and the video model are saved while the VM runs: they are in the persistent definition, used at the next start. - The template flag has its own form and view, set_template, for superusers and staff, and only for a shut-off VM: a running VM made a template left the quota while it kept running. Turning a template back into a VM checks the quota there, and each change is audited. The title form no longer touches the flag. - A new video model stays the primary one; the old model's memory and head settings, which are its own, go with it. - The agent and vCPU hot plug forms show the persistent definition; they showed the running VM's, so a pending change looked undone. - Enabling the guest agent adds its channel only where it is missing: saving Enabled again failed, and a channel pending the next start kept a running VM from getting one. - The agent line tells a VM that is not running, one without a channel, and a connected or not connected agent apart.
This commit is contained in:
parent
46188d3230
commit
a993c12db0
13 changed files with 272 additions and 172 deletions
|
|
@ -116,6 +116,24 @@ class DeviceEditsTestCase(unittest.TestCase):
|
|||
inbound = defined(p).find("devices/interface[@type='network']/bandwidth/inbound")
|
||||
self.assertEqual(inbound.attrib, {"average": "10", "peak": "20", "burst": "30", "floor": "4"})
|
||||
|
||||
def test_a_new_video_model_stays_the_primary_one(self):
|
||||
# the old model's memory sizes are its own: they go
|
||||
p = proxy()
|
||||
p._XMLDesc = lambda flags: PERSISTENT.replace("<model type='vga'/>", "<model type='vga' vram='16384' primary='yes'/>")
|
||||
p.set_video_model("virtio")
|
||||
self.assertEqual(defined(p).find("devices/video/model").attrib, {"type": "virtio", "primary": "yes"})
|
||||
|
||||
def test_the_agent_channel_and_vcpu_hot_plug_are_read_from_either_definition(self):
|
||||
p = proxy()
|
||||
pending = ("<channel type='unix'><target type='virtio' name='org.qemu.guest_agent.0'/></channel>"
|
||||
"<video>")
|
||||
vcpus = "<vcpus><vcpu id='0' enabled='yes' hotpluggable='no'/><vcpu id='1' enabled='no' hotpluggable='yes'/></vcpus>"
|
||||
p._XMLDesc = lambda flags: (PERSISTENT.replace("<video>", pending).replace("<devices>", vcpus + "<devices>")
|
||||
if flags == PERSISTENT_XML else LIVE)
|
||||
self.assertEqual((p.get_guest_agent(), p.get_vcpus()), (None, {}))
|
||||
self.assertIsNotNone(p.get_guest_agent(config=True))
|
||||
self.assertEqual([v["hotpluggable"] for v in p.get_vcpus(config=True).values()], ["no", "yes"])
|
||||
|
||||
def test_cpu_title_and_description_are_read_from_either_definition(self):
|
||||
p = proxy()
|
||||
self.assertEqual((p.get_vcpu(), p.get_cur_vcpu(), p.get_title(), p.get_description()), (1, 1, "", ""))
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@ class DeviceEditsByStateTestCase(unittest.TestCase):
|
|||
vm.instance = MagicMock()
|
||||
vm.instance.isActive.return_value = active
|
||||
vm.get_status = MagicMock(return_value=state)
|
||||
vm._XMLDesc = MagicMock(return_value=AGENT_DOMAIN)
|
||||
# an agent channel is added where there is none, removed where there is one
|
||||
vm._XMLDesc = MagicMock(return_value=DOMAIN if name == "add_guest_agent" else AGENT_DOMAIN)
|
||||
edit(vm)
|
||||
result[name] = [names[c.args[1]] for c in getattr(vm.instance, method).call_args_list]
|
||||
return result
|
||||
|
|
@ -119,11 +120,25 @@ class DeviceEditsByStateTestCase(unittest.TestCase):
|
|||
vm = wvmInstance.__new__(wvmInstance)
|
||||
vm.instance = MagicMock()
|
||||
vm.instance.isActive.return_value = True
|
||||
vm._XMLDesc = MagicMock(return_value=DOMAIN)
|
||||
vm.instance.attachDeviceFlags.side_effect = libvirtError("target sda already exists")
|
||||
with self.assertRaises(libvirtError):
|
||||
self.EDITS[name][1](vm)
|
||||
vm.instance.attachDeviceFlags.assert_called_once()
|
||||
|
||||
def test_an_agent_channel_is_added_only_where_it_is_missing(self):
|
||||
from libvirt import VIR_DOMAIN_AFFECT_CONFIG, VIR_DOMAIN_AFFECT_LIVE
|
||||
|
||||
for live, persistent, affected in ((AGENT_DOMAIN, AGENT_DOMAIN, []),
|
||||
(DOMAIN, AGENT_DOMAIN, [VIR_DOMAIN_AFFECT_LIVE]),
|
||||
(AGENT_DOMAIN, DOMAIN, [VIR_DOMAIN_AFFECT_CONFIG])):
|
||||
with self.subTest(affected=affected):
|
||||
vm = wvmInstance.__new__(wvmInstance)
|
||||
vm.instance = MagicMock(**{"isActive.return_value": True})
|
||||
vm._XMLDesc = lambda flags, live=live, persistent=persistent: persistent if flags == PERSISTENT_XML else live
|
||||
vm.add_guest_agent()
|
||||
self.assertEqual([c.args[1] for c in vm.instance.attachDeviceFlags.call_args_list], affected)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue