As the network and interface pages; plan reviewed with Codex.
- The list is one table with a search: each filter's chain, priority,
number of rules, the filters it references, and how many VMs and
filters use it directly; a row's menu clones it (one shared dialog,
the copy's name filled in) or deletes it, Delete disabled and saying
so while it is in use. Without the VMs (a host that fails to list
them) the list is not shown: it would offer to delete filters in use.
- New filter is one dialog with the filter as XML in the Ace editor,
from a starter filter, with what in, out and priority mean and a link
to libvirt's format.
- A filter's page: a Filter card (UUID, chain, priority, the VMs that
use it directly, linked, and the filters that reference it, linked);
its references with their parameters (one to a filter gone from the
host marked as missing, not linked), removed per row, added from a
select of the filters it can reference; its rules with the action as
a badge, the direction as to or from the VM, the priority (500 where
none is given), every protocol element with its attributes, a rule
of no protocol as any traffic of the chain, and when it does not
track connections; Add rule as an XML dialog; the XML, collapsed,
saved in place.
- The editors size themselves when shown and keep their label for
screen readers; tables keep their hidden
header text inside them, so a phone does not scroll the page
sideways. add_nwf_rule.html goes (the dialog is on the page).
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.
- Deleting a rule removes the row clicked, by its position, instead of the
first rule with the same action, direction and priority; a filter changed
since the page was read is refused instead of losing another rule.
- An added rule is added as entered, with all its attributes. It was merged
into a rule with the same action, direction and priority, where libvirt
keeps only the first protocol, so the new rule was silently dropped.
- A new filter shows in the list after it is created.
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.
Every change to a filter (a rule or reference removed or added, the XML
edited) undefined it and defined the new XML. libvirt refuses to
undefine a filter a running VM uses, so none of these worked on such a
filter; on an unused one a refused definition was undone by defining
the old XML without its UUID, so the filter came back as another one.
The filter is now defined again with its own UUID, which libvirt does
in place, while VMs use it too; XML it cannot parse or apply to the
running VMs is refused and reported. The XML editor shows the UUID.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Clone:
- only shut-off VMs are cloned, as the UI already required: a running
guest keeps writing while its disks are copied; the definition comes
from the persistent XML;
- MAC addresses and disk destinations are checked before anything is
allocated;
- every volume the clone creates (NVRAM and disks) is tracked; if a
later copy or the definition fails, only those are deleted, and any
that cannot be deleted are named in the error. Before, a failed clone
left its earlier copies behind.
libvirtError(msg) reports the thread's last libvirt error instead of
msg when there is one, so WebVirtCloud's own errors could show an
earlier, unrelated failure. util.OperationError, a libvirtError
subclass that keeps its message, replaces those raises in vrtManager,
instances and nwfilters; 'except libvirtError' still catches it.
- 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).