mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
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.
117 lines
5.7 KiB
Python
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())
|