As the storage pages; reviewed with Codex.
- The list is a card per network: its name with Active or Stopped and
Autostart badges, its type (network_mode: Isolated, NAT, Routed,
Open, Bridge, Macvtap, SR-IOV), its device, and each address with
its DHCP range; a bridge or macvtap network's addresses come from
the outside network.
- A network's page: its heading starts or stops it, the menu sets
autostart and deletes a stopped one. A Network card tells its state,
type, bridge or interface, MAC and what the type does; a card per
address (every <ip>, each with its DHCP range dialog, which libvirt
takes on a stopped network); its fixed addresses of every subnet in
one table, searched, each with Edit and Delete, one dialog adding
and editing them; the VMs whose definition names it, connected or
configured, linked (wvmNetwork.get_vms, one domain listing, a VM
undefined meanwhile left out); its
bandwidth limits where libvirt sets them (not on macvtap or SR-IOV
networks), in KiB/s, from the saved definition with a note that a
running network takes them when restarted; its XML in an accordion.
The page reads the running and the saved definition once each, and
only to render itself: its actions, which all redirect, read nothing
of it first.
- The New network dialog is one form, as the New pool one: the type
as radio cards (the radio_card.html include, now shared by both),
the chosen type's fields only, IPv6 with its box, a bridge or
interface suggested from the host's (get_host_interfaces, not the
bridges libvirt made for its own networks); a refused network or
one libvirt refuses opens the dialog again with what was entered,
the reasons beside the fields and focus on the first.
- What the New pool and New network dialogs share is one script,
static/js/choice_dialog.js: the radio cards show their fieldsets
(data-kinds) and a refused form opens again focused on its first
refused field; each dialog keeps only its own changes.
- The fixed-address dialogs per family go to the page's own dialog.
Reviewed with Codex against libvirt's network format and driver.
- Addresses: wvmNetwork found a network's <ip> by its text, so one
written as <ip .../> or <ip><dhcp>... without whitespace had none,
and a second address of a family overwrote the first. ip_networks
reads every <ip> in order, its index being libvirt's parentIndex:
family (ipv4 when written), address, subnet, DHCP (a <dhcp>, also
with fixed addresses only), first range and fixed addresses. The
parentIndex was guessed from the number of families, wrong when IPv6
comes first; changes now name the address by its index.
- One read: the page read the network's XML once per getter, ten or
more round trips; it reads it once (a cached_property of the
request's wvmNetwork). A change starts from the saved definition
read anew (VIR_NETWORK_XML_INACTIVE), not the running one: two QoS
changes on a running network no longer undo the first. The XML
editor shows and changes the saved definition, and defines this
network only (its name, and its UUID if given), read for that with
no entity expanded and handed to libvirt as written; an XML declaring
its encoding is taken. The actions go back to the network's page by
its own URL.
- Fixed addresses are found by the address they had (a hidden field),
not by the editable box: changing it and pressing Delete deleted
another entry or none. A change deletes the entry and adds it anew
from a copy, keeping what the page does not show (a client id, a
lease), and puts it back if the add fails: libvirt's own change
finds an entry by any of its MAC, address or name, so it could
replace another entry, and never by an IPv6 DUID. The address must
be of the subnet, not the host's, and neither it, the MAC or DUID
nor the name another entry's; an entry gone meanwhile is refused,
not added anew; an unchanged one writes no audit row. They can be
added while the network is stopped; a running network saved with
other addresses than it runs with is not changed live, as
parentIndex would name another <ip> of it.
- An address without a netmask or prefix takes libvirt's (IPv4 its
class's, IPv6 /64), for its checks and the overlap check.
- The DHCP range must be in the subnet, in order and not take in the
host's address.
- The create form takes a known mode only ("bogus" made an isolated
network, a missing one a server error); NAT and routed networks need
an IPv4 subnet, an isolated one may have none, a bridge or macvtap
network needs its bridge or interface and gets no addresses; IPv6
only with its box (whose value was "false", so never); no name or
subnet of another network of the host. "Fixed Addresses" at create
goes: it made a random-MAC entry for every address of the range,
for no real VM.
- Refusals of a fixed address, the DHCP range, the XML and a QoS
removal are messages, not server errors.
- The IPv6 forwarding of a bridge or macvtap network is the outside
network's, not ROUTE.
- get_networks_info reads each network's XML once and gives its
autostart and addresses too. Unused can_pxe, DHCP lease helpers,
get_uuid and the per-family range and host getters go.
- A network created with fixed addresses gets one per address of its DHCP
range for any subnet; the old prefix cut assumed a gateway ending in .1
and built addresses such as 10.0.0.1.130. Fixed addresses need a /24 or
smaller subnet.
- A new network that does not start (its subnet is in use) is undefined
again, so the name is free for another try.
- Fixed addresses are changed and deleted on a stopped network too: the
running network is changed only while it runs. A host with only a name
is deleted as defined, not with an empty MAC, shows no "None", and has no
edit button it could not use.
- The create dialog disables the fields it hides, so an IPv6 subnet typed
and then unchecked is not created, and switching from MACVTAP back to
BRIDGE restores the bridge label and the Open vSwitch option.
- Isolated networks show QoS; QoS save buttons no longer raise a script
error; saving an unchanged fixed address says so; two messages lose a
stray backslash and spaces.
On a running network the change did nothing, yet the page said the
range was changed; a network without a range or an unknown address
family ended in a server error. Each is refused now with the reason:
stop the network first, or the network has no such range.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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>
A network's QoS form whose rate was not a whole number (abc, 1.5) made
wvmNetwork.set_qos raise a ValueError that the view did not catch: the
request ended in a server error. The page's pattern stops this in a
browser, but the server must refuse it too. set_qos now says "QoS rates
must be whole numbers", and the view reports that, as it does a libvirt
error, and goes back to the network's page.
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.
Four lookups built XPath expressions from values that come from
requests (CodeQL py/xpath-injection, plus get_capabilities, which
CodeQL did not flag; the pages are for superusers):
- The architecture in the create wizard's URLs went into
arch[@name='...'] in get_emulator, get_machine_types and
get_capabilities: "nope' or '1'='1" matched every architecture. It is
now an XPath variable ($arch), which is never parsed as XPath.
- Network filter rules were found with a predicate built from the
posted action, direction and priority: a quote raised SyntaxError (an
error page). The rule is now found by comparing its attributes.
- unset_qos put the posted direction into the path, so "*" removed
every bandwidth setting. It accepts inbound and outbound, as set_qos
does; the network page shows an error for anything else.
No other XPath in vrtManager is built from a value; the remaining
expressions are constants. The tests fail on the previous code.
- Migrate network_size and wvmNetwork IP methods to Python built-in ipaddress
- Remove obsolete vendored vrtManager/IPy.py (1650+ lines)
- Add comprehensive unit test suite in vrtManager/test_network_ip.py (15 tests)
- Clean up obsolete IPy exclusion in .travis.yml
* 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>