1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/networks/views.py
catborise 09d7b0c08a fix(networks): fixed addresses, failed creates and stopped networks behave
- 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.
2026-10-26 15:36:57 +03:00

296 lines
12 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 django.utils.translation import gettext_lazy as _
from libvirt import libvirtError
from logs.audit import audit, failed
from vrtManager.network import network_size, wvmNetwork, wvmNetworks
from networks.forms import AddNetPool
@superuser_only
def networks(request, compute_id):
"""
:param request:
:param compute_id:
:return:
"""
compute = get_object_or_404(Compute, pk=compute_id)
errors = False
try:
conn = wvmNetworks(
compute.hostname,
compute.login,
compute.password,
compute.type,
)
networks = conn.get_networks_info()
dhcp4 = netmask4 = gateway4 = ""
dhcp6 = prefix6 = gateway6 = ""
ipv4 = ipv6 = False
if request.method == "POST":
if "create" in request.POST:
form = AddNetPool(request.POST)
if form.is_valid():
data = form.cleaned_data
if data["name"] in [net["name"] for net in networks]:
msg = _("Network pool name already in use")
messages.error(request, msg)
failed(request, compute, f"Network {data['name']}", "add", "name already in use")
errors = True
if (
data["forward"] in ["bridge", "macvtap"]
and data["bridge_name"] == ""
):
messages.error(request, _("Please enter bridge/dev name"))
errors = True
if data["subnet"]:
ipv4 = True
gateway4, netmask4, dhcp4 = network_size(
data["subnet"], data["dhcp4"]
)
if data["subnet6"]:
ipv6 = True
gateway6, prefix6, dhcp6 = network_size(
data["subnet6"], data["dhcp6"]
)
if not errors:
with audit(request, compute, f"Network {data['name']}", "add"):
conn.create_network(
data["name"],
data["forward"],
ipv4,
gateway4,
netmask4,
dhcp4,
ipv6,
gateway6,
prefix6,
dhcp6,
data["bridge_name"],
data["openvswitch"],
data["fixed"],
)
return HttpResponseRedirect(
reverse("network", args=[compute_id, data["name"]])
)
else:
for msg_err in form.errors.values():
messages.error(request, msg_err.as_text())
conn.close()
except libvirtError as lib_err:
messages.error(request, lib_err)
return render(request, "networks.html", locals())
@superuser_only
def network(request, compute_id, pool):
"""
:param request:
:param compute_id:
:param pool:
:return:
"""
compute = get_object_or_404(Compute, pk=compute_id)
try:
conn = wvmNetwork(
compute.hostname,
compute.login,
compute.password,
compute.type,
pool,
)
networks = conn.get_networks()
state = conn.is_active()
device = conn.get_bridge_device()
autostart = conn.get_autostart()
net_mac = conn.get_network_mac()
net_forward = conn.get_network_forward()
qos = conn.get_qos()
dhcp_range_start = ipv4_dhcp_range_end = dict()
ip_networks = conn.get_ip_networks()
for family, ip_network in ip_networks.items():
if family == "ipv4":
ipv4_dhcp_range_start = conn.get_dhcp_range_start(family)
ipv4_dhcp_range_end = conn.get_dhcp_range_end(family)
ipv4_network = ip_network
ipv4_fixed_address = conn.get_dhcp_host_addr(family)
elif family == "ipv6":
ipv6_dhcp_range_start = conn.get_dhcp_range_start(family)
ipv6_dhcp_range_end = conn.get_dhcp_range_end(family)
ipv6_network = ip_network
ipv6_fixed_address = conn.get_dhcp_host_addr(family)
else:
raise Exception(_("Unknown Network Family"))
xml = conn._XMLDesc(0)
except libvirtError as lib_err:
messages.error(request, lib_err)
return HttpResponseRedirect(reverse("networks", args=[compute_id]))
if request.method == "POST":
subject = f"Network {pool}"
if "start" in request.POST:
try:
with audit(request, compute, subject, "start"):
conn.start()
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
if "stop" in request.POST:
try:
with audit(request, compute, subject, "stop"):
conn.stop()
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
if "delete" in request.POST:
try:
with audit(request, compute, subject, "delete"):
conn.delete()
return HttpResponseRedirect(reverse("networks", args=[compute_id]))
except libvirtError as lib_err:
messages.error(request, lib_err)
if "set_autostart" in request.POST:
try:
with audit(request, compute, subject, "autostart on"):
conn.set_autostart(1)
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
if "unset_autostart" in request.POST:
try:
with audit(request, compute, subject, "autostart off"):
conn.set_autostart(0)
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
if "modify_fixed_address" in request.POST:
name = request.POST.get("name", "")
address = request.POST.get("address", "")
family = request.POST.get("family", "ipv4")
if family == "ipv4":
mac_duid = request.POST.get("mac", "")
if family == "ipv6":
mac_duid = request.POST.get("id", "")
try:
with audit(request, compute, subject, f"set fixed address {address}"):
changed = conn.modify_fixed_address(name, address, mac_duid, family)
if changed is False:
messages.info(request, _("The fixed address is unchanged"))
else:
messages.success(
request,
_("Fixed address operation completed for %(family)s")
% {"family": family.upper()},
)
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
except ValueError as val_err:
messages.error(request, val_err)
if "delete_fixed_address" in request.POST:
ip = request.POST.get("address", "")
family = request.POST.get("family", "ipv4")
with audit(request, compute, subject, f"delete fixed address {ip}"):
conn.delete_fixed_address(ip, family)
messages.success(
request,
_("%(family)s Fixed Address is Deleted.") % {"family": family.upper()},
)
return HttpResponseRedirect(request.get_full_path())
if "modify_dhcp_range" in request.POST:
range_start = request.POST.get("range_start", "")
range_end = request.POST.get("range_end", "")
family = request.POST.get("family", "ipv4")
try:
with audit(request, compute, subject, f"set DHCP range {family.upper()}"):
conn.modify_dhcp_range(range_start, range_end, family)
messages.success(
request,
_("%(family)s DHCP Range is Changed.") % {"family": family.upper()},
)
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
if "edit_network" in request.POST:
edit_xml = request.POST.get("edit_xml", "")
if edit_xml:
with audit(request, compute, subject, "change XML"):
conn.edit_network(edit_xml)
if conn.is_active():
messages.success(
request,
_(
"Network XML is changed. "
"Stop and start network to activate new config."
),
)
else:
messages.success(request, _("Network XML is changed."))
return HttpResponseRedirect(request.get_full_path())
if "set_qos" in request.POST:
qos_dir = request.POST.get("qos_direction", "")
average = request.POST.get("qos_average") or 0
peak = request.POST.get("qos_peak") or 0
burst = request.POST.get("qos_burst") or 0
try:
with audit(request, compute, subject, f"set QoS {qos_dir}"):
conn.set_qos(qos_dir, average, peak, burst)
if conn.is_active():
messages.success(
request,
_(
"%(qos_dir)s QoS is updated. Network XML is changed. Stop and start network to activate new config"
)
% {"qos_dir": qos_dir.capitalize()},
)
else:
messages.success(
request,
_("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()},
)
except (libvirtError, ValueError) as err:
messages.error(request, err)
return HttpResponseRedirect(request.get_full_path())
if "unset_qos" in request.POST:
qos_dir = request.POST.get("qos_direction", "")
try:
with audit(request, compute, subject, f"unset QoS {qos_dir}"):
conn.unset_qos(qos_dir)
except ValueError as err:
messages.error(request, err)
return HttpResponseRedirect(request.get_full_path())
if conn.is_active():
messages.success(
request,
_(
"%(qos_dir)s QoS is deleted. Network XML is changed. "
"Stop and start network to activate new config"
)
% {"qos_dir": qos_dir.capitalize()},
)
else:
messages.success(
request,
_("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()},
)
return HttpResponseRedirect(request.get_full_path())
conn.close()
return render(request, "network.html", locals())