- A VM delete reads delete_disk and delete_nvram as booleans from a JSON
or form body. The view read them as HTML checkboxes from the form body
only: JSON {"delete_disk": true} kept the disks while reporting success,
and a form "delete_disk=false" deleted them. Refused options stop
nothing; the API schema names both options.
- Power on and power cycle of a template answer 409 instead of reporting a
start that did not happen.
- The VM details leave out the host's ISO images for non-superusers, as
the VM page does; reading them also refreshed every pool of the host.
- Flavors take values of at least 1, as the web form does, and show their
id for later changes; a migration needs neither live nor offline; a VM
create on an unknown compute answers 404 instead of 500.
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 Logs page now records the panel's own records too: users (add,
change with the changed fields, delete, block, unblock, an admin's
password set, a user's own password change including the first-login
one, own profile edits), groups with their members and permissions,
VM owners from the accounts pages and from the VM page, OTP QR code
mails, flavors from web and API, app settings and the theme,
removed-VM records and SSH keys. No row carries a password or a key.
- A user is created in one transaction: when a VM named in
NEW_USER_DEFAULT_INSTANCES is missing, no half-made user stays.
- The OTP mail checks the email address before it creates a device;
without one it writes a failed row and makes no device.
- The VM page's owner rows read "VM web-1 owner bob: add" and
"...: remove" instead of "Add owner: bob" and "Delete owner: 17"; a
second owner refused by the single-owner setting is a failed row.
Owner rows keep the VM's host and name, so the VM's log tab shows
them.
- A setting or theme posted with its current value is no change and
writes no row; the old free-text setting rows are gone.
Host-side objects (networks, storage, interfaces, secrets, filters)
follow in the next layer.
A VM that changes its memory faster than the network carries it does
not finish a live migration without auto converge (measured: a guest
rewriting about 1.2 GB/s did not finish in 90 s over an 8.5 Gbit/s
link, and finished in 16-18 s with it). Auto converge only slows the
VM's CPUs while the migration cannot keep up, so a calm VM is not
affected.
The migrate form ticks it for a running VM. The API already documented
it as on by default but read a left-out option as off; the serializer
now has the defaults (auto converge on, compress and unsafe off) for
JSON and form-encoded requests, and the schema shows them.
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.
Creating each option on a RHEL qemu-kvm host showed:
- CD-ROM: the create page offered every disk bus, but the empty CD-ROM
of a new VM works only on ide, sata and scsi. fdc and virtio failed
("Invalid bus type", "does not support ejectable media"), usb failed
with a device named 'Nonea' because vol_dev_type() had no prefix for
usb, and after that libvirt refuses an empty usb disk. Only ide, sata
and scsi are offered now, and another value is refused before any
storage is allocated. vol_dev_type() names usb disks sdX, which also
fixes data volumes on the usb bus.
- USB controller: any input device added a bare <controller
type='usb'/>, which libvirt turns into piix3-uhci (USB 1.1) on q35
instead of its default qemu-xhci. The bare controller is gone; libvirt
adds the machine's default for USB inputs.
- MACs: with more networks than MAC addresses, create_instance indexed
past the list and the request failed with a 500. NICs without a given
MAC now get one from libvirt. MAC addresses are validated (format, not
more than networks) by the page and the API before anything is
created; they went into the XML unchecked.
Unit tests cover the refused values, the MAC rule and the usb prefix.
Live tests create a VM with every offered CD-ROM bus and start it,
check the USB controller with a USB input device and create a VM with
two networks and one MAC.
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.
Web form: the cache mode and the UEFI firmware value were checked only
after the disk volume had been created; an invalid one answered 500 and
left the volume. All checks now run before any allocation. Volumes the
request creates are removed on any failure up to the definition; ones
that cannot be removed are reported. After the definition the VM uses
them, so a later failure keeps them.
API: the new volume was never removed when the definition failed, and
the error was a 500. It is removed now and a libvirt error returns 400.
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.
Super-linter ran from the unpinned :latest image and, because of
branches-ignore: [master], never on pull requests to master. Ruff now
checks syntax errors and pyflakes rules (E9, F) on every push and PR.
Fixes the existing findings: unused imports and variables, an unused
duplicate import in instances/tests.py, and the star import in
accounts/views.py. settings-dev.py keeps its star import of the base
settings.
Disk edits:
- edit_disk built a new <disk> from the form and replaced the old one,
losing what the form does not show (e.g. encryption and virtio
driver options); a bus change detached and re-attached the disk.
The disk of the persistent definition is now edited in place and the
domain defined once; a bus change picks a free device name and drops
the old address and virtio-only options. Pending persistent changes of
a running VM are kept.
- Clone omits empty disk devices, refuses a disk without a supported
source and destination, and checks the name before allocating storage.
Locks:
- Every VM change held its compute's exclusive lock, so one slow
operation blocked all VMs on that compute. A VM change now holds its
own VM lock plus a shared compute lock; reconciliation, migration and
cloning hold the compute exclusively (two clones of different VMs
must not pass the name check together).
- Quota-checked changes of one user (CPU, memory and disk resize,
clone) run one at a time under a per-user lock, also across computes,
so concurrent requests cannot all pass the check against the old
allocation. It is the outermost lock; superusers, who have no quota,
skip it.
- A busy lock answers 409 to the API and a message in the web UI. API
power and destroy actions return the view's error instead of success.
- 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.
- Computes API: mark password as write_only in ComputeSerializer, restrict ComputeViewSet and architectures to IsAdminUser.
- Instances API: enforce user ownership tenant isolation in InstanceViewSet.list, restrict MigrateViewSet and CreateInstanceViewSet to IsAdminUser, require IsAdminUser for mutating FlavorViewSet.
- Storage, Network, and Interface APIs: restrict StorageViewSet, VolumeViewSet, NetworkViewSet, InterfaceViewSet to IsAdminUser.
- AppSettings & NWFilters: protect appsettings and nwfilter views with @superuser_only (403 Forbidden for non-superusers).
- noVNC Console: sign tokens with TimestampSigner (salt='console.novnc', max_age=600), verify signature and user authorization in novncd with backward-compatible fallback for debug/test mode.
- Accounts: avoid hardcoded default admin password; generate cryptographically secure random password unless ADMIN_PASSWORD is set (preserve 'admin' in test runner).
- gstfsd daemon: bind to 127.0.0.1 by default instead of 0.0.0.0.
- Tests: added comprehensive test coverage for API security, token expiration/rejection, and view permissions (132 tests passing).
* 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>