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