A VM made from a template came out at the template's size and shut off,
and was then resized and started by hand. The Clone tab now asks for the
clone's vCPUs and memory, filled in with the VM's, and whether to start
it. After the copy, before the clone is recorded, it is resized with the
Resize tab's own functions and started; a step that fails is a warning
of the job, and the clone stays. The quota counts the larger of the size
asked and the VM's, so a resize that fails leaves the clone at a size it
allowed.
When the job ends the page opens the clone's, not the cloned VM's again:
a template's page, shut off, read as a clone that had not started. An
outcome kept for a warning links to it.
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.
Windows 11 does not install without Secure Boot and a TPM 2.0, and the new
VM form offered neither: its firmware list was BIOS and one UEFI loader
guessed from file names, which on RHEL never matched the Secure Boot one.
The firmware choices are now BIOS, UEFI and UEFI Secure Boot, as the
host's libvirt reports them (its firmware features from libvirt 12.1,
before that its loaders), and libvirt picks the firmware itself: UEFI
without Secure Boot, or with Microsoft's keys enrolled. A TPM 2.0 switch,
shown when the host has swtpm, adds an emulated TPM. The create job
refuses a firmware or a TPM the host does not offer, and the API takes
both. The path-guessing helpers are gone.
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.
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.
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.
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.
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.
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.
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.
- A named CPU model is written without check='none' and with
fallback='forbid': libvirt checks before the start that the host runs
it, and it is not swapped for another model.
- Mode maximum is written as that mode; it was written as a model named
maximum.
- Model names up to 64 characters: the -noTSX and -IBRS models, the ones a
mixed set of hosts needs, were refused at 20.
- The mode or model is checked against the host's capabilities when the VM
is defined, from the page and the API alike; no CPU element (QEMU's
oldest default CPU) is no longer offered.
- The default CPU mode setting offers the modes the new VM dialog has;
no-model and custom, which matched none of them, become host-model.
A tombstone kept the VM's name and UUID but not its compute, so the page
could not say where the VM had been. It now stores the compute's name (as
text: the compute may be the one deleted) and the list shows it; records
made before this have no host. Deleting a record says so, and the admin
tables use scope="col" instead of the invalid span="col".
Closes#217
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.
The XML editor of a running or paused VM only showed its XML. It now
shows the persistent definition, the one the VM starts with next (with
secrets, like the other edit forms), and Change saves it through the same
review dialog; the running VM keeps its live configuration until it
restarts. The tab and the saved message say so. The check against a
definition changed since the editor was opened covers this case too.
The create form and the API took 0 or a negative number for vCPUs,
memory and a new disk's size: the API queued the job (202) and it
failed later in libvirt; the page did the same, its formnovalidate
skipping the browser's min. The create model's fields now refuse
values below 1, so the form shows the error beside its field and the
API answers 400 naming it.
The form also checks the MAC addresses as the API and the job do (one
per NIC at most, each a MAC address), so a bad one is an error on the
form instead of a job that fails.
Closes#175
The custom create form shows a MAC per network (random, or typed in),
but had no mac field: the script wrote the joined list into every
name="mac" input of the page, the other six-plus forms' own MAC fields,
so a flavor form then sent one MAC per custom network and was refused,
and the custom VM got other MACs from libvirt. The custom form gets its
own hidden mac field and the script writes only there. The field took
17 characters, one MAC, so the API also refused a VM with two NICs and
their MACs; it takes 255. The serializer's test sent no submission_key,
so its check for more MACs than networks never ran; it does now, next
to the case of two networks with two MACs.
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.
Create, revert and delete are one libvirt call each. The pflash-to-rom
loader rewrite, the hand-written block commit and the s1./s2. names are
gone, so UEFI VMs can take external snapshots, a revert keeps disks added
later, and deleting an older snapshot keeps the newer one.
Create refuses what libvirt could not revert or delete later: internal
snapshots on the VM, a saved state, a running snapshot job, disks that
are not files, CD-ROM media, a branch after a revert, and memory without
a running VM or room in the first disk's pool. A disk-only revert keeps
the VM running, paused or shut off; one with memory resumes it as saved.
A revert in the same second as the previous one, which libvirt fails
after stopping the VM, is retried once.
A snapshot the old code took of a UEFI VM saved the loader as rom; its
revert is refused (deleting it still works).
The snapshots tab lists internal and external snapshots separately, can
save memory too, shows running snapshot jobs, and the revert confirmation
names the disks it detaches and that NVRAM is not restored.
On an active VM the boot order editor, the video model select and the
console form showed the running VM: a pending boot order, video model or
console setting looked unset, and the boot order editor offered devices
of the running VM only. Choosing one of those cleared the pending order,
since the setter dropped the old order and skipped devices it could not
find. They now read the persistent definition (get_bootmenu,
get_bootorder, get_media_devices, get_video_model and the console
getters take config=), and set_bootorder refuses a device that is not in
it before it changes anything.
On an active VM the options and CPU forms write the persistent definition
but showed the running VM's title, description and vCPUs, so saving one
posted the live values back over a pending change. They now read the
persistent definition (get_vcpu, get_cur_vcpu, get_title and
get_description take config=).
Buttons in the settings and resize tabs that were disabled only by class
get the disabled attribute: Enter in a field no longer submits a form
the page shows as unavailable while the VM runs.
The QoS table showed the running VM's bandwidth while an edit changes the
definition for the next start. Each row posts average, peak and burst,
so an edit wrote the running values back over a pending change, and a
direction added while the VM ran had no row. The table shows the
persistent definition now. An edit also kept only the posted values and
dropped an inbound floor; it now updates them and keeps the rest.
On a running VM a disk edit changes the definition for the next start,
but the disk list and its edit form showed the running VM's disks. The
form posts every field, so an edit wrote the running values back over
earlier pending changes (cache, io, serial, ...), and a disk only in the
next definition could not be edited. The list now shows the persistent
disks. A volume is deleted only when both definitions use it at that
device, since the list may now show another source than the running VM.
A VM that disappears from its compute keeps its owners in a tombstone
until INSTANCE_OWNERSHIP_RETENTION_DAYS pass, but nothing showed them.
Superusers now see them on the "Removed VMs" admin page (name, UUID,
owners, removed, expires) and can remove one, so a VM deleted on
purpose no longer hands its owners to a later VM with the same UUID.
moveto read the VM state for each flag and dropped options that did
not fit it, so a request could run as something else than asked; the
log then named the mode from the form ("live" or "offline"), not the
one used. The API did not log at all and answered "instance migrate is
started" after the migration had finished.
- moveto reads the state once. A running VM migrates live, or without
live paused for the transfer (non-live); a paused VM stays paused; a
shut-off VM moves offline. Live for a shut-off VM, offline for a
running or paused one, and any other state are refused before
anything changes. unsafe, auto converge (live only) and compressed
apply to a running VM.
- migrate_instance logs the outcome for the VM page and the API: the
mode and options used, or the error. The API answers
"instance is migrated (<mode>)" and accepts requests that leave out
an optional option.
- Post copy is gone from the form, the view and the API: only the
flag was set, and without migrateStartPostCopy, which the app never
called, the migration never switched to post copy.
Migration left the VM defined on the source host unless "Delete
original" was ticked (VIR_MIGRATE_UNDEFINE_SOURCE). With the shared
storage migration needs, that definition points at the disks the
destination VM is running on: the VM showed on both hosts and could be
started (or autostarted) a second time against the same disks; only a
configured lock manager stops that.
moveto now always passes VIR_MIGRATE_UNDEFINE_SOURCE with
VIR_MIGRATE_PERSIST_DEST. The option is gone from the form, the view,
the API (MigrateSerializer.xml_del) and the clone auto-migration. It
removes the definition, not the disk files.
The instance lists read each VM from libvirt while rendering. When that
failed, the libvirt error replaced the whole page with the error page:
one VM removed out of band, or a host that is down, took the index or
a compute's instances page with it. To avoid that, both index views
left out every VM of a host that was not connected, so users saw their
VMs disappear.
- Instance.info is None when the VM cannot be read. The row then shows
the name and owners from the database, the state "Unknown", and no
title, vCPU, memory or actions.
- Both index views list the VMs of a host that is down. The grouped
view marks the host "Not Connected" and leaves out its CPU and memory.
- A compute's instances page shows the connection error, and no longer
says the hypervisor has no instances when it cannot be reached.
Checked against the test hosts with an unreachable compute added: both
index views list its VM as unknown next to the real VMs. The first
load takes 5.5 s (one bounded connection attempt), the next ones
0.1 s. The new tests fail on the previous code (VMs left out, error
pages).
The VM rows of the instance lists used instance.proxy.instance.info in
every state check, the vCPU column and the action buttons. A template
calls the method on each lookup, so every row made 7 virDomainGetInfo
RPCs (8 on a compute's instances page), and the memory column read the
domain XML once more.
- Instance.info reads virDomainGetInfo once per request; the lists and
instance_actions.html use it.
- The memory column of both index views comes from the same info
(current memory) instead of the domain XML. The value is the same:
checked against currentMemory for every running and shut-off VM of
the test hosts.
A row now makes one info call and one XML read (the title). The new
test counts the calls in the grouped and non-grouped index and on the
compute instances page; it fails on the previous code with 7 and 8
calls.
Comments, docstrings and live test names cited item IDs of a roadmap
that is not part of the repository. They now say what is meant, or
nothing where the sentence stands without them. Test assertions and
behavior are unchanged.
The sync deleted the Instance of every VM missing from its compute, and
its owners and rights went with it. A VM moved with virsh, or undefined
and defined again, came back with no owner.
Now, when a VM disappears from a compute:
- if the same UUID is recorded on another compute, it moved: its owners
and template flag go there;
- otherwise they are kept in an InstanceTombstone and restored when the
UUID appears again within INSTANCE_OWNERSHIP_RETENTION_DAYS (30).
A UUID recorded on two computes at the same time is a copy and gets no
owners. VMs deleted through WebVirtCloud leave no tombstone.
- change_network detached the NIC and attached one built from scratch,
dropping its QoS, link state and other settings. It now edits the NIC
of the persistent definition in place and defines once; a running VM
gets the change at its next start, as the UI already says.
- add_network, delete_network and set_link_state did nothing on a
paused VM, and set_link_state rewrote the persistent NIC from the live
XML. They now update the running definition when the VM is active and
the persistent one always, each from its own XML.
- Boot and console edits used xml.etree, which renamed the namespace
prefixes of other tools' metadata (<app:info> became <ns0:info>); they
use lxml now.
- The NIC table and the clone form are filled from the persistent
definition (Instance.config_networks, config_disks), so a pending NIC
change is shown and can be edited again.
A live test runs 18 domain edits on stopped, running and paused VMs
whose definition has elements WebVirtCloud does not manage, and checks
for each the effect, that nothing else in the persistent definition
changed, and that persistent-only edits leave the running VM alone.
SPICE was removed earlier; its leftovers and the console type choice go
too:
- the console settings form, update_console and the backend no longer
offer or change the type; an invalid console form now shows its
errors instead of being ignored;
- the create form, the API serializer and create_instance no longer take
a graphics type, new VMs get VNC; get_graphics_types and the graphics
entries of the domain capabilities are gone;
- migration appsettings.0013 deletes QEMU_CONSOLE_DEFAULT_TYPE;
- a VM defined elsewhere with another graphics type gets "Console type
... is not supported".
The locale catalogs still reference the deleted SPICE templates in
source comments; regenerating them is left to the translation work.
Instance.proxy looked the domain up by its stored name. After a rename
or a name swap outside WebVirtCloud, an operation on one VM changed
another; after a VM was replaced under the same name, operations hit
the new VM.
wvmInstance takes the UUID and uses lookupByUUIDString, with no
fallback to the name: a missing UUID fails instead of picking another
domain. Every caller that has an Instance passes it: proxy, console,
quota, post-migration autostart and the VDI URL. Migration uses the
domain the proxy already resolved. getvvfile and the gstfsd requests
use the host's current name of that UUID.
Live tests cover a name swap and a VM replaced under the same name;
both fail on the previous code.
- Routers use path converters (use_regex_path=False): computes, instances
and flavors take <int:...> ids, so non-numeric ids get 404 and
drf-spectacular derives the parameter types itself.
- Each method declares what it really returns: detail serializers,
a shared StatusSerializer for status-only replies, no request body for
actions. Instance properties used by the details serializer get return
type hints.
- The create-instance API drops the firmware field. Its only accepted
value was "" (BIOS), which produced an empty, invalid enum, and the
UEFI branch behind it was unreachable. Clients that still send it are
unaffected; DRF ignores unknown fields.
The schema now passes spectacular --validate --fail-on-warn; a test
keeps it that way.
* Add rest framework for API: First Commit
* modify some shell scripts to make variable references safer; modify some python scripts to reduce the code complexity and cyclomatic complexity of functions.
* Add REST API for some webvirtcloud functions. Instance list/delete/create, compute list/delete/create, storages-network list/retrieve. Add swagger and redoc for API interface
* update requirements
Co-authored-by: herengui <herengui@uniontech.com>