mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +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
|
|
@ -83,6 +83,7 @@ PERSISTENT_XML = VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE
|
|||
USB_HOSTDEVS = "devices/hostdev[@mode='subsystem'][@type='usb']"
|
||||
PCI_HOSTDEVS = "devices/hostdev[@mode='subsystem'][@type='pci']"
|
||||
# what of the host a VM holds: host devices, and NICs that are host devices
|
||||
GUEST_AGENT_CHANNEL = "/domain/devices/channel[@type='unix']/target[@name='org.qemu.guest_agent.0']"
|
||||
HOST_DEVICES = "devices/hostdev | devices/interface[@type='hostdev'] | devices/interface/actual[@type='hostdev']"
|
||||
|
||||
# External snapshot names become part of overlay and memory file names.
|
||||
|
|
@ -695,9 +696,9 @@ class wvmInstance(wvmConnect):
|
|||
readonly = util.get_xml_path(xml, "/domain/os/loader/@readonly")
|
||||
return {"loader": loader, "type": loader_type, "readonly": readonly}
|
||||
|
||||
def get_vcpus(self):
|
||||
def get_vcpus(self, config=False):
|
||||
vcpus = OrderedDict()
|
||||
tree = etree.fromstring(self._XMLDesc(0))
|
||||
tree = etree.fromstring(self._XMLDesc(PERSISTENT_XML if config else 0))
|
||||
for vcpu in tree.xpath("/domain/vcpus/vcpu"):
|
||||
vcpu_id = vcpu.get("id")
|
||||
enabled = vcpu.get("enabled")
|
||||
|
|
@ -1597,7 +1598,8 @@ class wvmInstance(wvmConnect):
|
|||
return model.get("type")
|
||||
|
||||
def set_video_model(self, model):
|
||||
"""Changes only primary video card"""
|
||||
"""Changes only the primary video card, which stays the primary one;
|
||||
the old model's memory and head settings go with it."""
|
||||
xml = self._XMLDesc(PERSISTENT_XML)
|
||||
tree = etree.fromstring(xml)
|
||||
video_models = tree.xpath("/domain/devices/video/model")
|
||||
|
|
@ -1605,7 +1607,9 @@ class wvmInstance(wvmConnect):
|
|||
if video_model.get("primary") == "yes" or len(video_models) == 1:
|
||||
parent = video_model.getparent()
|
||||
parent.remove(video_model)
|
||||
etree.SubElement(parent, "model", type=model)
|
||||
new_model = etree.SubElement(parent, "model", type=model)
|
||||
if video_model.get("primary"):
|
||||
new_model.set("primary", video_model.get("primary"))
|
||||
self._defineXML(etree.tostring(tree).decode())
|
||||
return
|
||||
|
||||
|
|
@ -2923,23 +2927,23 @@ class wvmInstance(wvmConnect):
|
|||
self._defineXML(etree.tostring(tree).decode())
|
||||
|
||||
def add_guest_agent(self):
|
||||
channel_xml = """
|
||||
<channel type='unix'>
|
||||
<target type='virtio' name='org.qemu.guest_agent.0'/>
|
||||
</channel>
|
||||
"""
|
||||
self._attach_device(channel_xml)
|
||||
"""Adds the agent channel to the definitions that do not have it."""
|
||||
flags = 0
|
||||
for xml_flags, affect in self._definitions():
|
||||
if not etree.fromstring(self._XMLDesc(xml_flags)).xpath(GUEST_AGENT_CHANNEL):
|
||||
flags |= affect
|
||||
if flags:
|
||||
channel_xml = "<channel type='unix'><target type='virtio' name='org.qemu.guest_agent.0'/></channel>"
|
||||
self.instance.attachDeviceFlags(channel_xml, flags)
|
||||
|
||||
def remove_guest_agent(self):
|
||||
for xml_flags, affect in self._definitions():
|
||||
tree = etree.fromstring(self._XMLDesc(xml_flags))
|
||||
for target in tree.xpath(
|
||||
"/domain/devices/channel[@type='unix']/target[@name='org.qemu.guest_agent.0']"
|
||||
):
|
||||
for target in tree.xpath(GUEST_AGENT_CHANNEL):
|
||||
channel_xml = etree.tostring(target.getparent()).decode()
|
||||
self.instance.detachDeviceFlags(channel_xml, affect)
|
||||
|
||||
def get_guest_agent(self):
|
||||
def get_guest_agent(self, config=False):
|
||||
def _get_agent(doc):
|
||||
"""
|
||||
Return agent channel object if it is defined.
|
||||
|
|
@ -2952,7 +2956,7 @@ class wvmInstance(wvmConnect):
|
|||
return channel
|
||||
return None
|
||||
|
||||
return util.get_xml_path(self._XMLDesc(0), func=_get_agent)
|
||||
return util.get_xml_path(self._XMLDesc(PERSISTENT_XML if config else 0), func=_get_agent)
|
||||
|
||||
def set_user_password(self, user, crypted):
|
||||
"""Set a user's password in the running guest through its agent;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue