1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 11:46:49 +00:00
Commit graph

61 commits

Author SHA1 Message Date
catborise
e79841ab1a fix(storages): a pool the host does not have goes back to the pools list
Opening /computes/<id>/storage/<pool>/ for a pool the host does not
have (or a host that does not answer) raised libvirt's error out of
the view: a 500. Now the pools list shows the reason, as the network
page does.
2026-11-03 14:53:05 +03:00
catborise
f77439f398 fix(storages): a refused new volume comes back in its dialog
A New volume form the pool page refused, for a name with a space or a
character not allowed, redirected back with the reasons at the top of
the page and lost what was typed.

The form now posts to the pool page itself: a valid one makes the
volume and redirects as before, a refused one renders the page with
the dialog open on what was entered, the refused field marked with its
reason and focused. A pool stopped meanwhile has no dialog: its page
shows the reasons. The separate create_volume view and URL go.
2026-10-31 18:35:09 +03:00
catborise
d97ec5afd2 fix: a queued job is shown once, in the job panel
Queuing a long operation put "... is being ...; follow it in the job
panel." above the page, while the job panel on the same page showed the
job and its progress. Every such form returns to a page with the job
panel for the job's resource (the VM, the compute's VM list, the pool),
and the panel shows a job even when it ends before its first poll. The
eight messages are removed: migrate, clone, create, volume clone and the
snapshot create, revert and delete jobs. Refusals stay messages.
2026-10-29 21:38:09 +03:00
catborise
a95ec40f69 fix(virtsecrets): a secret in use is not deleted, and a password is stored as typed
- A secret is in use when a VM names it in a disk, a host device or its
  vTPM, or a pool in its source, by UUID or by its usage within the usage
  type, as they run and as saved. The vTPM, host devices and pools' saved
  definitions were not checked before.
- A Ceph key is taken in base64, as `ceph auth get-key` prints it; any other
  value is a password or passphrase stored as typed, spaces included.
- A new secret takes its value at once; a value refused leaves no secret.
- TLS and vTPM secrets can be created; the usage has no length limit.
- Every POST redirects; the list is read once and only with its users; a
  secret, VM or pool gone meanwhile is left out.
- domain_trees() is shared by the in-use checks of secrets, network filters,
  networks and pools; the storage page's Ceph secret picker reads the same
  listing.
2026-10-29 10:10:43 +03:00
catborise
befd1747df perf(storages): a pool's volumes are read with one libvirt call each
wvmStorage.update_volumes looked each volume up by name three times,
read its info twice and its XML once: six round trips per volume to
the host. It now lists the pool's volumes as objects (listAllVolumes)
and reads each one's XML only (volume_details): name, capacity,
allocation and format are all in it, and libvirt refreshes a volume
for its XML as it does for info(). A pool of N volumes takes 2 + N
calls instead of 2 + 6N; 100 volumes over SSH on a test host read in
about 110 ms instead of 720 ms, with the same values.

- A volume deleted between the listing and its read is left out; any
  other error is raised. Volumes come sorted by name.
- get_volume_details (the API's one volume) reads it the same way.
- Only a refused refresh (a clone running in the pool) is tolerated,
  not any exception.
- The pool page reads its volumes and space only to render itself;
  its actions, which all redirect, no longer read every volume first.
- get_volume_size and get_volume_allocation go: nothing else used them.
2026-10-28 19:34:34 +03:00
catborise
3aa198304a feat(storages): the storage pages on Bootstrap's tables, cards, badges and menus
- The pool list is a card per pool, two to a row, as the host
  Overview's Hardware and Software cards: its name with Active or
  Stopped and Autostart badges in the header, then its type, its path
  (an RBD pool's Ceph pool), its volume count and its space as the
  Overview shows it (computes/pool_bar.html, without the name again);
  a stopped pool's space is unavailable, not zero.
  wvmStorages.get_storages_info gives the path, autostart and percent
  used, which computes.views.host_pools computed for itself.
- A pool's page has a Space card (percent, used of size, of what: the
  filesystem of its path, its volume group or the Ceph cluster, which
  other pools may share; free) and a Pool card (state, autostart,
  type, path) instead of a two-column list mixing facts and forms.
  Start or Stop is its heading's button; autostart and deleting a
  stopped pool are in its menu; the confirmations stay.
- The volume table drops the row number; a volume's capacity and what
  it has allocated share a column hidden on a phone; its format is a
  badge; its actions are one group, Clone and a menu with Delete,
  named for the volume.
- "New pool", "New volume" and "Upload ISO" are labelled buttons
  instead of bare green pluses; their dialogs' titles name them.
- The New pool dialog is one form (design reviewed with Codex): the
  pool's type as radio cards, as the VM create page chooses its disk
  source (their style moves to webvirtcloud.css), one name, and only
  the chosen type's fields, the others hidden and disabled.
  - A directory's or a share's mount path follows the name
    (/var/lib/libvirt/<name>) until it is edited: no default path of
    another pool any more.
  - ISO images is a directory preset named iso; when the host has an
    iso pool, a card links to it instead.
  - Ceph offers the host's Ceph secrets by their names, not every
    secret by UUID; without one it says so and links the Secrets page.
  - LVM asks to agree that the device is erased, the server too.
  - AddStgPool checks each type's fields, a name or a path another
    pool has, an RBD secret that is not one of the host's Ceph secrets,
    and the names "." and "..". A refused pool, or one libvirt refuses,
    opens the dialog again with what was entered, the reasons beside
    the fields and focus on the first; the audit row for a taken name
    stays.
2026-10-28 19:27:21 +03:00
catborise
fa5a8c4d6e fix(storages): the pool page measures its pool fresh, shares one clone dialog and says what it cannot show
- The page lists the volumes first: that refreshes the pool, and libvirt
  measures a pool's space only when it is refreshed, so the size and
  usage shown were as of the previous refresh.
- A space that cannot be read says so instead of 0 bytes, and the
  pool's status, read from the same pool info, no longer fails the
  page after it; a stopped pool says its space and volumes are
  unavailable until it is started, instead of 0 bytes and nothing.
- The API's pool is measured after the same refresh, and a stopped
  pool lists no volumes there instead of failing.
- A clone the job refuses (a name in use, a volume gone) is a message
  on the page, not a server error.
- An ISO image is recognised by its name (storages.jobs.is_iso):
  libvirt calls its format raw, so the template's "iso" check never
  disabled its Clone button. The clone job refuses one too; the upload
  uses the same rule.
- One clone dialog serves every volume, filled and reset by the button
  that opens it, instead of one dialog per volume in the page; its
  fields have labels and its title names the dialog.
- Volume rows are searched by name only (data-search), with a message
  when none matches, in a live region for screen readers; names show
  in full. The search script loads only
  with the volume table: on a stopped pool's page it failed for want
  of a search box. An empty pool says "This pool has no volumes".
- The unused wvmStorage.get_volumes_details goes: update_volumes is
  the same.
2026-10-28 19:20:35 +03:00
catborise
63aba5d9c9 fix(storages): pool pages work while a volume is cloned, failed pools are undefined
- libvirt refuses to refresh a pool while a volume is cloned in it. The pool
  page, the volume list of the VM and create pages, upload planning and the
  API no longer fail on that refusal; they use the list libvirt has.
- A new pool that does not start (unreachable NFS server, a device LVM
  cannot use) is undefined again, so the name is free for another try.
- A pool reporting no size, such as an iSCSI pool without LUNs, shows its
  page instead of a division error.
- Each clone dialog shows its own format and metadata rows, so a format
  is never shown without Convert ticked and silently ignored.
- The new-volume size is labelled in GiB and is at least 1; an inactive
  pool shows no "None" volume count.
2026-10-26 15:36:57 +03:00
catborise
b24746c1cb fix(logs): blocking a blocked user writes no row; one upload submit path
Follow-ups from the review of the audit log layers:

- Blocking a user who is already blocked, or unblocking one who is
  not, changes nothing and now writes no row, like any other edit
  that changes nothing.
- write_chunk takes the request instead of the user and an optional
  request; the view always had one, so the branch only tests used
  is gone and every chunk 0 goes through the same audited submit.
- Tests: a busy clone creates no job and its row carries the page's
  message; a later chunk that fails writes no submit row; libvirt
  refusing a network or pool delete is a failed row.
2026-10-23 14:23:32 +03:00
catborise
d5df187de4 fix(networks, storages): a name in use is refused by the page again
The create forms of networks and storage pools checked the new name
against the host's list of networks or pools, but that list holds one
dict per object, so the name never matched and the check never fired;
libvirt refused the duplicate with its own wording. The check now
compares names: the page shows its own message, nothing is sent to
libvirt, and the Logs page gets a failed row "...: add: name already
in use".
2026-10-23 14:07:47 +03:00
catborise
5b8793ad4c feat(logs): changes to networks, storage, interfaces, secrets and filters are logged
The Logs page now records every change an admin makes to a compute's
libvirt objects, with the compute's name in the host column:

- networks: add, start, stop, delete, autostart, DHCP range, fixed
  addresses, QoS and XML edits;
- storage pools: add, start, stop, delete, autostart, from web and
  API; volumes: add and delete (web and API), clone and ISO upload;
- host interfaces: add, start, stop, delete;
- secrets: add, set value (never the value), delete;
- network filters: add, clone, delete, XML edits, rules and
  references.

A refused or failed change is a failed row with its reason (libvirt
text through safe_text). The volume clone and upload jobs write their
row when they end; a refused submission is a failed row at once. A
volume row names the volume libvirt created (a dir pool adds .qcow2 or
.img). Volume create or delete through the API on an inactive pool
(409) is a failed row.

Network filters: the rows read "Network filter f1: add" instead of
"f1 network filter is created", and their host is the compute's name
instead of its hostname. A duplicate name or UUID no longer raises a
bare exception, and a filter XML that cannot be parsed no longer ends
in UnboundLocalError.
2026-10-23 13:30:21 +03:00
catborise
887b807451 fix: a network, pool or secret a VM needs is not stopped or deleted
Stopping a network cut the running VMs on it off, deleting one or a
secret kept the VMs that name it from starting, and stopping a pool
took the disks of running VMs away, all without a word. Each is now
refused with the VMs (and, for a secret, the pools) that need it:
stopping while a running VM uses it, deleting while a VM's definition
names it. A disk given by its file path does not need its pool's
definition. The API's pool stop is refused the same way.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 08:34:55 +03:00
catborise
ef1faf57c8 fix(storages): an unexpected ISO upload failure is logged
The upload view sent the error of an unexpected failure to the browser
but left nothing in the server log, so whoever runs the server had no
trace of it. It is logged with its traceback now; the superuser still
sees the message.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 21:43:56 +03:00
catborise
56b4b03500 feat(storages): an ISO upload is a job
The upload session lives in a job instead of flocks and .meta/.done
files; the job panel shows and cancels it; an upload idle for an hour is
ended and its partial file deleted; the page no longer reloads after an
upload.
2026-10-16 11:53:59 +03:00
catborise
49232c6e1d feat(storages): volume clone runs as a job 2026-10-15 09:28:43 +03:00
catborise
68812ddbdf refactor(computes): the lock helpers take claims instead of file locks 2026-10-14 23:27:57 +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
e84db7542d fix(appsettings,vrtManager,storages): error handlers that hid the real failure
Reviewing the error handlers outside instances/ turned up three that masked or
swallowed the failure they caught:

- appsettings/settings.get_settings() runs on every request (middleware) and
  loads app_settings from the database. Its bare `except: pass` left `entries`
  unbound on a database error, so the next line raised UnboundLocalError
  instead; it also caught KeyboardInterrupt/SystemExit. It now catches
  DatabaseError and returns, keeping the already-loaded values.
- vrtManager.network.refresh_dhcp_leases raised a formatted string
  (`raise f"..."`), which Python rejects with TypeError, hiding the real
  DHCPLeases failure. It now raises util.OperationError, which the API/HTML
  error handling already renders as a libvirt error, and clears self.leases.
- storages.views.get_volumes caught libvirtError and answered 200 with an empty
  body, so the caller could not tell a failed pool read from an empty pool. It
  now returns 400 with the error.

The other broad handlers reviewed (appsettings/nwfilters/virtsecrets views,
storages/upload cleanup and recovery paths, vrtManager display getters) report
the error or are best-effort and were left as they are.

Tests: get_settings() survives a database error during the query and during
iteration without raising and still loads a real value; refresh_dhcp_leases
raises OperationError (keeping the cause) not TypeError; get_volumes returns 400
on a listing failure and the sorted volumes on success. The tests fail on the
previous code.
2026-10-07 11:29:45 +03:00
catborise
b04f656d2b ci: replace super-linter with ruff
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.
2026-10-04 01:08:11 +03:00
catborise
4546653b5a fix: serve JSON endpoints as application/json and build DOM safely
Several views returned json.dumps() output through HttpResponse, i.e. as
text/html, and guess_mac_address reflects the URL's vname into it
(reflected XSS). Templates filled the log table and volume dropdowns by
concatenating server data into HTML strings, and log messages contain
user-entered snapshot/disk/clone names (stored XSS that runs when a
superuser opens the Logs tab).

- Use JsonResponse in guess_mac_address, random_mac_address,
  guess_clone_name, sshkeys, storages.get_volumes,
  datasource.os_metadata_json and logs.vm_logs; sshkeys?plain=true is
  served as text/plain.
- stats_tab.html builds log rows with .text(); instance.html and
  create_instance_w2.html build <option> elements with .val().text().
2026-10-02 18:29:11 +03:00
catborise
2441b21c0c feat(storage): support resilient ISO uploads across connection types 2026-09-28 14:57:31 +03:00
catborise
5e240236c3 feat(security): harden storage uploads and vrtManager snapshot XML handling 2026-09-27 13:28:17 +03:00
hudeng
326579a6ea feat: Add ISO file upload progress support. 2025-07-17 17:11:30 +08: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
62d4cf88ba fix upload iso method 2021-12-17 09:21:42 +03:00
catborise
c77e049e82 add rbd support for add new/existing vol. create from rbd based flavor 2021-12-16 11:03:03 +03:00
catborise
f690d1fa60 handle security concerns with file uploading 2021-12-06 08:42:50 +03:00
catborise
4d21a3184b fix: please wait dialog. 2021-10-04 16:18:36 +03:00
catborise
508e3609be lint with black python. convert f style strings to old one. some small fixes 2020-11-05 12:34:31 +03:00
Real-Gecko
01043ba8a8 Templates cleanup 2020-10-15 20:18:45 +06:00
Real-Gecko
1b3fd9d05e replaced ugettext_lazy with gettext_lazy 2020-10-14 18:27:57 +06:00
Real-Gecko
47009d47ca Instances overhaul 2020-07-13 15:33:09 +06:00
catborise
e97d592e51 fix some messages, add translation for some keywords, update tr locale file 2020-06-12 14:46:17 +03:00
catborise
e46bb99b3b fix typos and rearrange imports & add new lines EOF 2020-06-04 15:22:55 +03:00
catborise
7538ddab4f Add all settings to appsettings page & Convert settings choices 2020-06-04 12:32:00 +03:00
catborise
22cb8f702a fix code conventions for pylint 2020-06-04 08:48:43 +03:00
Real-Gecko
27f62dff6c Added admin application
- Manage users
- Manage groups
- Manage logs
2020-05-27 18:24:06 +06:00
Real-Gecko
38befa4362 Added django-login-required-middleware
Thus eliminating need for login_requred decorator on every view
2020-05-27 12:43:29 +06:00
catborise
4d40de1b55 Python3 & Django 2.2 Migration - Fix & Updates 2020-03-16 16:59:45 +03:00
catborise
1c9c717f67 fix indentation. fix imports and description. 2020-01-24 14:30:37 +03:00
catborise
3a925af3c2 fix connection undefined error while getting volumes 2019-12-13 16:38:21 +03:00
catborise
828a271789 pep8 style code corrections 2019-09-10 09:48:31 +03:00
catborise
3a15b49796 Fix image clone/add logs 2019-04-29 14:10:54 +03:00
catborise
2dc83f39a2 Check media before adding new/existing volume 2019-02-14 16:49:12 +03:00
catborise
fc3f04c244 Add pool refresh before getting list of volumes 2018-12-18 10:50:42 +03:00
catborise
91f01d884b add get_volumes function to view. And Remove unused 'get' artifact. 2018-11-16 16:04:26 +03:00
catborise
03ffa3a295 move add new disk to instance disk tab. add existing disk option to attach disk. Small typo fixes 2018-10-24 12:04:05 +03:00
catborise
ba212971fa success message converted to translate ready 2018-09-26 17:18:30 +03:00
catborise
f7d2d24d0b message.success fix - (request was missing) 2018-09-26 16:19:32 +03:00