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

20 commits

Author SHA1 Message Date
catborise
aab8dbf1df perf(instances): a VM page does not wait for the guest agent's addresses
A running VM's page read its addresses while it rendered: the guest agent,
when its channel is connected but it does not answer, holds the page (and
a gunicorn worker) for its whole 10 s timeout, on every load. The page now
shows them once it has loaded: vm_addresses.js asks the new
instances/<pk>/addresses/ for each NIC's addresses and fills the header's
IPv4 and each network card's IPv4 and IPv6.
2026-11-07 15:42:49 +03:00
catborise
f1f52aac42 refactor: the API's serializers and the new VM form no longer need models
Networks, Interfaces, Storages, Storage, Volume, MigrateInstance and
CreateInstance were unmanaged models with no table, there only so that
ModelSerializers and the new VM ModelForm could take their fields. They
made content types and migrations, and their DO_NOTHING foreign keys
added reverse accessors that meant nothing (Compute.host,
Compute.target_host, Instance.source_host).

The serializers are plain Serializers and NewVMForm a Form, field for
field as the models gave them (types, lengths, required, defaults, the
minimum of 1 for vCPUs, memory and disk size; the form's labels are
still derived from the field names). Compared field by field before and
after, the API schema changes only where the models were wrong:
- no int64 bounds on the listing fields;
- the interface fields lose the titles that named the wrong column
  (type was "Status", state "Device", mac "Forward");
- a pool's volumes is a list of objects (it was described as an
  integer) and a volume's allocation an integer (it was untyped).
One migration per app deletes the models; none touches a table.
2026-11-06 13:46:27 +03:00
catborise
02412b7ea5 feat(jobs): deleting a VM is a job that recovery finishes
The delete ran in the request: undefine, then the VM's record, then its
disk files. A request that died in between (a gunicorn worker past its
timeout, OOM, a restart), or a database write that failed after the
undefine, left a record that later showed as removed outside the panel,
and the disk files the user asked to delete were never deleted.

Deleting a VM is now an instance.delete job. It holds the compute
exclusively, as the request did, so no other VM attaches a file it is
about to delete. The job chooses the files before it stops the VM (a host
that cannot be checked still stops nothing) and records them first. It
then stops and undefines the VM, removes its record, and deletes the
files, each with its own Logs row. Recovery decides from libvirt: a VM
still on its host means the delete failed; a VM gone means libvirt did
it, so recovery removes the record and deletes the recorded files that
are still there.

The page queues the job and returns to the VM page, where the job panel
follows it and opens the VM list when it ends; disks that were kept are
the result's warning. The API's delete answers 202 with the job and
needs a submission_key. backing_path moves to wvmConnect, as recovery
has no domain to ask.
2026-11-06 09:49:31 +03:00
catborise
542cce031e chore(api): drop a class attribute MigrateSerializer never used
`instance = Instance.objects...` on the serializer class was a queryset,
not a field: DRF ignores it, and each serializer's own instance replaces
it.
2026-11-05 18:58:13 +03:00
catborise
b89672169f fix(instances): Refresh ISO list says which pools it could not read
A pool whose refresh failed, one busy with a volume copy for example,
was skipped without a word, so a hand-copied image stayed missing with
no reason given. The other pools are still refreshed; each failure is
shown with libvirt's error.

The API comment no longer says listing the ISO images refreshes pools.
2026-11-02 16:11:15 +03:00
catborise
005fa59bf0 feat(instances): a new VM can have UEFI Secure Boot and a TPM 2.0
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.
2026-11-01 16:18:29 +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
8d7f28482f fix(api): VM API answers as the VM pages do
- 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.
2026-10-26 17:47:18 +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
31cbe60aa4 feat(instances): migration runs as a job 2026-10-16 07:57:02 +03:00
catborise
6f0c730071 feat(instances): VM create runs as a job, also in the API 2026-10-15 09:28:43 +03:00
catborise
98bb6ebdb5 feat(instances): auto converge is on by default for a live migration
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.
2026-10-06 17:04:03 +03:00
catborise
5061cc7f2c fix(instances): a migration runs in the mode the VM's state allows, and is logged as it ran
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.
2026-10-06 15:26:49 +03:00
catborise
25b3671c33 fix(instances): a migrated VM's source definition is always removed
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.
2026-10-06 13:58:59 +03:00
catborise
03ac93ea53 fix(instances): CD-ROM bus, USB controller and MACs of a new VM
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.
2026-10-04 18:33:28 +03:00
catborise
e5fda79f5a feat(console): VNC is the only console type
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.
2026-10-04 01:08:11 +03:00
catborise
3b8869c72f fix(api): typed URLs and accurate response schemas
- 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.
2026-10-04 01:08:11 +03:00
catborise
a1eab70e2d reorg imports and black format 2022-11-02 16:05:41 +03:00
catborise
217e106c8b format python code with black 2022-11-02 08:54:35 +03:00
catborise
cfce71ec2b
Rest framework (#24)
* 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>
2022-08-22 15:12:33 +03:00