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

Merge pull request #257 from catborise/master

ipv6 support and bridge slave list & pep8 corrections
This commit is contained in:
Anatoliy Guskov 2019-11-07 10:53:41 +02:00 committed by GitHub
commit 23e496cf0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 508 additions and 189 deletions

View file

@ -73,6 +73,7 @@ def allinstances(request):
def instances(request, compute_id): def instances(request, compute_id):
""" """
:param request: :param request:
:param compute_id
:return: :return:
""" """
all_host_vms = {} all_host_vms = {}
@ -224,9 +225,9 @@ def instance(request, compute_id, vname):
def get_network_tuple(network_source_str): def get_network_tuple(network_source_str):
network_source_pack = network_source_str.split(":", 1) network_source_pack = network_source_str.split(":", 1)
if len(network_source_pack) > 1: if len(network_source_pack) > 1:
return (network_source_pack[1], network_source_pack[0]) return network_source_pack[1], network_source_pack[0]
else: else:
return (network_source_pack[0], 'net') return network_source_pack[0], 'net'
def migrate_instance(new_compute, instance, live=False, unsafe=False, xml_del=False, offline=False): def migrate_instance(new_compute, instance, live=False, unsafe=False, xml_del=False, offline=False):
status = connection_manager.host_is_up(new_compute.type, new_compute.hostname) status = connection_manager.host_is_up(new_compute.type, new_compute.hostname)
@ -1104,10 +1105,13 @@ def instances_actions(request):
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
@login_required @login_required
def inst_graph(request, compute_id, vname): def inst_graph(request, compute_id, vname):
""" """
:param request: :param request:
:param compute_id:
:param vname:
:return: :return:
""" """
json_blk = [] json_blk = []
@ -1298,7 +1302,7 @@ def delete_instance(instance, delete_disk=False):
conn.delete() conn.delete()
instance.delete() instance.delete()
print("Instance {} on compute {} sucessfully deleted".format(instance_name, compute.hostname)) print("Instance {} on compute {} successfully deleted".format(instance_name, compute.hostname))
except libvirtError as lib_err: except libvirtError as lib_err:
print("Error removing instance {} on compute {}".format(instance_name, compute.hostname)) print("Error removing instance {} on compute {}".format(instance_name, compute.hostname))

View file

@ -38,12 +38,12 @@
<div class="row"> <div class="row">
<div class="col-xs-6 col-sm-4"> <div class="col-xs-6 col-sm-4">
<p>{% trans "Interface" %}:</p> <p>{% trans "Interface" %}:</p>
<p>{% trans "IPv4" %}: ({% ifequal ipv4 None %}{% trans 'None' %}{% else %}{{ ipv4_type }}{% endifequal %})</p> <p>{% trans "IPv4" %} ({% ifequal ipv4 None %}{% trans 'None' %}{% else %}{{ ipv4_type }}{% endifequal %}):</p>
<p>{% trans "IPv6" %}: ({% ifequal ipv6 None %}{% trans 'None' %}{% else %}{{ ipv6_type }}{% endifequal %})</p> <p>{% trans "IPv6" %} ({% ifequal ipv6 None %}{% trans 'None' %}{% else %}{{ ipv6_type }}{% endifequal %}):</p>
<p>{% trans "MAC Adress" %}:</p> <p>{% trans "MAC Adress" %}:</p>
<p>{% trans "Interface Type" %}:</p> <p>{% trans "Interface Type" %}:</p>
{% ifequal itype 'bridge' %} {% ifequal itype 'bridge' %}
<p>{% trans "Bridge device" %}</p> <p>{% trans "Bridge Device" %}:</p>
{% endifequal %} {% endifequal %}
<p>{% trans "Boot Mode" %}:</p> <p>{% trans "Boot Mode" %}:</p>
<p>{% trans "State" %}:</p> <p>{% trans "State" %}:</p>
@ -69,5 +69,33 @@
</form> </form>
</p> </p>
</div> </div>
<div class="col-sm-12">
{% ifequal itype 'bridge' %}
<table class="table table-bordered">
<caption>{% trans 'Slaves' %}</caption>
<thead>
<tr class="active">
<td>{% trans 'MAC' %}</td>
<td>{% trans 'Name' %}</td>
<td>{% trans 'Type' %}</td>
<td>{% trans 'Speed' %}</td>
<td>{% trans 'State' %}</td>
</tr>
</thead>
<tbody>
{% for iface in slave_ifaces %}
<tr>
<td>{{ iface.mac }}</td>
<td>{{ iface.name }}</td>
<td>{{ iface.type }}</td>
<td>{{ iface.speed }}</td>
<td>{{ iface.state }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endifequal %}
</div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -61,6 +61,7 @@ def interfaces(request, compute_id):
def interface(request, compute_id, iface): def interface(request, compute_id, iface):
""" """
:param request: :param request:
:param compute_id:
:param iface: :param iface:
:return: :return:
""" """
@ -87,6 +88,7 @@ def interface(request, compute_id, iface):
ipv6 = conn.get_ipv6() ipv6 = conn.get_ipv6()
ipv6_type = conn.get_ipv6_type() ipv6_type = conn.get_ipv6_type()
bridge = conn.get_bridge() bridge = conn.get_bridge()
slave_ifaces = conn.get_bridge_slave_ifaces()
if request.method == 'POST': if request.method == 'POST':
if 'stop' in request.POST: if 'stop' in request.POST:

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)
@ -161,7 +182,7 @@ def network(request, compute_id, pool):
compute.login, compute.login,
compute.password, compute.password,
compute.type) compute.type)
conn.define_network(edit_xml) new_conn.define_network(edit_xml)
if conn.is_active(): if conn.is_active():
messages.success(request, _("Network XML is changed. Stop and start network to activate new config.")) messages.success(request, _("Network XML is changed. Stop and start network to activate new config."))
else: else:

View file

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.shortcuts import render
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -19,6 +18,7 @@ from logs.views import addlogmsg
def nwfilters(request, compute_id): def nwfilters(request, compute_id):
""" """
:param request: :param request:
:param compute_id:
:return: :return:
""" """
@ -31,9 +31,9 @@ def nwfilters(request, compute_id):
try: try:
conn = wvmNWFilters(compute.hostname, conn = wvmNWFilters(compute.hostname,
compute.login, compute.login,
compute.password, compute.password,
compute.type) compute.type)
if request.method == 'POST': if request.method == 'POST':
if 'create_nwfilter' in request.POST: if 'create_nwfilter' in request.POST:
@ -63,7 +63,7 @@ def nwfilters(request, compute_id):
addlogmsg(request.user.username, compute.hostname, lib_err.message) addlogmsg(request.user.username, compute.hostname, lib_err.message)
if 'del_nwfilter' in request.POST: if 'del_nwfilter' in request.POST:
name = request.POST.get('nwfiltername','') name = request.POST.get('nwfiltername', '')
msg = _("Deleting NWFilter: %s" % name) msg = _("Deleting NWFilter: %s" % name)
in_use = False in_use = False
nwfilter = conn.get_nwfilter(name) nwfilter = conn.get_nwfilter(name)
@ -71,7 +71,6 @@ def nwfilters(request, compute_id):
is_conn = wvmInstances(compute.hostname, compute.login, compute.password, compute.type) is_conn = wvmInstances(compute.hostname, compute.login, compute.password, compute.type)
instances = is_conn.get_instances() instances = is_conn.get_instances()
for inst in instances: for inst in instances:
# if in_use: break
i_conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, inst) i_conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, inst)
dom_filterrefs = i_conn.get_filterrefs() dom_filterrefs = i_conn.get_filterrefs()
@ -90,10 +89,10 @@ def nwfilters(request, compute_id):
if 'cln_nwfilter' in request.POST: if 'cln_nwfilter' in request.POST:
name = request.POST.get('nwfiltername','') name = request.POST.get('nwfiltername', '')
cln_name = request.POST.get('cln_name', name + '-clone') cln_name = request.POST.get('cln_name', name + '-clone')
conn.clone_nwfilter(name,cln_name) conn.clone_nwfilter(name, cln_name)
msg = _("Cloning NWFilter %s as %s" % (name, cln_name)) msg = _("Cloning NWFilter %s as %s" % (name, cln_name))
addlogmsg(request.user.username, compute.hostname, msg) addlogmsg(request.user.username, compute.hostname, msg)
@ -122,14 +121,14 @@ def nwfilter(request, compute_id, nwfltr):
try: try:
nwfilter = wvmNWFilter(compute.hostname, nwfilter = wvmNWFilter(compute.hostname,
compute.login, compute.login,
compute.password, compute.password,
compute.type, compute.type,
nwfltr) nwfltr)
conn = wvmNWFilters(compute.hostname, conn = wvmNWFilters(compute.hostname,
compute.login, compute.login,
compute.password, compute.password,
compute.type) compute.type)
for nwf in conn.get_nwfilters(): for nwf in conn.get_nwfilters():
nwfilters_all.append(conn.get_nwfilter_info(nwf)) nwfilters_all.append(conn.get_nwfilter_info(nwf))
@ -208,4 +207,4 @@ def nwfilter(request, compute_id, nwfltr):
except Exception as error_msg: except Exception as error_msg:
error_messages.append(error_msg) error_messages.append(error_msg)
return render(request, 'nwfilter.html', locals()) return render(request, 'nwfilter.html', locals())

View file

@ -12,6 +12,7 @@ from libvirt import libvirtError
def secrets(request, compute_id): def secrets(request, compute_id):
""" """
:param request: :param request:
:param compute_id:
:return: :return:
""" """

View file

@ -318,9 +318,9 @@ class IPint(object):
(self._ipversion == 6 and self._prefixlen == 128): (self._ipversion == 6 and self._prefixlen == 128):
if self.NoPrefixForSingleIp: if self.NoPrefixForSingleIp:
want = 0 want = 0
if want == None: if want is None:
want = self.WantPrefixLen want = self.WantPrefixLen
if want == None: if want is None:
want = 1 want = 1
if want: if want:
if want == 2: if want == 2:
@ -354,7 +354,7 @@ class IPint(object):
""" """
bits = _ipVersionToLen(self._ipversion) bits = _ipVersionToLen(self._ipversion)
if self.WantPrefixLen == None and wantprefixlen == None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 0 wantprefixlen = 0
ret = _intToBin(self.ip) ret = _intToBin(self.ip)
return '0' * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen) return '0' * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen)
@ -370,7 +370,7 @@ class IPint(object):
'ffff:ffff:ffff:ffff:ffff:f:f:fffc/127' 'ffff:ffff:ffff:ffff:ffff:f:f:fffc/127'
""" """
if self.WantPrefixLen == None and wantprefixlen == None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 1 wantprefixlen = 1
if self._ipversion == 4: if self._ipversion == 4:
@ -413,7 +413,7 @@ class IPint(object):
2001:658:22a:cafe:200:0:0:1 2001:658:22a:cafe:200:0:0:1
""" """
if self.WantPrefixLen == None and wantprefixlen == None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 1 wantprefixlen = 1
if self._ipversion == 4: if self._ipversion == 4:
@ -434,7 +434,7 @@ class IPint(object):
2001:0658:022a:cafe:0200:0000:0000:0001 2001:0658:022a:cafe:0200:0000:0000:0001
""" """
if self.WantPrefixLen == None and wantprefixlen == None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 1 wantprefixlen = 1
return intToIp(self.ip, self._ipversion) + self._printPrefix(wantprefixlen) return intToIp(self.ip, self._ipversion) + self._printPrefix(wantprefixlen)
@ -448,7 +448,7 @@ class IPint(object):
0x20010658022acafe0200000000000001 0x20010658022acafe0200000000000001
""" """
if self.WantPrefixLen == None and wantprefixlen == None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 0 wantprefixlen = 0
x = '0x%x' % self.ip x = '0x%x' % self.ip
@ -463,7 +463,7 @@ class IPint(object):
42540616829182469433547762482097946625 42540616829182469433547762482097946625
""" """
if self.WantPrefixLen == None and wantprefixlen == None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 0 wantprefixlen = 0
x = '%d' % self.ip x = '%d' % self.ip

View file

@ -124,16 +124,7 @@ class wvmConnection(object):
# on server shutdown libvirt module gets freed before the close callbacks are called # on server shutdown libvirt module gets freed before the close callbacks are called
# so we just check here if it is still present # so we just check here if it is still present
if libvirt is not None: if libvirt is not None:
if (reason == libvirt.VIR_CONNECT_CLOSE_REASON_ERROR): self.last_error = reason
self.last_error = 'connection closed: Misc I/O error'
elif (reason == libvirt.VIR_CONNECT_CLOSE_REASON_EOF):
self.last_error = 'connection closed: End-of-file from server'
elif (reason == libvirt.VIR_CONNECT_CLOSE_REASON_KEEPALIVE):
self.last_error = 'connection closed: Keepalive timer triggered'
elif (reason == libvirt.VIR_CONNECT_CLOSE_REASON_CLIENT):
self.last_error = 'connection closed: Client requested it'
else:
self.last_error = 'connection closed: Unknown error'
# prevent other threads from using the connection (in the future) # prevent other threads from using the connection (in the future)
self.connection = None self.connection = None
@ -255,11 +246,11 @@ class wvmConnectionManager(object):
""" """
self._connections_lock.acquireRead() self._connections_lock.acquireRead()
try: try:
if (host in self._connections): if host in self._connections:
connections = self._connections[host] connections = self._connections[host]
for connection in connections: for connection in connections:
if (connection.login == login and connection.passwd == passwd and connection.type == conn): if connection.login == login and connection.passwd == passwd and connection.type == conn:
return connection return connection
finally: finally:
self._connections_lock.release() self._connections_lock.release()
@ -278,13 +269,13 @@ class wvmConnectionManager(object):
connection = self._search_connection(host, login, passwd, conn) connection = self._search_connection(host, login, passwd, conn)
if (connection is None): if connection is None:
self._connections_lock.acquireWrite() self._connections_lock.acquireWrite()
try: try:
# we have to search for the connection again after aquireing the write lock # we have to search for the connection again after aquireing the write lock
# as the thread previously holding the write lock may have already added our connection # as the thread previously holding the write lock may have already added our connection
connection = self._search_connection(host, login, passwd, conn) connection = self._search_connection(host, login, passwd, conn)
if (connection is None): if connection is None:
# create a new connection if a matching connection does not already exist # create a new connection if a matching connection does not already exist
connection = wvmConnection(host, login, passwd, conn) connection = wvmConnection(host, login, passwd, conn)
@ -317,7 +308,7 @@ class wvmConnectionManager(object):
socket_host.settimeout(1) socket_host.settimeout(1)
if conn_type == CONN_SSH: if conn_type == CONN_SSH:
if ':' in hostname: if ':' in hostname:
LIBVIRT_HOST, PORT = (hostname).split(":") LIBVIRT_HOST, PORT = hostname.split(":")
PORT = int(PORT) PORT = int(PORT)
else: else:
PORT = SSH_PORT PORT = SSH_PORT
@ -332,6 +323,7 @@ class wvmConnectionManager(object):
except Exception as err: except Exception as err:
return err return err
connection_manager = wvmConnectionManager( connection_manager = wvmConnectionManager(
settings.LIBVIRT_KEEPALIVE_INTERVAL if hasattr(settings, 'LIBVIRT_KEEPALIVE_INTERVAL') else 5, settings.LIBVIRT_KEEPALIVE_INTERVAL if hasattr(settings, 'LIBVIRT_KEEPALIVE_INTERVAL') else 5,
settings.LIBVIRT_KEEPALIVE_COUNT if hasattr(settings, 'LIBVIRT_KEEPALIVE_COUNT') else 5 settings.LIBVIRT_KEEPALIVE_COUNT if hasattr(settings, 'LIBVIRT_KEEPALIVE_COUNT') else 5
@ -368,7 +360,7 @@ class wvmConnect(object):
minor = ver / 1000 minor = ver / 1000
ver = ver % 1000 ver = ver % 1000
release = ver release = ver
return "%s.%s.%s" % (major,minor,release) return "%s.%s.%s" % (major, minor, release)
def get_lib_version(self): def get_lib_version(self):
ver = self.wvm.getLibVersion() ver = self.wvm.getLibVersion()
@ -432,7 +424,7 @@ class wvmConnect(object):
for arch in ctx.xpath('/capabilities/guest/arch'): for arch in ctx.xpath('/capabilities/guest/arch'):
domain_types = arch.xpath('domain/@type') domain_types = arch.xpath('domain/@type')
arch_name = arch.xpath('@name')[0] arch_name = arch.xpath('@name')[0]
result[arch_name]= domain_types result[arch_name] = domain_types
return result return result
return util.get_xml_path(self.get_cap_xml(), func=hypervisors) return util.get_xml_path(self.get_cap_xml(), func=hypervisors)
@ -446,7 +438,7 @@ class wvmConnect(object):
for arch in ctx.xpath('/capabilities/guest/arch'): for arch in ctx.xpath('/capabilities/guest/arch'):
emulator = arch.xpath('emulator') emulator = arch.xpath('emulator')
arch_name = arch.xpath('@name')[0] arch_name = arch.xpath('@name')[0]
result[arch_name]= emulator result[arch_name] = emulator
return result return result
return util.get_xml_path(self.get_cap_xml(), func=emulators) return util.get_xml_path(self.get_cap_xml(), func=emulators)
@ -460,8 +452,8 @@ class wvmConnect(object):
def get_bus_list(ctx): def get_bus_list(ctx):
result = [] result = []
for disk_enum in ctx.xpath('/domainCapabilities/devices/disk/enum'): for disk_enum in ctx.xpath('/domainCapabilities/devices/disk/enum'):
if disk_enum.xpath("@name")[0] == "bus": if disk_enum.xpath("@name")[0] == "bus":
for values in disk_enum: result.append(values.text) for values in disk_enum: result.append(values.text)
return result return result
# return [ 'ide', 'scsi', 'usb', 'virtio' ] # return [ 'ide', 'scsi', 'usb', 'virtio' ]
@ -482,11 +474,11 @@ class wvmConnect(object):
def get_image_formats(self): def get_image_formats(self):
"""Get available image formats""" """Get available image formats"""
return [ 'raw', 'qcow', 'qcow2' ] return ['raw', 'qcow', 'qcow2']
def get_file_extensions(self): def get_file_extensions(self):
"""Get available image filename extensions""" """Get available image filename extensions"""
return [ 'img', 'qcow', 'qcow2' ] return ['img', 'qcow', 'qcow2']
def get_video(self): def get_video(self):
""" Get available graphics video types """ """ Get available graphics video types """
@ -496,7 +488,7 @@ class wvmConnect(object):
if video_enum.xpath("@name")[0] == "modelType": if video_enum.xpath("@name")[0] == "modelType":
for values in video_enum: result.append(values.text) for values in video_enum: result.append(values.text)
return result return result
return util.get_xml_path(self.get_dom_cap_xml(),func=get_video_list) return util.get_xml_path(self.get_dom_cap_xml(), func=get_video_list)
def get_iface(self, name): def get_iface(self, name):
return self.wvm.interfaceLookupByName(name) return self.wvm.interfaceLookupByName(name)
@ -560,6 +552,7 @@ class wvmConnect(object):
def get_host_instances(self, raw_mem_size=False): def get_host_instances(self, raw_mem_size=False):
vname = {} vname = {}
def get_info(doc): def get_info(doc):
mem = util.get_xpath(doc, "/domain/currentMemory") mem = util.get_xpath(doc, "/domain/currentMemory")
mem = int(mem) / 1024 mem = int(mem) / 1024
@ -574,7 +567,7 @@ class wvmConnect(object):
title = title if title else '' title = title if title else ''
description = util.get_xpath(doc, "/domain/description") description = util.get_xpath(doc, "/domain/description")
description = description if description else '' description = description if description else ''
return (mem, vcpu, title, description) return mem, vcpu, title, description
for name in self.get_instances(): for name in self.get_instances():
dom = self.get_instance(name) dom = self.get_instance(name)
xml = dom.XMLDesc(0) xml = dom.XMLDesc(0)
@ -592,6 +585,7 @@ class wvmConnect(object):
def get_user_instances(self, name): def get_user_instances(self, name):
dom = self.get_instance(name) dom = self.get_instance(name)
xml = dom.XMLDesc(0) xml = dom.XMLDesc(0)
def get_info(ctx): def get_info(ctx):
mem = util.get_xpath(ctx, "/domain/currentMemory") mem = util.get_xpath(ctx, "/domain/currentMemory")
mem = int(mem) / 1024 mem = int(mem) / 1024
@ -604,7 +598,7 @@ class wvmConnect(object):
title = title if title else '' title = title if title else ''
description = util.get_xpath(ctx, "/domain/description") description = util.get_xpath(ctx, "/domain/description")
description = description if description else '' description = description if description else ''
return (mem, vcpu, title, description) return mem, vcpu, title, description
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info) (mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
return { return {
'name': dom.name(), 'name': dom.name(),

View file

@ -247,7 +247,7 @@ class wvmInstance(wvmConnect):
def get_disk_devices(self): def get_disk_devices(self):
def disks(doc): def disks(doc):
result = [] result = []
dev = volume = storage = src_file = None dev = volume = storage = src_file = bus = None
disk_format = used_size = disk_size = disk_cache = None disk_format = used_size = disk_size = disk_cache = None
for disk in doc.xpath('/domain/devices/disk'): for disk in doc.xpath('/domain/devices/disk'):
@ -288,7 +288,7 @@ class wvmInstance(wvmConnect):
def get_media_devices(self): def get_media_devices(self):
def disks(doc): def disks(doc):
result = [] result = []
dev = volume = storage = None dev = volume = storage = bus = None
src_file = None src_file = None
for media in doc.xpath('/domain/devices/disk'): for media in doc.xpath('/domain/devices/disk'):
device = media.xpath('@device')[0] device = media.xpath('@device')[0]
@ -341,6 +341,7 @@ class wvmInstance(wvmConnect):
def get_bootorder(self): def get_bootorder(self):
boot_order = {} boot_order = {}
type = target = None
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
os = tree.find('os') os = tree.find('os')
boot = os.findall('boot') boot = os.findall('boot')
@ -363,7 +364,7 @@ class wvmInstance(wvmConnect):
devices = tree.find('devices') devices = tree.find('devices')
for dev in devices: for dev in devices:
dev_target = dev_type = dev_device = dev_alias = None dev_target = None
boot_dev = dev.find('boot') boot_dev = dev.find('boot')
if boot_dev is not None: if boot_dev is not None:
idx = boot_dev.get('order') idx = boot_dev.get('order')
@ -439,6 +440,7 @@ class wvmInstance(wvmConnect):
disk.insert(2, src_media) disk.insert(2, src_media)
return True return True
vol = None
storages = self.get_storages(only_actives=True) storages = self.get_storages(only_actives=True)
for storage in storages: for storage in storages:
stg = self.get_storage(storage) stg = self.get_storage(storage)

View file

@ -1,5 +1,6 @@
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from vrtManager import util from vrtManager import util
from xml.etree import ElementTree
from libvirt import VIR_INTERFACE_XML_INACTIVE from libvirt import VIR_INTERFACE_XML_INACTIVE
@ -119,9 +120,34 @@ class wvmInterface(wvmConnect):
return int_ipv6_ip + '/' + int_ipv6_mask return int_ipv6_ip + '/' + int_ipv6_mask
def get_bridge(self): def get_bridge(self):
bridge = None
if self.get_type() == 'bridge': if self.get_type() == 'bridge':
xml = self._XMLDesc() bridge = util.get_xml_path(self._XMLDesc(), "/interface/bridge/interface/@name")
return util.get_xml_path(xml, "/interface/bridge/interface/@name") for iface in self.get_bridge_slave_ifaces():
if iface.get('state') == 'up' and iface.get('speed') is not 'unknown':
bridge = iface.get('name')
return bridge
return bridge
else:
return None
def get_bridge_slave_ifaces(self):
ifaces = list()
if self.get_type() == 'bridge':
tree = ElementTree.fromstring(self._XMLDesc())
for iface in tree.findall("./bridge/"):
address = state = speed = None
name = iface.get('name')
type = iface.get('type')
link = iface.find('link')
if link is not None:
state = link.get('state')
speed = link.get('speed')
mac = iface.find('mac')
if mac is not None:
address = mac.get('address')
ifaces.append({'name': name, 'type': type, 'state': state, 'speed': speed, 'mac': address})
return ifaces
else: else:
return None return None

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:
prefix = int(prefix)
binstr = ((prefix * "1") + ((base - prefix) * "0"))
netmask_str = str(IP(int(binstr, base=2)))
if prefix: if netmask_str:
prefix = int(prefix) netmask = IP(netmask_str)
binstr = ((prefix * "1") + ((32 - prefix) * "0")) gateway = IP(address_str)
netmaskStr = str(IP(int(binstr, base=2))) network = IP(gateway.int() & netmask.int())
netmask_str = netmask_str if family == 'ipv4' else str(prefix)
ret = IP(str(network) + "/" + netmask_str)
else:
ret = IP(str(address_str))
ip_networks[family] = ret
return ip_networks
if netmaskStr: def get_network_forward(self):
netmask = IP(netmaskStr)
gateway = IP(addrStr)
network = IP(gateway.int() & netmask.int())
ret = IP(str(network) + "/" + netmaskStr)
else:
ret = IP(str(addrStr))
return ret
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 ""
result.append({'ip': ip, 'mac': mac, 'name': name}) for ipdhcp in tree.findall("./ip"):
return result 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})
return result
else:
continue
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
return util.get_xml_path(self._XMLDesc(0), func=network) def modify_dhcp_range(self, range_start, range_end, family='ipv4'):
if not self.is_active():
def modify_fixed_address(self, name, address, mac): tree = etree.fromstring(self._XMLDesc(0))
util.validate_macaddr(mac) if family == 'ipv4':
if name: range = tree.xpath("./ip[not(@family='ipv6')]/dhcp/range")
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(mac, name, IP(address)) if family == 'ipv6':
else: range = tree.xpath("./ip[@family='ipv6']/dhcp/range")
new_xml = '<host mac="{}" ip="{}"/>'.format(mac, IP(address)) range[0].set('start', range_start)
new_host_xml = ElementTree.fromstring(new_xml) range[0].set('end', range_end)
self.wvm.networkDefineXML(etree.tostring(tree))
tree = ElementTree.fromstring(self._XMLDesc(0)) def delete_fixed_address(self, ip, family='ipv4'):
hosts = tree.findall("./ip/dhcp/host") 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))