1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/nwfilters/views.py
catborise 0014b5f240 feat(nwfilters): the network filter pages on Bootstrap's cards, tables and dialogs
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).
2026-10-29 10:10:30 +03:00

107 lines
5.2 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 instances.models import Instance
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())
# the VMs first: a list without them would offer to delete filters in use
users = conn.get_users()
nwfilters_all = conn.get_nwfilters_info()
for nwf in nwfilters_all:
nwf["vms"] = users.get(nwf["name"], [])
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()
chain = nwfilter.tree.get("chain")
priority = nwfilter.tree.get("priority")
rules = nwfilter.get_rules()
refs = nwfilter.get_refs()
ref_choices = nwfilter.get_ref_choices()
filter_names = nwfilter.get_nwfilters()
referenced_by = [nwf["name"] for nwf in nwfilter.get_nwfilters_info() if name in nwf["refs"]]
vm_names = nwfilter.get_users().get(name, [])
vm_ids = dict(Instance.objects.filter(compute=compute, name__in=vm_names).values_list("name", "id"))
vms = [{"name": vm_name, "id": vm_ids.get(vm_name)} for vm_name in vm_names]
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())