1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 12:46:49 +00:00
webvirtcloud/nwfilters/views.py
catborise bc2b70544a fix(nwfilters): a filter in use is not deleted, and a change replaces no other filter
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.
2026-10-29 10:10:17 +03:00

95 lines
4.5 KiB
Python

from admin.decorators import superuser_only
from computes.models import Compute
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from libvirt import libvirtError
from logs.audit import audit
from vrtManager import util
from vrtManager.nwfilters import wvmNWFilter, wvmNWFilters
@superuser_only
def nwfilters(request, compute_id):
"""The host's network filters; one created, cloned or deleted, after
which the list is read again."""
compute = get_object_or_404(Compute, pk=compute_id)
nwfilters_all = []
try:
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
if request.method == "POST":
name = request.POST.get("nwfiltername", "")
if "create_nwfilter" in request.POST:
xml = request.POST.get("nwfilter_xml", "")
try: # the row names the filter where the XML does
new_name = util.parse_xml(xml).get("name")
except util.OperationError:
new_name = None
with audit(request, compute, f"Network filter {new_name or '(no name)'}", "add"):
conn.create_nwfilter(xml)
elif "cln_nwfilter" in request.POST:
clone_name = request.POST.get("cln_name", "")
with audit(request, compute, f"Network filter {name}", f"clone as {clone_name}"):
conn.clone_nwfilter(name, clone_name)
elif "del_nwfilter" in request.POST:
with audit(request, compute, f"Network filter {name}", "delete"):
conn.delete_nwfilter(name)
return HttpResponseRedirect(request.get_full_path())
nwfilters_all = conn.get_nwfilters_info()
except libvirtError as lib_err: # OperationError too: a name in use, a filter in use
messages.error(request, lib_err)
if request.method == "POST": # a host not reached as well: nothing was changed
return HttpResponseRedirect(request.get_full_path())
return render(request, "nwfilters.html", {"nwfilters": nwfilters_all, "compute": compute})
@superuser_only
def nwfilter(request, compute_id, nwfltr):
"""A network filter of the host: its rules and references changed one at
a time, or its XML as a whole."""
compute = get_object_or_404(Compute, pk=compute_id)
try:
nwfilter = wvmNWFilter(compute.hostname, compute.login, compute.password, compute.type, nwfltr)
if request.method == "POST":
post = request.POST
subject = f"Network filter {nwfltr}"
try:
if "edit_nwfilter" in post:
with audit(request, compute, subject, "change XML"):
nwfilter.edit(post.get("edit_xml", ""))
elif "add_nwfilter_rule" in post:
with audit(request, compute, subject, "add rule"):
nwfilter.add_rule(post.get("nwfilterrule_xml", ""))
elif "del_nwfilter_rule" in post:
with audit(request, compute, subject, "delete rule"):
nwfilter.delete_rule(post.get("index", ""), post.get("rule", ""))
elif "add_nwfilter_ref" in post:
ref_name = post.get("nwfilters_select", "")
with audit(request, compute, subject, f"add reference {ref_name}"):
nwfilter.add_ref(ref_name)
elif "del_nwfilter_ref" in post:
with audit(request, compute, subject, "delete reference") as entry:
entry.action = f"delete reference {nwfilter.delete_ref(post.get('index', ''), post.get('ref', ''))}"
except libvirtError as err: # OperationError too: a filter changed meanwhile, XML refused
messages.error(request, err)
return HttpResponseRedirect(request.get_full_path())
name = nwfilter.get_name()
uuid = nwfilter.get_uuid()
xml = nwfilter.get_xml()
rules = nwfilter.get_rules()
refs = nwfilter.get_refs()
ref_choices = nwfilter.get_ref_choices()
except libvirtError as lib_err:
messages.error(request, lib_err)
if request.method == "POST": # a filter gone meanwhile, a host not reached: nothing was changed
return HttpResponseRedirect(reverse("nwfilters", args=[compute_id]))
return render(request, "nwfilter.html", locals())