1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-12-25 23:55:24 +00:00

Add IPv6 support.

This commit is contained in:
catborise 2019-11-07 10:33:36 +03:00
parent 0738ec7ec4
commit c5a96b7662
5 changed files with 391 additions and 128 deletions

View file

@ -1,16 +1,16 @@
{% load i18n %} {% load i18n %}
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<a href="#AddFixedNet" type="button" class="btn btn-success pull-right" data-toggle="modal"> <a href="#AddFixedNet4" type="button" class="btn btn-success pull-right" data-toggle="modal">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
</a> </a>
<!-- Modal pool --> <!-- Modal pool -->
<div class="modal fade" id="AddFixedNet" tabindex="-1" role="dialog" aria-labelledby="AddFixedNetLabel" aria-hidden="true"> <div class="modal fade" id="AddFixedNet4" tabindex="-1" role="dialog" aria-labelledby="AddFixedNet4Label" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">{% trans "Add Fixed Address" %}</h4> <h4 class="modal-title">{% trans "Add IPv4 Fixed Address" %}</h4>
</div> </div>
<form method="post" action="" role="form">{% csrf_token %} <form method="post" action="" role="form">{% csrf_token %}
<div class="modal-body"> <div class="modal-body">
@ -21,10 +21,16 @@
<input type="text" readonly class="form-control" name="subnet" value="{{ ipv4_network }}" required pattern="[0-9\/\.]+"> <input type="text" readonly class="form-control" name="subnet" value="{{ ipv4_network }}" required pattern="[0-9\/\.]+">
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-sm-4 control-label">{% trans "MAC" %}</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="mac" required pattern="[0-9\/\:]+">
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">{% trans "Name" %}</label> <label class="col-sm-4 control-label">{% trans "Name" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="name" required pattern="[a-zA-Z0-9_]+"> <input type="text" class="form-control" name="name" pattern="[a-zA-Z0-9_]+">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -33,15 +39,10 @@
<input type="text" class="form-control" name="address" required pattern="[0-9\/\.]+"> <input type="text" class="form-control" name="address" required pattern="[0-9\/\.]+">
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-sm-4 control-label">{% trans "MAC" %}</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="mac" required pattern="[0-9\/\:]+">
</div>
</div>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<input name="family" value="ipv4" hidden/>
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button> <button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
<button type="submit" class="btn btn-primary" name="modify_fixed_address">{% trans "Create" %}</button> <button type="submit" class="btn btn-primary" name="modify_fixed_address">{% trans "Create" %}</button>
</div> </div>

View file

@ -0,0 +1,53 @@
{% load i18n %}
{% if request.user.is_superuser %}
<a href="#AddFixedNet6" type="button" class="btn btn-success pull-right" data-toggle="modal">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
</a>
<!-- Modal pool -->
<div class="modal fade" id="AddFixedNet6" tabindex="-1" role="dialog" aria-labelledby="AddFixedNet6Label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">{% trans "Add IPV6 Fixed Address" %}</h4>
</div>
<form method="post" action="" role="form">{% csrf_token %}
<div class="modal-body">
<div class="row">
<div class="form-group">
<label class="col-sm-4 control-label">{% trans "Subnet Pool" %}</label>
<div class="col-sm-6">
<input type="text" readonly class="form-control" name="subnet" value="{{ ipv6_network }}" required pattern="[0-9\/\.]+">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">{% trans "ID" %}</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="id" required pattern="[0-9a-dA-D\/\:]+">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">{% trans "Name" %}</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="name" pattern="[a-zA-Z0-9_]+">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">{% trans "Address" %}</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="address" required pattern="[a-dA-D0-9\/\:]+">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<input name="family" value="ipv6" hidden/>
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
<button type="submit" class="btn btn-primary" name="modify_fixed_address">{% trans "Create" %}</button>
</div>
</form>
</div> <!-- /.modal-content -->
</div> <!-- /.modal-dialog -->
</div> <!-- /.modal -->
{% endif %}

View file

@ -68,6 +68,7 @@
</p> </p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<h3 class="page-header"></h3> <h3 class="page-header"></h3>
</div> </div>
@ -93,31 +94,32 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<h3 class="page-header">{% trans "IPv4 Configuration" %}</h3> <h3 class="page-header">{% trans "IPv4 Configuration" %}</h3>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-6 col-sm-4"> <div class="col-xs-6 col-sm-4">
<p>{% trans "IPv4 Forwarding:" %}</p> <p>{% trans "IPv4 Forwarding" %}:</p>
<p>{% trans "Network:" %}</p> <p>{% trans "Network" %}:</p>
<p>{% trans "DHCP:" %}</p>
{% if ipv4_dhcp_range_start and ipv4_dhcp_range_end %} {% if ipv4_dhcp_range_start and ipv4_dhcp_range_end %}
<p>{% trans "Start:" %}</p> <p>{% trans "DHCP" %}:</p>
<p>{% trans "End:" %}</p> <p>{% trans "Start" %}:</p>
<p>{% trans "End" %}:</p>
{% endif %} {% endif %}
</div> </div>
<div class="col-xs-6 col-sm-4"> <div class="col-xs-6 col-sm-4">
<p> <p>
{% ifequal ipv4_forward.0 'nat' %} {% ifequal net_forward.0 'nat' %}
{% trans "NAT" %} {% trans "NAT" %}
{% endifequal %} {% endifequal %}
{% ifequal ipv4_forward.0 'route' %} {% ifequal net_forward.0 'route' %}
{% trans "ROUTE" %} {% trans "ROUTE" %}
{% endifequal %} {% endifequal %}
{% ifequal ipv4_forward.0 'bridge' %} {% ifequal net_forward.0 'bridge' %}
{% trans "BRIDGE" %} {% trans "BRIDGE" %}
{% endifequal %} {% endifequal %}
{% if not ipv4_forward.0 %} {% if not net_forward.0 %}
{% trans "ISOLATE" %} {% trans "ISOLATE" %}
{% endif %} {% endif %}
</p> </p>
@ -137,6 +139,7 @@
{% else %} {% else %}
<p><input name="range_start" value="{{ ipv4_dhcp_range_start }}"/></p> <p><input name="range_start" value="{{ ipv4_dhcp_range_start }}"/></p>
<p><input name="range_end" value="{{ ipv4_dhcp_range_end }}"/></p> <p><input name="range_end" value="{{ ipv4_dhcp_range_end }}"/></p>
<input hidden name="family" value="ipv4"/>
<div class="col-xs-10 col-sm-8"> <div class="col-xs-10 col-sm-8">
<input type="submit" class="btn btn-primary btn-block" value="Apply" <input type="submit" class="btn btn-primary btn-block" value="Apply"
name="modify_dhcp_range" name="modify_dhcp_range"
@ -147,15 +150,15 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% ifequal ipv4_forward.0 'nat' %} {% if ipv4_dhcp_range_start and ipv4_dhcp_range_end %}
{% if state %} {% if state %}
{% include 'modify_fixed_address.html' %} {% include 'modify_ipv4_fixed_address.html' %}
{% endif %} {% endif %}
<div class="row"> <div class="row">
<h3 class="page-header">{% trans "Fixed Address" %}</h3> <h3 class="page-header">{% trans "IPv4 Fixed Address" %}</h3>
</div> </div>
{% endifequal %} {% endif %}
{% if fixed_address %} {% if ipv4_fixed_address %}
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col-xs-12">
<div class="panel-group" id="accordion"> <div class="panel-group" id="accordion">
@ -175,7 +178,7 @@
<input type="button" class="btn btn-default" id="filter_button" value="Filter"> <input type="button" class="btn btn-default" id="filter_button" value="Filter">
<button type="button" class="btn btn-default" id="filter_clear">{% trans 'Clear' %}</button> <button type="button" class="btn btn-default" id="filter_clear">{% trans 'Clear' %}</button>
</div> </div>
<table class="table table-hover"> <table id="ipv4_table" class="table table-hover">
<thead> <thead>
<tr> <tr>
<th style="text-align: center">{% trans "MAC" %}</th> <th style="text-align: center">{% trans "MAC" %}</th>
@ -185,14 +188,132 @@
</tr> </tr>
</thead> </thead>
<tbody style="text-align: center"> <tbody style="text-align: center">
{% for fix in fixed_address %} {% for fix4 in ipv4_fixed_address %}
<tr> <tr>
<form method="post" role="form">{% csrf_token %} <form method="post" role="form">{% csrf_token %}
<td><label class="form-control" disabled="true">{{ fix.mac }}</label></td> <td><input class="form-control" value="{{ fix4.mac }}" name="mac" readonly/></td>
<td><input class="form-control" value="{{ fix.ip }}" name="address" /></td> <td><input class="form-control" value="{{ fix4.ip }}" name="address" /></td>
<td><input class="form-control" value="{{ fix.name }}" name="name" /></td> <td><input class="form-control" value="{{ fix4.name }}" name="name" /></td>
<td> <td>
<input hidden name="mac" value="{{ fix.mac }}"/> <input hidden name="family" value="ipv4"/>
<button type="submit" class="btn btn-sm btn-primary"
name="modify_fixed_address"
title="Edit entry" onclick="return confirm('{% trans "Are you sure?" %}')">
<i class="glyphicon glyphicon-save"></i>
</button>
<button type="submit" class="btn btn-sm btn-danger"
name="delete_fixed_address"
title="Delete entry" onclick="return confirm('{% trans "Are you sure?" %}')">
<i class="glyphicon glyphicon-trash"></i>
</button>
</td>
</form>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endif %}
<div class="row">
<h3 class="page-header">{% trans "IPv6 Configuration" %}</h3>
</div>
<div class="row">
<div class="col-xs-6 col-sm-4">
<p>{% trans "IPv6 Forwarding" %}:</p>
<p>{% trans "Network" %}:</p>
{% if ipv6_dhcp_range_start and ipv6_dhcp_range_end %}
<p>{% trans "DHCP" %}:</p>
<p>{% trans "Start" %}:</p>
<p>{% trans "End" %}:</p>
{% endif %}
</div>
<div class="col-xs-6 col-sm-4">
<p>
{% if not net_forward.0 %}
{% trans "ISOLATE" %}
{% else %}
{% trans "ROUTE" %}
{% endif %}
</p>
<p>{{ ipv6_network }}</p>
<p>
{% if ipv6_dhcp_range_start and ipv6_dhcp_range_end %}
<span class="text-success">{% trans "ON" %}</span>
{% else %}
<span class="text-danger">{% trans "OFF" %}</span>
{% endif %}
</p>
{% if ipv6_dhcp_range_start and ipv6_dhcp_range_end %}
<form method="post" role="form">{% csrf_token %}
{% if state %}
<p>{{ ipv6_dhcp_range_start }}</p>
<p>{{ ipv6_dhcp_range_end }}</p>
{% else %}
<p><input name="range_start" value="{{ ipv6_dhcp_range_start }}"/></p>
<p><input name="range_end" value="{{ ipv6_dhcp_range_end }}"/></p>
<input hidden name="family" value="ipv6"/>
<div class="col-xs-10 col-sm-8">
<input type="submit" class="btn btn-primary btn-block" value="Apply"
name="modify_dhcp_range"
title="Edit DHCP Range" onclick="return confirm('{% trans "Are you sure?" %}')"/>
</div>
{% endif %}
</form>
{% endif %}
</div>
</div>
{% if ipv6_dhcp_range_start and ipv6_dhcp_range_end %}
{% if state %}
{% include 'modify_ipv6_fixed_address.html' %}
{% endif %}
<div class="row">
<h3 class="page-header">{% trans "IPv6 Fixed Address" %}</h3>
</div>
{% endif %}
{% if ipv6_fixed_address %}
<div class="row">
<div class="col-xs-12">
<div class="panel-group" id="accordion">
<div class="panel panel-default">
<div class="panel-heading">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseIPv6">
{% trans 'Show' %}
</a>
</div>
<div id="collapseIPv6" class="panel-collapse collapse">
<div class="panel-body">
<div class="input-append form-inline pull-right">
<div class="form-group">
<input type="text" class="form-control" id="filter_input_ipv6">
</div>
<input type="button" class="btn btn-default" id="filter_button_ipv6" value="Filter">
<button type="button" class="btn btn-default" id="filter_clear_ipv6">{% trans 'Clear' %}</button>
</div>
<table id="ipv6_table" class="table table-hover">
<thead>
<tr>
<th style="text-align: center">{% trans "ID" %}</th>
<th style="text-align: center">{% trans "Address" %}</th>
<th style="text-align: center">{% trans "Name" %}</th>
<th style="text-align: center">{% trans "Action" %}</th>
</tr>
</thead>
<tbody style="text-align: center">
{% for fix6 in ipv6_fixed_address %}
<tr>
<form method="post" role="form">{% csrf_token %}
<td><input class="form-control" value="{{ fix6.id }}" name="id" readonly/></td>
<td><input class="form-control" value="{{ fix6.ip }}" name="address" /></td>
<td><input class="form-control" value="{{ fix6.name }}" name="name" /></td>
<td>
<input hidden name="family" value="ipv6"/>
<button type="submit" class="btn btn-sm btn-primary" <button type="submit" class="btn btn-sm btn-primary"
name="modify_fixed_address" name="modify_fixed_address"
title="Edit entry" onclick="return confirm('{% trans "Are you sure?" %}')"> title="Edit entry" onclick="return confirm('{% trans "Are you sure?" %}')">
@ -229,15 +350,17 @@
// add event button labeled "filter" // add event button labeled "filter"
$('#filter_button').click(function (event) { $('#filter_button').click(function (event) {
// get value // get value
var filter_val = $('#filter_input').val(); let filter_val = $('#filter_input').val();
if (filter_val == '') { if (filter_val == '') {
// show all // show all
$('tbody tr').show(); $('#ipv4_table tbody tr').show();
} else { } else {
// show only matches
$('tbody tr:Contains(\'' + filter_val + '\')').show();
// hide non-matching items // hide non-matching items
$('tbody tr:not(:Contains(\'' + filter_val + '\'))').hide(); let row_not_contains4 = $('#ipv4_table tbody tr input:not([value*=\'' + filter_val + '\'])');
row_not_contains4.closest('tr').hide();
// show only matches
let row_contains4 = $('#ipv4_table tbody tr input[value*=\'' + filter_val + '\']');
row_contains4.closest('tr').show();
} }
}); });
// add event button labeled "clear" // add event button labeled "clear"
@ -252,6 +375,35 @@
$('#filter_button').click(); $('#filter_button').click();
} }
}); });
// add event button labeled "filter"
$('#filter_button_ipv6').click(function (event) {
// get value
let filter_val = $('#filter_input_ipv6').val();
if (filter_val == '') {
// show all
$('#ipv6_table tbody tr').show();
} else {
// hide non-matching items
let row_not_contains6 = $('#ipv6_table tbody tr input:not([value*=\'' + filter_val + '\'])');
row_not_contains6.closest('tr').hide();
// show only matches
let row_contains6 = $('#ipv6_table tbody tr input[value*=\'' + filter_val + '\']');
row_contains6.closest('tr').show();
}
});
// add event button labeled "clear"
$('#filter_clear_ipv6').click(function (event) {
$('#filter_input_ipv6').val('');
$('#filter_button_ipv6').click();
});
// trigger filter when enter key pressed
$('#filter_input_ipv6').keyup(function (event) {
if (event.keyCode == 13) {
$('#filter_button_ipv6').click();
}
});
}); });
</script> </script>
<script src="{% static "js/ace.js" %}"></script> <script src="{% static "js/ace.js" %}"></script>

View file

@ -86,11 +86,24 @@ def network(request, compute_id, pool):
state = conn.is_active() state = conn.is_active()
device = conn.get_bridge_device() device = conn.get_bridge_device()
autostart = conn.get_autostart() autostart = conn.get_autostart()
ipv4_forward = conn.get_ipv4_forward() net_forward = conn.get_network_forward()
ipv4_dhcp_range_start = conn.get_ipv4_dhcp_range_start() dhcp_range_start = ipv4_dhcp_range_end = dict()
ipv4_dhcp_range_end = conn.get_ipv4_dhcp_range_end()
ipv4_network = conn.get_ipv4_network() ip_networks = conn.get_ip_networks()
fixed_address = conn.get_mac_ipaddr() 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) xml = conn._XMLDesc(0)
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err) error_messages.append(lib_err)
@ -130,26 +143,34 @@ def network(request, compute_id, pool):
if 'modify_fixed_address' in request.POST: if 'modify_fixed_address' in request.POST:
name = request.POST.get('name', '') name = request.POST.get('name', '')
address = request.POST.get('address', '') address = request.POST.get('address', '')
mac = request.POST.get('mac', '') 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: try:
ret_val = conn.modify_fixed_address(name, address, mac) ret_val = conn.modify_fixed_address(name, address, mac_duid, family)
messages.success(request, "Fixed Address Operation Completed.") messages.success(request, "{} Fixed Address Operation Completed.".format(family))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err.message) error_messages.append(lib_err.message)
except ValueError as val_err: except ValueError as val_err:
error_messages.append(val_err.message) error_messages.append(val_err.message)
if 'delete_fixed_address' in request.POST: if 'delete_fixed_address' in request.POST:
mac = request.POST.get('mac', '') ip = request.POST.get('address', '')
conn.delete_fixed_address(mac) family = request.POST.get('family', 'ipv4')
messages.success(request, "Fixed Address is Deleted.") conn.delete_fixed_address(ip, family)
messages.success(request, "{} Fixed Address is Deleted.".format(family))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'modify_dhcp_range' in request.POST: if 'modify_dhcp_range' in request.POST:
range_start = request.POST.get('range_start', '') range_start = request.POST.get('range_start', '')
range_end = request.POST.get('range_end', '') range_end = request.POST.get('range_end', '')
family = request.POST.get('family', 'ipv4')
try: try:
conn.modify_dhcp_range(range_start, range_end) conn.modify_dhcp_range(range_start, range_end, family)
messages.success(request, "DHCP Range is Changed.") messages.success(request, "{} DHCP Range is Changed.".format(family))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err.message) error_messages.append(lib_err.message)

View file

@ -1,7 +1,7 @@
from vrtManager import util from vrtManager import util
from vrtManager.IPy import IP from vrtManager.IPy import IP
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from xml.etree import ElementTree from lxml import etree
from libvirt import VIR_NETWORK_SECTION_IP_DHCP_HOST from libvirt import VIR_NETWORK_SECTION_IP_DHCP_HOST
from libvirt import VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_UPDATE_COMMAND_MODIFY from libvirt import VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_UPDATE_COMMAND_MODIFY
from libvirt import VIR_NETWORK_UPDATE_AFFECT_LIVE, VIR_NETWORK_UPDATE_AFFECT_CONFIG from libvirt import VIR_NETWORK_UPDATE_AFFECT_LIVE, VIR_NETWORK_UPDATE_AFFECT_CONFIG
@ -77,6 +77,7 @@ class wvmNetwork(wvmConnect):
def __init__(self, host, login, passwd, conn, net): def __init__(self, host, login, passwd, conn, net):
wvmConnect.__init__(self, host, login, passwd, conn) wvmConnect.__init__(self, host, login, passwd, conn)
self.net = self.get_network(net) self.net = self.get_network(net)
self.parent_count = len(self.get_ip_networks())
def get_name(self): def get_name(self):
return self.net.name() return self.net.name()
@ -111,128 +112,163 @@ class wvmNetwork(wvmConnect):
def delete(self): def delete(self):
self.net.undefine() self.net.undefine()
def update(self, command, section, parentIndex, xml, flags=0): def update(self, command, section, xml, parentIndex, flags=0):
return self.net.update(command, section, parentIndex, xml, flags) return self.net.update(command, section, parentIndex, xml, flags)
def get_ipv4_network(self): def get_ip_networks(self):
ip_networks = dict()
xml = self._XMLDesc(0) xml = self._XMLDesc(0)
if util.get_xml_path(xml, "/network/ip") is None: if util.get_xml_path(xml, "/network/ip") is None:
return None return None
addrStr = util.get_xml_path(xml, "/network/ip/@address") tree = etree.fromstring(xml)
netmaskStr = util.get_xml_path(xml, "/network/ip/@netmask") ips = tree.findall('.ip')
prefix = util.get_xml_path(xml, "/network/ip/@prefix") for ip in ips:
address_str = ip.get('address')
netmask_str = ip.get('netmask')
prefix = ip.get('prefix')
family = ip.get('family', 'ipv4')
base = 32 if family == 'ipv4' else 128
if prefix: if prefix:
prefix = int(prefix) prefix = int(prefix)
binstr = ((prefix * "1") + ((32 - prefix) * "0")) binstr = ((prefix * "1") + ((base - prefix) * "0"))
netmaskStr = str(IP(int(binstr, base=2))) netmask_str = str(IP(int(binstr, base=2)))
if netmaskStr: if netmask_str:
netmask = IP(netmaskStr) netmask = IP(netmask_str)
gateway = IP(addrStr) gateway = IP(address_str)
network = IP(gateway.int() & netmask.int()) network = IP(gateway.int() & netmask.int())
ret = IP(str(network) + "/" + netmaskStr) netmask_str = netmask_str if family == 'ipv4' else str(prefix)
ret = IP(str(network) + "/" + netmask_str)
else: else:
ret = IP(str(addrStr)) ret = IP(str(address_str))
ip_networks[family] = ret
return ip_networks
return ret def get_network_forward(self):
def get_ipv4_forward(self):
xml = self._XMLDesc(0) xml = self._XMLDesc(0)
fw = util.get_xml_path(xml, "/network/forward/@mode") fw = util.get_xml_path(xml, "/network/forward/@mode")
forwardDev = util.get_xml_path(xml, "/network/forward/@dev") forward_dev = util.get_xml_path(xml, "/network/forward/@dev")
return [fw, forwardDev] return [fw, forward_dev]
def get_ipv4_dhcp_range(self): def get_dhcp_range(self, family='ipv4'):
xml = self._XMLDesc(0) xml = self._XMLDesc(0)
dhcpstart = util.get_xml_path(xml, "/network/ip/dhcp/range[1]/@start") if family == 'ipv4':
dhcpend = util.get_xml_path(xml, "/network/ip/dhcp/range[1]/@end") dhcpstart = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@start")
dhcpend = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@end")
if family == 'ipv6':
dhcpstart = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@start")
dhcpend = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@end")
if not dhcpstart or not dhcpend: if not dhcpstart or not dhcpend:
return None return None
return [IP(dhcpstart), IP(dhcpend)] return [IP(dhcpstart), IP(dhcpend)]
def get_ipv4_dhcp_range_start(self): def get_dhcp_range_start(self, family='ipv4'):
dhcp = self.get_ipv4_dhcp_range() dhcp = self.get_dhcp_range(family)
if not dhcp: if not dhcp:
return None return None
return dhcp[0] return dhcp[0]
def get_ipv4_dhcp_range_end(self): def get_dhcp_range_end(self, family='ipv4'):
dhcp = self.get_ipv4_dhcp_range() dhcp = self.get_dhcp_range(family)
if not dhcp: if not dhcp:
return None return None
return dhcp[1] return dhcp[1]
def can_pxe(self): def can_pxe(self):
xml = self._XMLDesc(0) xml = self._XMLDesc(0)
forward = self.get_ipv4_forward()[0] forward = self.get_network_forward()[0]
if forward and forward != "nat": if forward and forward != "nat":
return True return True
return bool(util.get_xml_path(xml, "/network/ip/dhcp/bootp/@file")) return bool(util.get_xml_path(xml, "/network/ip/dhcp/bootp/@file"))
def get_mac_ipaddr(self): def get_dhcp_host_addr(self, family='ipv4'):
def network(doc): result = list()
result = [] tree = etree.fromstring(self._XMLDesc(0))
for net in doc.xpath('/network/ip/dhcp/host'):
ip = net.xpath('@ip')[0]
mac = net.xpath('@mac')[0]
name = net.xpath('@name')
name = name[0] if name else ""
for ipdhcp in tree.findall("./ip"):
if family == 'ipv4':
if ipdhcp.get('family') is None:
hosts = ipdhcp.findall('./dhcp/host')
for host in hosts:
ip = host.get('ip')
mac = host.get('mac')
name = host.get('name','')
result.append({'ip': ip, 'mac': mac, 'name': name}) result.append({'ip': ip, 'mac': mac, 'name': name})
return result return result
return util.get_xml_path(self._XMLDesc(0), func=network)
def modify_fixed_address(self, name, address, mac):
util.validate_macaddr(mac)
if name:
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(mac, name, IP(address))
else: else:
new_xml = '<host mac="{}" ip="{}"/>'.format(mac, IP(address)) continue
new_host_xml = ElementTree.fromstring(new_xml) if family == 'ipv6':
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
for host in hosts:
ip = host.get('ip')
id = host.get('id')
name = host.get('name','')
result.append({'ip': ip, 'id': id, 'name': name})
return result
tree = ElementTree.fromstring(self._XMLDesc(0)) def modify_dhcp_range(self, range_start, range_end, family='ipv4'):
hosts = tree.findall("./ip/dhcp/host") if not self.is_active():
tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4':
range = tree.xpath("./ip[not(@family='ipv6')]/dhcp/range")
if family == 'ipv6':
range = tree.xpath("./ip[@family='ipv6']/dhcp/range")
range[0].set('start', range_start)
range[0].set('end', range_end)
self.wvm.networkDefineXML(etree.tostring(tree))
def delete_fixed_address(self, ip, family='ipv4'):
tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4':
hosts = tree.xpath("/network/ip[not(@family='ipv6')]/dhcp/host")
parent_index = self.parent_count - 2
if family == 'ipv6':
hosts = tree.xpath("/network/ip[@family='ipv6']/dhcp/host")
parent_index = self.parent_count - 1
for h in hosts:
if h.get('ip') == ip:
if family == 'ipv4':
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get('mac'), h.get('name'), ip)
if family == 'ipv6':
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get('id'), h.get('name'), ip)
self.update(VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
break
def modify_fixed_address(self, name, address, mac_duid, family='ipv4'):
tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4':
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
hosts = tree.xpath("./ip[not(@family='ipv6')]/dhcp/host")
compare_var = 'mac'
parent_index = self.parent_count - 2
if family == 'ipv6':
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
compare_var = 'id'
parent_index = self.parent_count - 1
new_host_xml = etree.fromstring(new_xml)
host = None host = None
for h in hosts: for h in hosts:
if h.get('mac') == mac: if h.get(compare_var) == mac_duid:
host = h host = h
break break
if host is None: if host is None:
self.update(VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_SECTION_IP_DHCP_HOST, -1, new_xml, self.update(VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG) VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
else: else:
# change the host # change the host
if host.get('name') == new_host_xml.get('name') and host.get('ip') == new_host_xml.get('ip'): if host.get('name') == new_host_xml.get('name') and host.get('ip') == new_host_xml.get('ip'):
return False return False
else: else:
self.update(VIR_NETWORK_UPDATE_COMMAND_MODIFY, VIR_NETWORK_SECTION_IP_DHCP_HOST, -1, new_xml, self.update(VIR_NETWORK_UPDATE_COMMAND_MODIFY, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG) VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
def delete_fixed_address(self, mac):
util.validate_macaddr(mac)
tree = ElementTree.fromstring(self._XMLDesc(0))
hosts = tree.findall("./ip/dhcp/host")
for h in hosts:
if h.get('mac') == mac:
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(mac, h.get('name'), h.get('ip'))
self.update(VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_SECTION_IP_DHCP_HOST, -1, new_xml,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
break
def modify_dhcp_range(self, range_start, range_end):
if not self.is_active():
new_range = '<range start="{}" end="{}"/>'.format(range_start, range_end)
tree = ElementTree.fromstring(self._XMLDesc(0))
dhcp = tree.find("./ip/dhcp")
old_range = dhcp.find('range')
dhcp.remove(old_range)
dhcp.append(ElementTree.fromstring(new_range))
self.wvm.networkDefineXML(ElementTree.tostring(tree))