1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
Commit graph

197 commits

Author SHA1 Message Date
catborise
f63c1ebe32 fix(instances): a VM shut down after its Migrate tab opened moves offline
The Migrate tab shows a running VM's live migration switch, on by
default. A VM shut down after the tab opened, as one is to move it shut
off, was then refused: "A shut-off VM cannot be migrated live". A
shut-off VM now moves offline whatever the request says about live, as
the tab tells for a shut-off VM; the tuning options are for a running VM
only, as before. An offline request for a running or paused VM is still
refused.
2026-11-01 18:29:57 +03:00
catborise
dbc7e688ac feat(instances): a shut-off VM with a TPM migrates with its TPM state
A shut-off VM with TPM state, as every Windows 11 VM, was refused for
migration: the state is a file of the source host, and an offline move
would start it there with a new TPM. Such a VM now migrates as a shut-off
VM with disks to copy does: its UEFI variables are copied, it is started
paused, its CPUs never run, migrates live, which carries the TPM state,
and is shut off on the destination. A shut-off VM with a saved state is
refused before any of that, for every way it moves: started paused, it
would resume and then lose the saved memory.

The clone tab says that a clone gets a new, empty TPM, and the destroy
page that the TPM state goes with the VM.
2026-11-01 18:29:53 +03:00
catborise
e35342bff1 feat(instances): a VM's TPM 2.0 is switched on and off on its Options tab
A VM made without a TPM, a Windows 10 to be upgraded to Windows 11, had
no way to get one but the XML editor. The Options tab has a TPM 2.0
switch, as the RNG one: it adds an emulated TPM of the host's model to
the definition for the next start, or removes it. Its state stays on the
host until the VM is undefined, so a TPM added again has it back. A TPM
the switch did not make (passthrough, 1.2, encrypted, with its own state
path) is left to the XML editor, and a host without swtpm says so.
2026-11-01 17:10:26 +03:00
catborise
2a05576e18 feat(instances): a CD-ROM is added on the bus chosen, with its ISO
A running VM got its new CD-ROM on SCSI, the one bus the panel could plug
in then, and Windows does not see a virtio-scsi drive before the driver
on that ISO is installed. Add CD-ROM is now a dialog that chooses the bus
and the ISO: a running VM takes USB, first, which every guest sees and
which hot-plugs, or SCSI; a shut-off one SATA (IDE on pc), SCSI or USB.
libvirt has no empty USB drive, so a USB CD-ROM takes its ISO when it is
added and is detached instead of ejected, also while the VM runs.

A USB CD-ROM is a CD drive on QEMU's usb-bot only. Where QEMU has none
(RHEL 9), libvirt took usb-storage, which shows the guest a hard disk
that Windows does not read; the drive now asks for usb-bot, and such a
host refuses it with libvirt's message.
2026-11-01 16:27:39 +03:00
catborise
95562544eb feat(instances): Add PCIe slots for a VM that has none free
An existing q35 VM whose PCIe root ports are all used takes no new
virtio disk or network device while it runs, and the only way to give
it more was editing its XML.

The Disks tab of a PCIe machine now counts its slots, "PCIe slots: 0
free of 7", in red when none is free, with what its next start will
have when that differs, and Add PCIe slots adds four root ports to its
persistent definition: libvirt numbers and places them, and a running
VM gets them at its next start. The no-slot advice of Add disk and Add
network device points at it.
2026-10-31 20:44:24 +03:00
catborise
2e17661390 fix(instances): a network device keeps its source unless another is chosen
The Edit dialog of a VM's network device selected the listed network
or interface whose name matched the device's source, and the first one
when none did: saving only a new model moved a macvtap device or a
bridge the host's lists did not show onto the first network, a bridge
named like a network became that network, and a macvtap device chosen
again lost its mode.

The dialog now offers the device's own source first, "<name>, as it
is", and posts nothing for it; the view passes no source and the
device's source element is left as it is. Choosing another source
changes it as before.
2026-10-31 18:10:05 +03:00
catborise
a408cfdb2b feat(instances): the Migrate tab marks hosts it cannot use and files in the way
The Migrate tab offered every other host alike, and its plan showed
neither a file of the same name in a destination pool nor the disks of
the VM's next start, which the job then refused. Now:

- When the tab opens, the hosts are checked first: one that cannot be
  reached, or the VM's own host under another record (the same libvirt
  host UUID), is shown with why and cannot be chosen, and the disks of
  the first one left are checked. The job refuses the VM's own host
  under another name too.
- A pool of the destination that has a file of a disk's name is shown
  but cannot be chosen for it; a disk no pool can take refuses the form.
- The next start's file disks the migration does not carry are listed;
  one not on storage both hosts share refuses the form, as the job does.
2026-10-31 01:34:44 +03:00
catborise
54a1943e26 fix(instances): a VM's destruction checks its files on every host first
Destroying a VM with its disk files forced it off first and then
worked out which files to delete, so a check that failed left the VM
stopped, and only this host's VMs and volumes were checked: a file on
shared storage that a VM on another host uses was deleted.

The files are now worked out before the VM is stopped: the disks it
runs with and those of its next start, as before with their snapshot
files and seed. A file a VM or volume of another of the panel's hosts
uses at the same path (shared storage is mounted at one path on every
host, as migration needs) is kept like one used here; another record
of the VM's own host is skipped, as there the VM itself uses them. A
host that cannot be read stops the destruction with its name, before
anything is stopped or deleted.
2026-10-31 01:08:42 +03:00
catborise
6dc2e5851b fix(instances): the quota counts queued clones and pending values
A user's quota counted each VM's running vCPUs, memory and disks, so a
larger value set for the VM's next start was not counted, and a clone
counted only once its VM was recorded, so a user could queue clones
past the quota. Now:

- Each VM counts the larger of its running and its next-start values.
- A clone job counts as one VM with the source's persistent vCPUs,
  memory and disk size, which its plan stores, from its admission until
  its VM is recorded; a failed, cancelled or resolved job no longer
  counts. The clone's VM and its owner are recorded in one transaction,
  so the quota counts either the job or the VM, never neither.
- The quota reads each VM's definition once (cached_reads).
2026-10-31 00:51:31 +03:00
catborise
5e93920d78 feat(instances): a VM's stats in one grid, its logs a switch away
The Stats tab stacked one large card per chart, so a VM with a few
devices made a long page, and its "Real Time" and "Logs" sub-tabs were
shown to every user although only a superuser may read the logs. The
owner chose the layout from rendered options: a state line, CPU and
memory side by side, one chart per NIC and disk below, each with its
latest reading next to its title, and a small Graphs/Logs switch for
superusers.

Codex reviewed the tab; this is fixed:

- Memory is shown in MiB (it was labelled MB), and its axis grows to
  the RSS when the RSS passes the balloon size instead of clipping it.
- The CPU reading says it is of the host's CPUs.
- A NIC is titled by its MAC, not an invented "eth0", and its readings
  are matched to its chart by the MAC: they were matched by position, so
  removing a NIC while the page was open moved the next one's readings
  into its chart.
- A VM that is not running says nothing is measured.
- The logs load whenever the Logs view is shown, by keyboard too; an
  empty answer says "None" and a failed one says so, instead of an
  empty table. The tab shows the latest 50 rows, with a link to all of
  the VM's rows on the Logs page.
- The VM's header shows memory in MiB; it said MB.
2026-10-30 23:41:17 +03:00
catborise
b72e9b1442 feat(instances): a VM's destruction says what goes, and keeps what a kept file needs
The Destroy tab was a sub-tab with one sentence and a link; its
confirmation page said only "This action is irreversible!" over a
"Remove Instance's data" switch. The tab now shows the state and
"Review destruction". The owner chose the confirmation layout from
three rendered options: the VM and its host, that its definition,
saved state and snapshot records go and that a running VM is forced
off, two plans for the files (delete the disk files, or keep them), the
VM's disks, what is always kept, the NVRAM choice, and Cancel.

Codex reviewed destroying; this is fixed:

- A disk file that cannot be deleted keeps the files below it, which
  it needs: they were deleted after it, leaving it broken. The files
  are deleted overlays first (split_disk_paths_by_use orders them by
  how many files each grows from), and if the files a kept one needs
  cannot be read, none of the rest goes. A message names each file
  kept so, and a failed deletion says the VM is removed.
2026-10-30 22:19:31 +03:00
catborise
7fc55537e5 feat(instances): external snapshots first, internal ones a fallback
The Snapshots tab had three sub-tabs: internal, external and the
lists, with the two kinds side by side as equals. The owner set the
direction: external snapshots are the way; internal ones pause the VM
while its memory is saved and can take long, so they stay only as a
fallback for a VM that cannot take an external one.

The tab now has the external snapshot form on top, its name and
description on one line, with its memory and freeze options; the
internal snapshot under a folded "fallback" line with its warning; and
one list of all snapshots, newest first, each on one line with its
name, description, kind and date, and Revert and Delete.

Codex reviewed snapshots end to end; these are fixed:

- The pause and memory lines follow the VM's state and the kind.
- An internal snapshot is reverted to on a shut-off VM only, on the
  server too; the tab alone held that rule.
- A paused VM's revert says it comes back paused, not that it starts.
- An external snapshot waits, with the reason, while snapshots newer
  than the one reverted to exist; the server refused it unexplained.
- Deleting an external snapshot says its files are merged with the
  disks; "into the next one" was wrong for the last one.
- The description has no 45-character limit only the browser kept.
- Freezing is not shown ticked where it cannot be offered, and
  unticking memory gives back the earlier freeze choice.
- Internal create, revert and delete refuse a saved state or a running
  disk job, as external ones do.
2026-10-30 21:40:00 +03:00
catborise
f8e30d7668 feat(instances): a VM's resize tab as a ledger, its vCPU changes kept
The Resize tab's CPU, Memory and Disk panes were horizontal forms with
bold host figures. The owner chose the ledger layout from three
rendered options: each section with its heading, the VM's figures and
the host's on the left, its fields on the right, and one line on what
applies now and what at the next start.

Codex reviewed resizing end to end; these are fixed:

- A vCPU turned on or off while the VM runs is kept at its next start:
  libvirt was asked without flags, which changes the running VM only.
- A paused VM offers to turn vCPUs on only: turning one off needs the
  guest, which does not run.
- A smaller disk size is refused, and so is the rest of the form,
  before anything grows; it was skipped without a word.
- vCPUs and memory below 1 are refused.
- The memory fields are numbers filled with the VM's values: the
  "Custom value" box, its script and the preset list are gone; an empty
  custom field silently used the preset.
- Units and words: MiB, not MB; a disk's field is its new size, with
  its size now above it; the messages say what the VM gets.
2026-10-30 18:16:11 +03:00
catborise
1150b941be feat(instances): a VM's RNG device and crash action in its options
Two settings the owner chose to add to Settings > Options after the
page's review with Codex. Both change the persistent definition, so
they are saved while the VM runs and used from its next start.

- Random number generator: a switch for a virtio RNG device fed from
  the host's /dev/urandom, so a new VM does not wait for entropy at
  boot. Another RNG device, or the panel's with a rate or driver, is
  shown as the VM's own and left to the XML editor.
- When the guest crashes: Restart or Stop (on_crash restart or
  destroy); libvirt's default, Stop, when the definition has none.
  Stop keeps a VM that crashes again and again down for a look. Any
  other action is shown and left to the XML editor.
2026-10-30 16:20:32 +03:00
catborise
a993c12db0 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.
2026-10-30 16:03:43 +03:00
catborise
400ba1614f feat(instances): a VM's clone form in device cards, with fixes to what it clones
Settings > Clone was a horizontal form with unlabelled checkboxes. The
owner chose this layout from three rendered options: the clone's name
on top, a "Network" card with a new MAC address per NIC, a "Storage"
card with a new volume name per disk, then the optional title and
description and a footer with Clone.

Codex reviewed cloning end to end; these are fixed:

- Every NIC of the clone gets a new random MAC when the form opens.
  Only the first did, so a VM with two NICs gave its clone the second
  NIC's MAC. Guess MAC is offered for the first NIC only: a name's DHCP
  host entry holds one address.
- A VM without a NIC can be cloned: the first NIC's MAC was required.
- The disk name script uses the persistent disks, as the form does; a
  disk added pending the next start kept the source's volume name.
- A running or paused VM is not cloned while a copied disk changes at
  the next start: the backup copies the running disk, so the clone
  would get the old contents under the new definition.
- A derived volume name that does not start with the source's name now
  starts with the clone's name and the disk's device, so a second clone
  or a second disk does not take the same name.
- Guess for the clone name says when the DHCP file has no free name; it
  stopped with a script error.
- The qcow2 metadata preallocation box shows only for a shut-off VM: a
  live clone's backup ignores it.

Other users no longer get hidden MAC and disk inputs or the scripts that
filled them: the server derives those values and ignored the posted ones.
2026-10-30 14:55:57 +03:00
catborise
301b73155d feat(instances): a VM's console settings in two cards, with a password action
Settings > Console was one horizontal form, and on a running VM its
Update button was disabled. The owner chose this layout from three
rendered options: the console type on top, then a "VNC connection" card
(listen address, keymap) and a "VNC password" card.

- The password is changed by an action: keep it, generate a new one,
  set a new one or remove it. This replaces the Generate and Clear
  boxes and their precedence, and an emptied field no longer removes
  the password silently. The pane says whether a password is set; the
  form no longer carries the password itself.
- A VNC password takes at most 8 bytes: libvirt refuses a longer one
  ("VNC password is 9 characters long, only 8 permitted"). Generate and
  a new VM's random password now make 8 characters; they made 12, which
  libvirt 11 refuses. A set password keeps its spaces.
- Every check is in the form, so a refused save changes nothing; before,
  a refused password removal still saved the other settings.
- The settings can be saved while the VM runs: they are in the
  persistent definition. A line says the running console keeps its
  settings until the VM is shut down and started.
- The console type shown and compared is the persistent one; it was the
  running VM's, so a pending switch to Serial showed VNC and a later
  save could switch again.
- While the saved type is Serial, the VNC settings are not shown or
  taken; choosing Serial ignores the posted VNC settings.
2026-10-30 14:55:57 +03:00
catborise
20cfc25367 feat(instances): a VM's boot settings as switches and its boot order as one list
The Boot pane shows Autostart and the boot menu as switches that save on
change, and the boot order as one list of the VM's disks, CD-ROM drives
and NICs: the devices in the order first, checked and numbered, the
others below. Up and Down move the checked devices; Apply order saves.

- The boot menu can be changed while the VM runs: it is in the
  persistent definition, so it applies at the next start, as the boot
  order does.
- The boot order editor no longer needs the boot menu enabled.
- A VM that boots by device type (<os><boot dev='hd'/>) names those
  types; checking devices replaces that order.
- An order is refused while a device the list does not show (a host
  device, a floppy) has a boot place, so Apply does not drop it; the
  message points to the XML editor.
- An empty order is refused with a message instead of being ignored.
- get_bootorder gives a NIC's full MAC as its target.
- The unused jQuery multiselect plugin is removed.
2026-10-30 14:55:57 +03:00
catborise
a8f445d580 feat(instances): a VM's network devices as cards, each with its QoS limits
Settings > Network was a table whose fields were read-only inputs cut
off at phone width, an unlabelled "+", three icon buttons per NIC and
a separate QoS table keyed by MAC. The owner chose card layout from
three rendered options, with the QoS limits folding out like the
device details:

- A card per NIC: a VM's only NIC spans the row, two or more sit side
  by side from md. Each has its name and target, the link state as a
  switch, its source and IPv4 addresses, and "Device details"
  (type, MAC, model, NWFilter, IPv6) in a <details>.
- "QoS limits" in a second <details>, its summary naming the limited
  directions: a form per inbound or outbound limit, with Save and
  Delete limit, and the units.
- Labelled Edit, Add QoS and Delete in the card footer; "Add network
  device" by the heading. The edit and add-QoS dialogs are titled and
  labelled, and the edit dialog's fields have labels.

The limits come from each NIC of the persistent definition, so the QoS
table, Instance.config_qos and wvmInstance.get_all_qos are removed.
2026-10-30 14:55:57 +03:00
catborise
7f8e5cd618 feat(instances): move a VM's disk to another storage pool of its host
The Disks tab has a Move button for each disk: it opens a dialog to
choose another storage pool of the same host, and the move runs as a job.

- Running or paused VM: libvirt copies the disk with a block job
  (TRANSIENT_JOB, as the VM is persistent) into a file it creates in the
  pool, then pivots. The pivot names the copy in both the running and
  the next start's definition.
- Shut-off VM: the volume is copied into the pool and the copy named in
  the definition.

The source file goes then, unless a VM or volume of any compute uses it
(shared storage holds it for every host that mounts it), a compute
cannot be read, or the delete fails: the job lists such a file under
"Left behind", and the move stands.

A disk moves when:
- the VM is defined and running, paused or shut off, without snapshots,
  a saved state or a block job;
- the disk is a writable, unshared, unencrypted raw or qcow2 file of a
  storage pool, without a backing file, and the same file in both
  definitions;
- the pool keeps disk files, is another directory, and has no file of
  that name (libvirt would write into it).
Otherwise it is refused with the reason before anything changes.

The job claims the VM and the file's name in both pools. A cancel aborts
the block copy, and ends the job cancelled once the VM is back on its
file. A failed move deletes the copy it made, unless a definition names
it (a lost reply after the pivot); a file there before the copy began is
never deleted. Recovery after a stopped worker
ends a copy left mirroring, matched by its destination, and reads the
outcome from the definitions.

Superusers only, like the other disk edits.
2026-10-29 21:30:26 +03:00
catborise
51d24fce30 feat(instances): migrate a VM with its disks copied into pools of the destination
A migration needed every disk on storage both hosts share: it was refused
when the destination lacked a disk file, and a file of the same name
there was taken for the VM's own disk.

The Migrate tab now lists the VM's disk files for the chosen destination.
For each disk it offers the destination's pools that keep disk files
(directory, filesystem and NFS pools). A disk on storage both hosts share
can also stay where it is.

A directory counts as shared when both hosts have it as a storage pool
and a marker file created on the source exists on the destination. A
directory the probe cannot tell is never taken as shared.

libvirt copies the chosen disks during the migration: migrate3 with
NON_SHARED_DISK for those targets, and destination and persistent
definitions naming the new paths, where libvirt creates the files.

- A shut-off VM is started paused for the copy and shut off on the
  destination; its CPUs never run. Its UEFI variables are copied first,
  as the destination would start from the firmware's template. If the
  migration fails, the VM is shut off on the source again.
- Refused before anything changes, each disk with its reason:
  - a disk neither shared nor given a pool, also one only the next
    start's definition has;
  - CD-ROM images, read-only or encrypted disks, formats other than raw
    and qcow2, and disks with a backing file;
  - a pool that is not of disk files, or that has a file of that name,
    which libvirt would reuse and overwrite;
  - two disks copied to one file.
- The job claims each copy's name in its pool, and the source volume.
- A failed or cancelled migration deletes the copies libvirt made, and
  the UEFI variables copy, unless a VM on the destination has them.
- The source files stay and are named in the log. With "Delete the
  source files of copied disks" they go, except one another VM or volume
  uses; a failed delete is logged and the migration stands.

The NVRAM sharing check uses the same probe: a shut-off move stops when
it cannot be told, and the source file stays.

The API's migrate call takes disk_pools ({target: pool}) and
delete_source.
2026-10-29 19:46:31 +03:00
catborise
d43245d996 feat(instances): PCI devices hot-plugged into a running VM
- A running VM gets a PCI device of its host at once and for its next
  start, in one libvirt call; a hot plug libvirt could not keep for the
  next start says that the device is in the running VM only. A q35 VM
  without a free pcie-root-port gets libvirt's error and where a slot
  comes from.
- A PCI device is taken from the running VM and from its next start, each
  as it has it; a refusal by the guest stops there. When the guest has
  not let the device go within libvirt's wait, the page says the removal
  is requested and the Logs row records the request: the device stays in
  the running VM until the guest lets it go or the VM stops.
- A paused VM, or one with a saved state, does not change its PCI devices.
- A device for a running VM is checked alone too, as libvirt takes only
  the hot-plugged device from its host driver.
2026-10-29 14:54:36 +03:00
catborise
80dd145bcf feat(instances): PCI devices of the host given to a shut-off VM
- The Host devices tab gives a shut-off VM a PCI device of its host and
  takes it back; libvirt binds the device to vfio-pci when the VM starts
  and gives it back when it stops (managed). The VM's PCI devices are
  listed with whether the running VM and its next start have them.
- A device is offered, and accepted on the server under the compute's
  claim, only when it is no bridge of any kind (bridge header, PCIe port,
  or of the bridge class: host bridge, LPC), the host has none of its own
  network interfaces, disks or graphics card on it (else: bind it to
  vfio-pci on the host first), no other VM names it, and every other
  endpoint of its IOMMU group is the VM's too or has no driver or
  vfio-pci and no other VM; bridges in the group stay with pcieport, and
  a member that cannot be read keeps the group. Nothing in the group is
  taken implicitly.
- A snapshot revert checks the PCI devices of the snapshot with the same
  rules; migration and clones already leave host devices out.
- The add forms of the tab load together, when the tab opens.
2026-10-29 14:20:34 +03:00
catborise
ac8ff62e7e feat(instances): USB devices of the host given to a VM
- A Host devices tab on the VM page lists the VM's USB host devices, each
  once: how it is chosen (its address, or any device of its model), the
  device the running VM holds and whether its next start has it; its other
  host devices (PCI, SCSI, mediated) are listed for the XML editor.
- Superusers add a USB device of the host and take it back, on a running
  VM too. The add form is loaded when the tab opens, as its choices read
  every VM of the host; a hub, a device the host has its own disks or
  network interfaces on, or one another VM names is not offered, with the
  reason, and refused on the server under the compute's claim. A device is
  chosen by model when the host has one of it, else by its address.
- A VM without a USB controller is refused; a device is taken from each
  definition as that definition describes it.
- A clone gets none of the VM's host devices (the clone form says so), and
  a VM with host devices is not migrated. A snapshot revert is refused when
  it would give the VM a device another VM names or the host uses.
- A NIC that is a host device is no longer edited or removed from the
  Network tab: the XML editor changes it.
2026-10-29 13:33:23 +03:00
catborise
bc2b70544a fix(nwfilters): a filter in use is not deleted, and a change replaces no other filter
Plan reviewed with Codex; libvirt's behaviour checked on a host.

- A filter is not deleted while a VM's interface references it, as the
  VM runs or as saved for its next boot (a stopped VM too), or while
  another filter references it: libvirt refuses only one a running VM
  uses, and a VM using a filter that references a deleted one does not
  start. The VMs are read from one listing, one or two XML reads each,
  instead of a connection per VM; the refusal names them.
- Create refuses a name or UUID the host has, clone a name in use or
  one outside the panel's names, and editing the XML must keep the
  filter's name and UUID: each would replace another filter or make a
  copy. Entered XML is read for these checks without expanding entities
  or taking a DTD (util.parse_xml, shared with the network editor),
  and a rule is one <rule> element.
- A rule or reference is deleted only while it reads as the page showed
  it, not by index and three attributes: a rule alike in those or a
  filter changed meanwhile loses nothing.
- A reference is added only to another filter of the host not
  referenced yet; the picker offers those.
- References keep their parameters, in order (a name may repeat); a
  rule shows every protocol element it has, a rule without one too.
- One change a POST (two would both start from the page's reading,
  the second undoing the first); every change redirects and reports its
  refusal as a message, a POST for a filter gone meanwhile going to the
  list; the catch-all that showed any error goes, and so does
  wvmInstance.get_filterrefs, which only the old delete check used. The list reads each filter's
  XML once from one listing; a filter's page reads its XML once and
  only the other filters' names; the per-filter XML dialog of the list
  goes (a filter's page shows its XML). The XML editors send their text
  untouched too.
2026-10-29 10:10:17 +03:00
catborise
554e3a7995 fix(console): a VM with a QEMU websocket port opens through novncd
A VM defined with QEMU's own VNC websocket (graphics websocket='...',
which the panel never sets) made the console page connect to that port on
the panel's host name: the port is on the compute, so the console did not
open unless the panel ran on that compute, and then it bypassed novncd and
the panel's console token. Such a VM has its ordinary VNC port too, and
novncd now reaches it there like any other VM.
2026-10-26 21:27:52 +03:00
catborise
11348b2c37 fix(instances): Guest Info says when the agent fails and keeps what it answered
When the guest agent failed, the Guest Info section stayed empty with no
word: the request's error answer was not handled. An agent without the
time zone or host name command lost the OS details it had answered too.
The section now shows the agent's error, and a missing command leaves out
only its own details.
2026-10-26 13:49:37 +03:00
catborise
e29a79c76d fix(instances): internal snapshot names are checked, snapshot dates carry the year
Only external snapshots had their name checked. An internal one could be
taken with an empty name: libvirt named it, the job and its log row named
nothing, and a recovery looked for "" and marked the job failed though the
snapshot existed. Both kinds now pass the same check when queued, and the
internal form asks for a name as the external one does.

Snapshot dates showed no year, so last year's snapshot looked like this
year's in the list one reverts from; they now read 2026-10-13 23:04:00
under "Date (time zone)", as on the Jobs page.
2026-10-26 13:49:37 +03:00
catborise
f004552148 feat(instances): a new VM can get a cloud-init seed with its hostname and SSH keys
Cloud images read their first-boot settings with cloud-init. The panel
served them only over HTTP, which a VM reaches only with the network
and a reverse DNS name for its address. A new VM can now carry them
itself: Cloud-init seed (Advanced) on the create form, or cloud_init in
the API.

The job writes a NoCloud seed, an ISO labelled cidata, into the disk's
directory pool as cidata-<uuid>.iso and puts it in the VM's CD-ROM
drive. Its meta-data holds the VM's UUID as instance-id and its name as
hostname, written as JSON so a VM named 123 or yes keeps a string
hostname; its user-data is what the HTTP datasource serves, with the
creating user's SSH keys. The ISO is built with pycdlib and written
through a libvirt stream, as the NVRAM copy is, now one helper for both.

A seed needs a CD-ROM bus and a directory pool, else the create is
refused. A failed create deletes the seed with the new disk, recovery
names one left behind, and deleting the VM with its disks deletes its
seed, found in the pools by name even when ejected. A clone's drive is
left empty: the seed is the source VM's identity.
2026-10-25 19:57:15 +03:00
catborise
37422d81b3 fix(instances): a quiesced snapshot or live clone stops early on a silent guest agent
A quiesced snapshot and a live clone freeze the guest's file systems
through libvirt, which asks the agent without a timeout: with the agent
hung, the job waited, holding the VM, with no end.

The agent must now first answer a guest-ping within 10 s; a frozen or
dead agent fails the job in seconds, before anything is frozen. The
freeze itself stays libvirt's, without a timeout: a timed freeze was
tried and left the guest frozen, since the freeze still ran in the
guest when the agent came back, after its thaw had failed.
2026-10-25 17:42:01 +03:00
catborise
9c86e75c36 fix(instances): the IP search asks a guest agent with a timeout
The IP search and the VM report read each running VM's addresses and
OS from its guest agent with interfaceAddresses() and guestInfo(),
which wait for a hung agent indefinitely. The search answered by its
deadline, but the thread stayed blocked, counted against the search
thread limit and held up the worker's exit.

They now use the 10 s agent command the VM page uses, shared as
vrtManager.instance.agent_command() and agent_interfaces(). With the
agent frozen, a search answers in 5 s from the leases and the ARP
table, counts the VM unread, and its thread ends about 5 s later.
2026-10-25 16:15:18 +03:00
catborise
400b19cf42 fix(instances): a VM whose guest agent hangs no longer stops its page
The VM page read the guest's addresses with interfaceAddresses() from
the agent, and the OS details with agent commands without a timeout.
A connected agent that hangs (a frozen guest) kept the page from
loading at all and held a worker: seen still loading after 120 s.

Both now go through the 10 s guest agent command the root password and
SSH key use. The addresses come from guest-network-get-interfaces, in
the form the page's address code already reads; an agent that does not
answer leaves the ARP address. With the agent frozen the page loads in
about 10 s and the OS details answer with the agent's error (400) in
5 s, instead of a server error.
2026-10-25 15:56:47 +03:00
catborise
75fcc6f6c0 feat(instances): a running VM gets its root password and SSH key through its guest agent
The Access tab's Root Password and SSH Keys worked only on a shut-off
VM, through gstfsd on the compute. A running VM whose QEMU guest agent
is connected now gets them through the agent: guest-set-user-password
with the SHA-512 crypt hash, and guest-ssh-add-authorized-keys adding
the key to root's keys. A shut-off VM still goes through gstfsd; any
other VM is refused with "Shut the VM down, or start its QEMU guest
agent, and try again", and the buttons are disabled.

Each is one agent command with a 10 s timeout. libvirt's own calls for
them (setUserPassword, authorizedSSHKeysSet) wait for a hung agent
indefinitely, holding a worker and the VM's lock, and the domain's
agent timeout would change every other agent call of the VM too.

The agent's or libvirt's error is shown as is through error_text, so
users who do not see the hosts get no connection details, and the
attempt is logged as failed. The README names the SELinux boolean a
RHEL-family guest needs before its agent may add SSH keys.
2026-10-25 15:37:37 +03:00
catborise
c46212bb38 fix(instances): a disk on an LVM pool is not resized, the page says so instead of failing
libvirt's logical pool cannot change a volume's capacity, so every
resize of such a disk ended in a 500. Disks are resized one at a time;
VIR_ERR_NO_SUPPORT becomes a message naming the disk, and the other
disks still grow.

A live test creates an LVM pool from the storage page on a spare disk
(TEST_LIBVIRT_LVM_DEVICE; the Vagrant computes get /dev/vdb), attaches
new and existing volumes to stopped and running VMs as block disks, and
checks the refused resize in every state.
2026-10-18 21:10:06 +03:00
catborise
0f9bbd3e86 feat(instances): choose VNC or the serial console on the VM page
Settings > Console gets a Console type field. Serial removes the VM's
graphics device (adding a pty console when there is none); VNC adds the
graphics device new VMs get, on localhost, and then applies the form's
VNC fields, so an administrator can open it to all interfaces for a TCP
compute. Serial is offered only while SERIAL_CONSOLE_ENABLED is on.
2026-10-17 19:48:58 +03:00
catborise
d3e4ef9132 feat(instances): a shut-off UEFI VM can be migrated
The move copies the VM's NVRAM file to the destination with libvirt
streams (unless both hosts share the NVRAM directory) and removes the
copy if the move fails; the source's file goes with the existing
cleanup. The undefine keeps the file, as libvirt refuses to undefine a
VM with NVRAM otherwise. A VM with TPM state is still refused.
2026-10-16 21:05:23 +03:00
catborise
46a611941e feat(instances): a running VM can be cloned
libvirt's backup copies the disks of a running or paused VM from one
instant into new volumes while it keeps running; the clone is defined
shut off as before. The VM is held for the copy, the copy can be
cancelled, and recovery reads the job's records and libvirt.
2026-10-16 16:52:38 +03:00
catborise
39ad472a7c refactor(instances): live clone primitives and a shared clone definition
The clone's definition is one method for both paths; wvmInstance can check,
start, follow, read and abort a push backup of a VM's disks into new
volumes, and freeze/thaw the guest.
2026-10-16 16:52:38 +03:00
catborise
c2d3285e0f feat(instances): a running migration can be cancelled; its time limit goes 2026-10-16 07:57:02 +03:00
catborise
8d2e88f4bb feat(instances): snapshot revert runs as a job 2026-10-15 14:21:32 +03:00
catborise
fbf82da5a9 feat(instances): VM clone runs as a job 2026-10-15 09:28:43 +03:00
catborise
079e2ca5ca feat(instances): external snapshot delete runs as a job 2026-10-14 23:27:57 +03:00
catborise
5f8f7a8643 fix(instances): a snapshot needs free space in the VM's storage pools
A disk-only snapshot was taken without any space check, though its
overlays grow as the guest writes and a later delete merges them down;
a full pool pauses the guest and can leave the snapshot undeletable.
Only a memory snapshot was checked, for the memory alone.

Before a snapshot, each storage pool with a disk of the VM must have
free a share of those disks' virtual size (10%, at least 1 GiB), and
the pool of the memory file the VM's memory on top. Both values are on
the Settings page (Snapshot Free Percent, Snapshot Free Min GiB; 0
turns a rule off, an invalid value keeps the default). The pools are
refreshed first, and a failed refresh or an unreadable volume refuses
the snapshot instead of skipping the check; a disk in no pool is not
checked. Nothing is reserved: later writes can still fill a pool.
2026-10-13 13:27:39 +03:00
catborise
f766890825 feat(instances): external snapshots can freeze the guest file systems
A disk-only snapshot of a running VM is crash-consistent: data the
guest has not written yet is missing from it. With a connected QEMU
guest agent, the snapshot form now offers to freeze the guest's file
systems while the disks are snapshotted (libvirt's QUIESCE flag); the
box is checked by default and can be cleared. It is offered only for a
running VM whose agent is connected, and not together with memory:
libvirt accepts quiesce only for disk-only snapshots, and a memory
snapshot keeps the whole guest state anyway. A request that does not
fit is refused before libvirt is called.
2026-10-13 10:55:24 +03:00
catborise
5388743053 fix(vrtManager): refuse to migrate a VM with snapshots in every state
libvirt keeps snapshot metadata on the source host and a migration does
not carry it, even when both hosts share the disks. Only the shut-off
path refused such a VM itself; a running or paused one relied on
libvirt's own refusal. moveto now refuses it for every state, before
any check against the destination, with the same message.
2026-10-13 09:36:27 +03:00
catborise
097a91592c fix(instances): a snapshot file another VM uses is not called left behind
After a snapshot revert or delete, files libvirt could not remove are
named in a warning that says nothing uses them and asks to remove them
by hand. A file another VM on the same host uses (as a disk, a backing
file or a snapshot file) is no longer named: removing it would break
that VM. The warning now says no VM on this host uses the files.
2026-10-13 09:21:51 +03:00
catborise
c970f8e853 fix(storages): keep volumes a VM still needs
libvirt deletes any volume it is asked to. The storage page and the API
deleted a VM's disk, the base image of another volume or the file a
snapshot was taken on without a check, breaking the VM or its
snapshots.

wvmStorage.del_volume now refuses a volume a domain on the compute uses
as a disk or a backing file of one, a file of a domain's snapshots, or
the backing file of another volume. The check is the one destroy
already used, moved to wvmConnect and extended to snapshot files, so
destroy also keeps the files of another VM's snapshots. The storage
page shows the refusal; the API answers 400 with it, as for other
refusals. Deleting a disk from a VM refuses after the detach when the
VM's own snapshots need the volume, and says the volume was kept.

Network disks count by their source name, pool volume disks by their
volume's path. A volume whose metadata cannot be read stops the check
instead of counting as unused; only one removed meanwhile is skipped.
The check and the delete hold the compute lock, so no VM operation
attaches the volume in between; a busy compute is a message on the page
and 409 in the API.
2026-10-13 09:13:02 +03:00
catborise
08cad04468 fix(instances): deleting a VM's data takes its snapshot files too
Deleting a VM with its data deleted only the images its disks pointed
at. With external snapshots that is the newest overlay: the image the
snapshots were taken on, the older overlays and the memory files stayed
on disk, with nothing referring to them once the VM and its snapshot
metadata were gone.

The files the VM's snapshots were taken on, down each disk's backing
chain, the overlays of snapshots kept off the chain after a revert, and
the snapshots' memory files are now the VM's own too. A template the
VM grew from ends the chain and stays, as does an overlay of a disk
detached since. The backing references of the VM's own volumes no
longer count as another domain's use, and a file another VM uses keeps
the files below it.

A backing file that cannot be read (other than one in no pool) stops the
split before anything is deleted, instead of ending the chain there.
2026-10-13 09:03:05 +03:00
catborise
ff4ffab382 fix(instances): snapshot tab reads less and fails less
The snapshot tab listed the VM's snapshots three times per page: once
per kind and once more for all of them. The list of all is now made
from the two kinds, so the combined flag is no longer used anywhere.

The revert confirm named only the disks the persistent definition
would lose. A disk hot-plugged into the running VM alone is detached
too, so the live definition is compared with what ran when the
snapshot was taken.

A storage pool refresh error after libvirt had already made, reverted
or deleted the snapshot was shown as if the operation had failed. It
is now logged, and the left-behind check is skipped then, since a stale
pool still lists the removed files. A volume removed while that check
reads it is skipped too.

An error reading the block jobs no longer breaks the instance page;
create, revert and delete still query the jobs again and refuse.
2026-10-13 08:30:22 +03:00
catborise
3fd422db7e fix(instances): name snapshot files libvirt could not remove
When libvirt cannot remove a snapshot file it merged or discarded, it
only logs a warning and the delete or revert still succeeds. On NFS it
removes them as the qemu user, so an image directory the qemu user may
not write to left every merged overlay on disk without a word.

Revert and delete now compare the files in use before and after and
show a warning naming the ones still on disk. Only a snapshot's own
files (overlays, memory) and overlays on a snapshot point count, and a
disk the revert detached is never named, so a kept disk is not offered
for removal.
2026-10-12 21:41:20 +03:00