1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/interfaces/views.py
catborise d1fb9bd2d4 fix(console,computes): an unreachable host is named as the cause, not an empty list
The console page of a VM whose host does not answer said "Fail to get
console. Please check the console configuration of your VM." and logged
nothing. It now shows the connection error (to users who do not see the
hosts, that the host cannot be reached) and logs it with the VM and host.

A host's Storage, Networks, Interfaces, Filters and Secrets pages showed
the connection error and also "This host has no ...". The list is None
when it was not read, and the page shows only the error.
2026-11-06 23:08:11 +03:00

117 lines
5.7 KiB
Python

from django.contrib import messages
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from libvirt import libvirtError
from computes.models import Compute
from instances.models import Instance
from interfaces.forms import AddInterface
from logs.audit import audit
from vrtManager.interface import networks_by_device, wvmInterface, wvmInterfaces
from admin.decorators import superuser_only
@superuser_only
def interfaces(request, compute_id):
"""The host's interfaces, and a new one where its libvirt can define them."""
compute = get_object_or_404(Compute, pk=compute_id)
ifaces_all = None # not read: the page shows no list
try:
conn = wvmInterfaces(compute.hostname, compute.login, compute.password, compute.type)
ifaces_all = conn.get_ifaces_info()
defined_names = [iface["name"] for iface in ifaces_all]
changeable = conn.can_change_interfaces()
used_by = networks_by_device(conn.wvm)
for iface in ifaces_all:
iface["networks"] = used_by.get(iface["name"], [])
# the list by type, in libvirt's four, a type the host has none of left out
iface_groups = [(title, [iface for iface in ifaces_all if iface["type"] == kind])
for kind, title in (("bridge", _("Bridges")), ("bond", _("Bonds")),
("vlan", _("VLANs")), ("ethernet", _("Ethernet")))]
form = AddInterface()
# the new interface dialog's type: the one sent back after a refusal
if_kind = request.POST.get("itype", "bridge")
# the host's devices are only the create form's choices
netdevs, members, netdev_error = [], [], None
if changeable:
try:
netdevs = conn.get_net_devices()
members = conn.get_member_candidates(netdevs)
ethernet_devices = [dev for dev in members if dev not in defined_names]
except Exception as err: # a host without the node device driver too
netdev_error = err
messages.error(request, _("The network devices of this host could not be read: %(error)s") % {"error": err})
# the page says why nothing is created on a host that cannot change
# interfaces; without the host's devices nothing can be checked
if request.method == "POST" and "create" in request.POST and changeable and netdev_error is None:
form = AddInterface(request.POST, netdevs=netdevs, members=members,
defined=defined_names)
if form.is_valid():
data = form.cleaned_data
try:
with audit(request, compute, f"Interface {data['name']}", "add"):
conn.create_iface(
data["name"], data["itype"], data["start_mode"], data["netdev"],
data["ipv4_type"], data["ipv4_addr"], data["ipv4_gw"],
data["ipv6_type"], data["ipv6_addr"], data["ipv6_gw"],
data["stp"], data["delay"],
)
except libvirtError as err: # shown in the dialog, which opens again
form.add_error(None, str(err))
else:
return HttpResponseRedirect(reverse("interface", args=[compute_id, data["name"]]))
conn.close()
except libvirtError as lib_err:
messages.error(request, lib_err)
return render(request, "interfaces.html", locals())
@superuser_only
def interface(request, compute_id, iface):
"""An interface of the host; started, stopped or deleted where the host's libvirt can."""
compute = get_object_or_404(Compute, pk=compute_id)
try:
conn = wvmInterface(compute.hostname, compute.login, compute.password, compute.type, iface)
changeable = conn.can_change_interfaces()
# the page says why nothing is done on a host that cannot change interfaces
if request.method == "POST" and changeable:
here = reverse("interface", args=[compute_id, iface])
subject = f"Interface {iface}"
try:
if "stop" in request.POST:
with audit(request, compute, subject, "stop"):
conn.stop_iface()
return HttpResponseRedirect(here)
if "start" in request.POST:
with audit(request, compute, subject, "start"):
conn.start_iface()
return HttpResponseRedirect(here)
if "delete" in request.POST:
with audit(request, compute, subject, "delete"):
conn.delete_iface()
return HttpResponseRedirect(reverse("interfaces", args=[compute_id]))
except libvirtError as err: # OperationError too: an active one, a bridge whose addresses go nowhere
messages.error(request, err)
return HttpResponseRedirect(here)
info = conn.get_info()
info["addressing"] = [("IPv4", info["ipv4"]), ("IPv6", info["ipv6"])]
state = conn.is_active()
networks = networks_by_device(conn.wvm).get(iface, [])
if info["type"] == "bridge":
vms = conn.get_vms(networks)
vm_ids = dict(Instance.objects.filter(compute=compute, name__in=[vm["vm"] for vm in vms]).values_list("name", "id"))
for vm in vms:
vm["id"] = vm_ids.get(vm["vm"])
conn.close()
except libvirtError as lib_err:
messages.error(request, lib_err)
return render(request, "interface.html", locals())