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

Merge pull request #346 from catborise/master

fix some errors
This commit is contained in:
Anatoliy Guskov 2020-07-25 10:47:31 +03:00 committed by GitHub
commit 8e4073f4b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 16100 additions and 11347 deletions

View file

@ -335,13 +335,13 @@ python manage.py test
### Screenshots ### Screenshots
Instance Detail: Instance Detail:
<img src="doc/images/instance.PNG" width="95%" align="center"/> <img src="doc/images/instance.PNG" width="96%" align="center"/>
Instance List:</br> Instance List:</br>
<img src="doc/images/grouped.PNG" width="47%"/> <img src="doc/images/grouped.PNG" width="43%"/>
<img src="doc/images/nongrouped.PNG" width="51%"/> <img src="doc/images/nongrouped.PNG" width="53%"/>
Other: </br> Other: </br>
<img src="doc/images/hosts.PNG" width="52%"/> <img src="doc/images/hosts.PNG" width="47%"/>
<img src="doc/images/log.PNG" width="47%"/> <img src="doc/images/log.PNG" width="49%"/>
### License ### License

View file

@ -18,7 +18,7 @@
<div class="col-lg-12"> <div class="col-lg-12">
<h3 class="page-header">{% trans "Edit Profile" %}</h3> <h3 class="page-header">{% trans "Edit Profile" %}</h3>
{% if perms.accounts.change_password %} {% if perms.accounts.change_password %}
<a href="{% url 'change_password' %}" class="btn btn-primary">{% icon 'lock' %} {% trans "Change Password" %}</a> <a href="{% url 'change_password' %}" class="ml-3 btn btn-primary">{% icon 'lock' %} {% trans "Change Password" %}</a>
{% endif %} {% endif %}
<form method="post" action="" role="form" aria-label="Edit user info form">{% csrf_token %} <form method="post" action="" role="form" aria-label="Edit user info form">{% csrf_token %}
<div class="form-group"> <div class="form-group">

View file

@ -1,5 +1,8 @@
from django import forms from django import forms
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.urls import reverse_lazy
from django.utils.text import format_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from accounts.models import UserAttributes from accounts.models import UserAttributes
@ -68,6 +71,16 @@ class UserForm(forms.ModelForm):
'is_superuser', 'is_superuser',
] ]
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
password = ReadOnlyPasswordHashField(label=_("Password"),
help_text=format_lazy(_("""Raw passwords are not stored, so there is no way to see
this user's password, but you can change the password
using <a href='{}'>this form</a>."""),
reverse_lazy('admin:user_update_password', args=[self.instance.id,]))
)
self.fields['Password'] = password
class UserCreateForm(UserForm): class UserCreateForm(UserForm):
password = forms.CharField(widget=forms.PasswordInput) password = forms.CharField(widget=forms.PasswordInput)

View file

@ -1,5 +1,4 @@
from django.urls import path from django.urls import path
from django.contrib.auth.views import PasswordChangeView, PasswordChangeDoneView
from . import views from . import views
@ -10,6 +9,7 @@ urlpatterns = [
path('groups/<int:pk>/delete/', views.group_delete, name='group_delete'), path('groups/<int:pk>/delete/', views.group_delete, name='group_delete'),
path('users/', views.user_list, name='user_list'), path('users/', views.user_list, name='user_list'),
path('users/create/', views.user_create, name='user_create'), path('users/create/', views.user_create, name='user_create'),
path('users/<int:pk>/update_password/', views.user_update_password, name='user_update_password'),
path('users/<int:pk>/update/', views.user_update, name='user_update'), path('users/<int:pk>/update/', views.user_update, name='user_update'),
path('users/<int:pk>/delete/', views.user_delete, name='user_delete'), path('users/<int:pk>/delete/', views.user_delete, name='user_delete'),
path('users/<int:pk>/block/', views.user_block, name='user_block'), path('users/<int:pk>/block/', views.user_block, name='user_block'),

View file

@ -1,4 +1,7 @@
from django.conf import settings from django.conf import settings
from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import AdminPasswordChangeForm
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
@ -133,6 +136,29 @@ def user_update(request, pk):
}, },
) )
@superuser_only
def user_update_password(request, pk):
user = get_object_or_404(User, pk=pk)
if request.method == 'POST':
form = AdminPasswordChangeForm(user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important!
messages.success(request, _('User password changed: {}'.format(user.username)))
return redirect('admin:user_list')
else:
messages.error(request, _('Wrong Data Provided'))
else:
form = AdminPasswordChangeForm(user)
return render(
request,
'accounts/change_password_form.html',
{
'form': form,
'user': user.username
}
)
@superuser_only @superuser_only
def user_delete(request, pk): def user_delete(request, pk):

View file

@ -11,7 +11,6 @@
<!-- /.row --> <!-- /.row -->
{% include 'errors_block.html' %} {% include 'errors_block.html' %}
{% include 'messages_block.html' %}
<div class=""> <div class="">
<div class="col-lg-12"> <div class="col-lg-12">

View file

@ -12,6 +12,7 @@ class TcpComputeForm(forms.ModelForm):
class Meta: class Meta:
model = Compute model = Compute
widgets = {'password': forms.PasswordInput()}
fields = '__all__' fields = '__all__'
@ -30,6 +31,7 @@ class TlsComputeForm(forms.ModelForm):
class Meta: class Meta:
model = Compute model = Compute
widgets = {'password': forms.PasswordInput()}
fields = '__all__' fields = '__all__'

View file

@ -25,26 +25,26 @@
<div class="col-lg-12"> <div class="col-lg-12">
<table class="table table-striped table-hover"> <table class="table table-striped table-hover">
<thead> <thead>
<tr> <tr class="d-flex">
<th span="col">{% trans "Name" %}</th> <th span="col" class="col-sm-3">{% trans "Name" %}</th>
<th span="col">{% trans "Status" %}</th> <th span="col" class="col-sm-2">{% trans "Status" %}</th>
<th span="col">{% trans "Details" %}</th> <th span="col" class="col-sm-5">{% trans "Details" %}</th>
<th span="col">{% trans "Actions" %}</th> <th span="col" class="col-sm-2 text-center">{% trans "Actions" %}</th>
</tr> </tr>
</thead> </thead>
<tbody class="searchable"> <tbody class="searchable">
{% for compute in computes %} {% for compute in computes %}
<tr> <tr class="d-flex">
<td> <td class="col-sm-3">
{{ compute.name }} {{ compute.name }}
</td> </td>
<td> <td class="col-sm-2">
{% if compute.status is True %}{% trans "Connected" %}{% else %}{% trans "Not Connected" %}{% endif %} {% if compute.status is True %}{% trans "Connected" %}{% else %}{% trans "Not Connected" %}{% endif %}
</td> </td>
<td> <td class="col-sm-5">
{{ compute.details|default:"" }} {{ compute.details|default:"" }}
</td> </td>
<td> <td class="col-sm-2">
<div class="float-right btn-group"> <div class="float-right btn-group">
{% if compute.status is True %} {% if compute.status is True %}
<a class="btn btn-success" title="{%trans "Overview" %}" href="{% url 'overview' compute.id %}">{% icon 'eye' %}</a> <a class="btn btn-success" title="{%trans "Overview" %}" href="{% url 'overview' compute.id %}">{% icon 'eye' %}</a>

View file

@ -160,6 +160,11 @@
SpiceHtml5.sendCtrlAltFN(sc, f); SpiceHtml5.sendCtrlAltFN(sc, f);
return false; return false;
} }
function sendCtrlAltDel() {
SpiceHtml5.sendCtrlAltDel(sc);
return false;
}
/* SPICE port event listeners /* SPICE port event listeners
window.addEventListener('spice-port-data', function(event) { window.addEventListener('spice-port-data', function(event) {
// Here we convert data to text, but really we can obtain binary data also // Here we convert data to text, but really we can obtain binary data also

View file

@ -186,6 +186,11 @@
return false; return false;
} }
function sendCtrlAltDel() {
SpiceHtml5.sendCtrlAltDel(sc);
return false;
}
/* SPICE port event listeners /* SPICE port event listeners
window.addEventListener('spice-port-data', function(event) { window.addEventListener('spice-port-data', function(event) {
// Here we convert data to text, but really we can obtain binary data also // Here we convert data to text, but really we can obtain binary data also
@ -198,7 +203,7 @@
}); });
*/ */
document.getElementById("fullscreen_button").addEventListener('click', fullscreen); document.getElementById("fullscreen_button").addEventListener('click', fullscreen);
document.getElementById('ctrlaltdel').addEventListener('click', function () { sendCtrlAltDel(sc); }); document.getElementById('ctrlaltdel').addEventListener('click', function () { sendCtrlAltDel(); });
document.getElementById('ctrlaltf1').addEventListener('click', function () { sendctrlaltfn(0) }); document.getElementById('ctrlaltf1').addEventListener('click', function () { sendctrlaltfn(0) });
document.getElementById('ctrlaltf2').addEventListener('click', function () { sendctrlaltfn(1) }); document.getElementById('ctrlaltf2').addEventListener('click', function () { sendctrlaltfn(1) });
document.getElementById('ctrlaltf3').addEventListener('click', function () { sendctrlaltfn(2) }); document.getElementById('ctrlaltf3').addEventListener('click', function () { sendctrlaltfn(2) });

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -12,6 +12,7 @@
<!-- Tab panes --> <!-- Tab panes -->
<div class="tab-content"> <div class="tab-content">
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="destroy"> <div role="tabpanel" class="tab-pane tab-pane-bordered active" id="destroy">
<p>{% trans 'This action starts remove instance process' %}</p>
{% if request.user.is_superuser or userinstance.is_delete %} {% if request.user.is_superuser or userinstance.is_delete %}
{% if instance.status == 3 %} {% if instance.status == 3 %}
<a class="btn btn-lg btn-success disabled float-right">{% trans "Destroy" %}</a> <a class="btn btn-lg btn-success disabled float-right">{% trans "Destroy" %}</a>

View file

@ -353,6 +353,7 @@
<input name="set_link_state" value="{{ network.state }}" hidden/> <input name="set_link_state" value="{{ network.state }}" hidden/>
<input type="checkbox" {% if network.state == 'up' %} checked{% endif %} onclick='submit();' /> <input type="checkbox" {% if network.state == 'up' %} checked{% endif %} onclick='submit();' />
<strong>{% trans 'active' %}</strong> <strong>{% trans 'active' %}</strong>
<small>{{ network.type }}</small>
</form> </form>
</td> </td>
<th class="d-none d-table-cell d-sm-table-cell">{% trans 'MAC' %}</th> <th class="d-none d-table-cell d-sm-table-cell">{% trans 'MAC' %}</th>
@ -390,10 +391,10 @@
<input class="form-control" type="text" value="{{ network.nic }}" readonly/> <input class="form-control" type="text" value="{{ network.nic }}" readonly/>
<select class="form-control" name="net-source-{{ forloop.counter0 }}"> <select class="form-control" name="net-source-{{ forloop.counter0 }}">
{% for c_net in networks_host %} {% for c_net in networks_host %}
<option value="net:{{ c_net }}" {% if c_net == network.nic %} selected {% endif %}>{% trans 'Network' %} {{ c_net }}</option> <option value="net:{{ c_net }}" {% if c_net == network.nic %} selected {% endif %}>{% trans 'Network' %} {{ c_net }}</option>
{% endfor %} {% endfor %}
{% for c_iface in interfaces_host %} {% for c_iface in interfaces_host %}
<option value="iface:{{ c_iface }}" {% if c_iface == network.nic %} selected {% endif %}>{% trans 'Interface' %} {{ c_iface }}</option> <option value="iface:{{ c_iface }}" {% if c_iface == network.nic %} selected {% endif %}>{% trans 'Interface' %} {{ c_iface }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -405,7 +406,7 @@
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}"> <select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
<option value="">{% trans "None" %}</option> <option value="">{% trans "None" %}</option>
{% for c_filters in nwfilters_host %} {% for c_filters in nwfilters_host %}
<option value="{{ c_filters }}" {% if c_filters == network.filterref %} selected {% endif %}>{{ c_filters }}</option> <option value="{{ c_filters }}" {% if c_filters == network.filterref %} selected {% endif %}>{{ c_filters }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -462,7 +463,11 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td class="bg-primary" colspan="9"></td> <td class="py-1 bg-primary text-white" colspan="9">
{% if network.type == 'direct' %}
<small>{% trans 'In most configurations, macvtap does not work for host to guest network communication' %}</small>
{% endif %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -965,8 +965,8 @@ def set_qos(request, pk):
else: else:
messages.success( messages.success(
request, request,
_(f"{qos_dir.capitalize()} QoS is set. Network XML is changed.") + _(f"{qos_dir.capitalize()} QoS is set. Network XML is changed. \
_("Stop and start network to activate new config"), Stop and start network to activate new config.")
) )
return redirect(request.META.get('HTTP_REFERER') + '#network') return redirect(request.META.get('HTTP_REFERER') + '#network')
@ -984,8 +984,8 @@ def unset_qos(request, pk):
else: else:
messages.success( messages.success(
request, request,
_(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. ") + _(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. \
_("Stop and start network to activate new config."), Stop and start network to activate new config.")
) )
return redirect(request.META.get('HTTP_REFERER') + '#network') return redirect(request.META.get('HTTP_REFERER') + '#network')
@ -1409,7 +1409,7 @@ def create_instance(request, compute_id, arch, machine):
console_pass=data["console_pass"], console_pass=data["console_pass"],
mac=data['mac'], mac=data['mac'],
qemu_ga=data['qemu_ga']) qemu_ga=data['qemu_ga'])
create_instance = Instance(compute_id=compute_id, name=data['name']) create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
create_instance.save() create_instance.save()
msg = _("Instance is created") msg = _("Instance is created")
messages.success(request, msg) messages.success(request, msg)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -46,7 +46,7 @@ class AddNetPool(forms.Form):
def clean_bridge_name(self): def clean_bridge_name(self):
bridge_name = self.cleaned_data['bridge_name'] bridge_name = self.cleaned_data['bridge_name']
if self.cleaned_data['forward'] == 'bridge': if self.cleaned_data['forward'] in ['bridge', 'macvtap']:
have_symbol = re.match('^[a-zA-Z0-9\.\_\:\-]+$', bridge_name) have_symbol = re.match('^[a-zA-Z0-9\.\_\:\-]+$', bridge_name)
if not have_symbol: if not have_symbol:
raise forms.ValidationError(_('The pool bridge name must not contain any special characters')) raise forms.ValidationError(_('The pool bridge name must not contain any special characters'))

View file

@ -28,6 +28,7 @@
<option value="route">{% trans "ROUTE" %}</option> <option value="route">{% trans "ROUTE" %}</option>
<option value="none">{% trans "ISOLATE" %}</option> <option value="none">{% trans "ISOLATE" %}</option>
<option value="bridge">{% trans "BRIDGE" %}</option> <option value="bridge">{% trans "BRIDGE" %}</option>
<option value="macvtap">{% trans "MACVTAP" %}</option>
</select> </select>
</div> </div>
</div> </div>
@ -55,25 +56,25 @@
<input type="checkbox" id="enable_ipv6" name="enable_ipv6" value="false"> <input type="checkbox" id="enable_ipv6" name="enable_ipv6" value="false">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group_dhcp ipv6_group"> <div class="form-group row ipv6_group">
<label class="col-sm-4 col-form-label">{% trans "IPv6 Subnet pool" %}</label> <label class="col-sm-4 col-form-label">{% trans "IPv6 Subnet pool" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="subnet6" value="" placeholder="fd00:dead:baba:1::/64" required pattern="[0-9\/\.]+"> <input type="text" class="form-control" name="subnet6" value="" placeholder="fd00:dead:baba:1::/64" required pattern="[0-9\/\.]+">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group_dhcp ipv6_group"> <div class="form-group row ipv6_group">
<label class="col-sm-4 col-form-label">{% trans "DHCPv6" %}</label> <label class="col-sm-4 col-form-label">{% trans "DHCPv6" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="checkbox" name="dhcp6" value="true"> <input type="checkbox" name="dhcp6" value="true">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group"> <div class="form-group row bridge_name_form_group">
<label class="col-sm-4 col-form-label">{% trans "Bridge Name" %}</label> <label class="col-sm-4 col-form-label" id="bridge_label">{% trans "Bridge Name" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="bridge_name" placeholder="br0" pattern="[a-z0-9\-_:]+"> <input type="text" class="form-control" name="bridge_name" id="bridge_name" placeholder="br0" pattern="[a-z0-9\-_:]+">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group"> <div class="form-group row bridge_name_form_group openvswitch">
<label class="col-sm-4 col-form-label">{% trans "Open vSwitch" %}</label> <label class="col-sm-4 col-form-label">{% trans "Open vSwitch" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="checkbox" name="openvswitch" value="true"> <input type="checkbox" name="openvswitch" value="true">
@ -88,4 +89,5 @@
</div> <!-- /.modal-content --> </div> <!-- /.modal-content -->
</div> <!-- /.modal-dialog --> </div> <!-- /.modal-dialog -->
</div> <!-- /.modal --> </div> <!-- /.modal -->
{% endif %} {% endif %}

View file

@ -37,7 +37,6 @@
<!-- /.row --> <!-- /.row -->
{% include 'errors_block.html' %} {% include 'errors_block.html' %}
{% include 'messages_block.html' %}
<div class="row"> <div class="row">
<dl class="ml-3 row"> <dl class="ml-3 row">

View file

@ -79,6 +79,12 @@
if ($(this).val() == 'bridge') { if ($(this).val() == 'bridge') {
$('.bridge_name_form_group').show(); $('.bridge_name_form_group').show();
$('.bridge_name_form_group_dhcp').hide(); $('.bridge_name_form_group_dhcp').hide();
} else if ($(this).val() == 'macvtap') {
$('#bridge_label').text("Dev Name");
$('#bridge_name').attr("placeholder", "eth0");
$('.bridge_name_form_group').show();
$('.bridge_name_form_group_dhcp').hide();
$('.openvswitch').hide();
} else { } else {
$('.bridge_name_form_group').hide(); $('.bridge_name_form_group').hide();
$('.bridge_name_form_group_dhcp').show(); $('.bridge_name_form_group_dhcp').show();

View file

@ -42,8 +42,8 @@ def networks(request, compute_id):
if data['name'] in networks: if data['name'] in networks:
msg = _("Network pool name already in use") msg = _("Network pool name already in use")
error_messages.append(msg) error_messages.append(msg)
if data['forward'] == 'bridge' and data['bridge_name'] == '': if data['forward'] in ['bridge', 'macvtap'] and data['bridge_name'] == '':
error_messages.append(_('Please enter bridge name')) error_messages.append(_('Please enter bridge/dev name'))
if data['subnet']: if data['subnet']:
ipv4 = True ipv4 = True
gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4']) gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4'])

View file

@ -841,7 +841,7 @@ class wvmConnect(object):
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
if raw_mem_size: if raw_mem_size:
mem = int(mem) * (1024 * 1024) mem = int(mem) * (1024 * 1024)
cur_vcpu = util.get_xpath(doc, "/domain/vcpu/@current") cur_vcpu = util.get_xpath(doc, "/domain/vcpu/@current")
@ -875,7 +875,7 @@ class wvmConnect(object):
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
cur_vcpu = util.get_xpath(ctx, "/domain/vcpu/@current") cur_vcpu = util.get_xpath(ctx, "/domain/vcpu/@current")
if cur_vcpu: if cur_vcpu:
vcpu = cur_vcpu vcpu = cur_vcpu

View file

@ -32,7 +32,7 @@ class wvmInstances(wvmConnect):
def get_instance_memory(self, name): def get_instance_memory(self, name):
inst = self.get_instance(name) inst = self.get_instance(name)
mem = util.get_xml_path(inst.XMLDesc(0), "/domain/currentMemory") mem = util.get_xml_path(inst.XMLDesc(0), "/domain/currentMemory")
return int(mem) / 1024 return int(mem) // 1024
def get_instance_vcpu(self, name): def get_instance_vcpu(self, name):
inst = self.get_instance(name) inst = self.get_instance(name)
@ -242,11 +242,11 @@ class wvmInstance(wvmConnect):
def get_memory(self): def get_memory(self):
mem = util.get_xml_path(self._XMLDesc(0), "/domain/memory") mem = util.get_xml_path(self._XMLDesc(0), "/domain/memory")
return int(mem) / 1024 return int(mem) // 1024
def get_cur_memory(self): def get_cur_memory(self):
mem = util.get_xml_path(self._XMLDesc(0), "/domain/currentMemory") mem = util.get_xml_path(self._XMLDesc(0), "/domain/currentMemory")
return int(mem) / 1024 return int(mem) // 1024
def get_title(self): def get_title(self):
title = util.get_xml_path(self._XMLDesc(0), "/domain/title") title = util.get_xml_path(self._XMLDesc(0), "/domain/title")
@ -345,6 +345,7 @@ class wvmInstance(wvmConnect):
result = [] result = []
inbound = outbound = [] inbound = outbound = []
for net in ctx.xpath('/domain/devices/interface'): for net in ctx.xpath('/domain/devices/interface'):
interface_type = net.xpath('@type')[0]
mac_inst = net.xpath('mac/@address')[0] mac_inst = net.xpath('mac/@address')[0]
nic_inst = net.xpath('source/@network|source/@bridge|source/@dev')[0] nic_inst = net.xpath('source/@network|source/@bridge|source/@dev')[0]
target_inst = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0] target_inst = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0]
@ -369,6 +370,7 @@ class wvmInstance(wvmConnect):
except libvirtError: except libvirtError:
ipv4, ipv6 = None, None ipv4, ipv6 = None, None
result.append({ result.append({
'type': interface_type,
'mac': mac_inst, 'mac': mac_inst,
'nic': nic_inst, 'nic': nic_inst,
'target': target_inst, 'target': target_inst,
@ -993,7 +995,7 @@ class wvmInstance(wvmConnect):
except SyntaxError: except SyntaxError:
# Little fix for old version ElementTree # Little fix for old version ElementTree
graphic = root.find("devices/graphics") graphic = root.find("devices/graphics")
if keymap: if keymap != 'auto':
graphic.set('keymap', keymap) graphic.set('keymap', keymap)
else: else:
try: try:
@ -1289,24 +1291,39 @@ class wvmInstance(wvmConnect):
bridge_name = iface.name() bridge_name = iface.name()
else: else:
net = self.get_network(source) net = self.get_network(source)
bridge_name = net.bridgeName() try:
bridge_name = net.bridgeName()
except libvirtError:
bridge_name = None
return bridge_name return bridge_name
def add_network(self, mac_address, source, source_type='net', model='virtio', nwfilter=None): def add_network(self, mac_address, source, source_type='net', model='virtio', nwfilter=None):
bridge_name = self.get_bridge_name(source, source_type) forward_mode = ''
if source_type != 'iface':
forward_mode = self.get_network_forward(source)
forward_mode = self.get_network_forward(source)
if forward_mode in ['nat', 'isolated', 'routed']: if forward_mode in ['nat', 'isolated', 'routed']:
interface_type = 'network' interface_type = 'network'
elif forward_mode == '':
interface_type = 'direct'
else: else:
interface_type = 'bridge' if self.get_bridge_name(source, source_type) is None:
interface_type = 'network'
else:
interface_type = 'bridge'
xml_iface = f""" xml_iface = f"""
<interface type='{interface_type}'> <interface type='{interface_type}'>
<mac address='{mac_address}'/>""" <mac address='{mac_address}'/>"""
if interface_type == 'network': if interface_type == 'network':
xml_iface += f"""<source network='{source}'/>""" xml_iface += f"""<source network='{source}'/>"""
elif interface_type == 'direct':
if source_type == 'net':
xml_iface += f"""<source network='{source}' mode='bridge'/>"""
else:
xml_iface += f"""<source dev='{source}' mode='bridge'/>"""
else: else:
bridge_name = self.get_bridge_name(source, source_type)
xml_iface += f"""<source bridge='{bridge_name}'/>""" xml_iface += f"""<source bridge='{bridge_name}'/>"""
xml_iface += f"""<model type='{model}'/>""" xml_iface += f"""<model type='{model}'/>"""
if nwfilter: if nwfilter:
@ -1342,49 +1359,38 @@ class wvmInstance(wvmConnect):
net_source_type = network_data.get('net-source-' + str(num) + '-type') net_source_type = network_data.get('net-source-' + str(num) + '-type')
net_filter = network_data.get('net-nwfilter-' + str(num)) net_filter = network_data.get('net-nwfilter-' + str(num))
net_model = network_data.get('net-model-' + str(num)) net_model = network_data.get('net-model-' + str(num))
bridge_name = self.get_bridge_name(net_source, net_source_type)
source = interface.find('source')
if interface.get('type') == 'bridge': if interface.get('type') == 'bridge':
source = interface.find('mac') bridge_name = self.get_bridge_name(net_source, net_source_type)
source.set('address', net_mac)
source = interface.find('source')
source.set('bridge', bridge_name) source.set('bridge', bridge_name)
elif interface.get('type') in ['network', 'direct']:
source = interface.find('model') if net_source_type == 'net':
if net_model != 'default': source.set('network', net_source)
source.attrib['type'] = net_model elif net_source_type == 'iface':
source.set('dev', net_source)
else: else:
interface.remove(source) raise libvirtError(f"Unknown network type: {net_source_type}")
else:
raise libvirtError(f"Unknown network type: {interface.get('type')}")
source = interface.find('filterref') source = interface.find('model')
if net_filter: if net_model != 'default':
if source is not None: source.set('filter', net_filter) source.attrib['type'] = net_model
else: else:
element = ElementTree.Element("filterref") interface.remove(source)
element.attrib['filter'] = net_filter
interface.append(element)
else:
if source is not None: interface.remove(source)
elif interface.get('type') == 'network':
source = interface.find('mac')
source.set('address', net_mac)
source = interface.find('source')
source.set('network', net_source)
source = interface.find('model') source = interface.find('mac')
if net_model != 'default': source.set('address', net_mac)
source.attrib['type'] = net_model source = interface.find('filterref')
if net_filter:
if source is not None: source.set('filter', net_filter)
else: else:
interface.remove(source) element = ElementTree.Element("filterref")
element.attrib['filter'] = net_filter
source = interface.find('filterref') interface.append(element)
if net_filter: else:
if source is not None: source.set('filter', net_filter) if source is not None: interface.remove(source)
else:
element = ElementTree.Element("filterref")
element.attrib['filter'] = net_filter
interface.append(element)
else:
if source is not None: interface.remove(source)
new_xml = ElementTree.tostring(tree).decode() new_xml = ElementTree.tostring(tree).decode()
self._defineXML(new_xml) self._defineXML(new_xml)

View file

@ -1,4 +1,5 @@
from lxml import etree from lxml import etree
from libvirt import libvirtError
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
@ -32,7 +33,11 @@ class wvmNetworks(wvmConnect):
for network in get_networks: for network in get_networks:
net = self.get_network(network) net = self.get_network(network)
net_status = net.isActive() net_status = net.isActive()
net_bridge = net.bridgeName() try:
net_bridge = net.bridgeName()
except libvirtError:
net_bridge = util.get_xml_path(net.XMLDesc(0), "/network/forward/interface/@dev")
net_forward = util.get_xml_path(net.XMLDesc(0), "/network/forward/@mode") net_forward = util.get_xml_path(net.XMLDesc(0), "/network/forward/@mode")
networks.append({'name': network, 'status': net_status, networks.append({'name': network, 'status': net_status,
'device': net_bridge, 'forward': net_forward}) 'device': net_bridge, 'forward': net_forward})
@ -50,15 +55,20 @@ class wvmNetworks(wvmConnect):
<name>{name}</name>""" <name>{name}</name>"""
if forward in ['nat', 'route', 'bridge']: if forward in ['nat', 'route', 'bridge']:
xml += f"""<forward mode='{forward}'/>""" xml += f"""<forward mode='{forward}'/>"""
xml += """<bridge """ if forward == 'macvtap':
if forward in ['nat', 'route', 'none']: xml += f"""<forward mode='bridge'>
xml += """stp='on' delay='0'""" <interface dev='{bridge}'/>
if forward == 'bridge': </forward>"""
xml += f"""name='{bridge}'""" else:
xml += """/>""" xml += """<bridge """
if openvswitch is True: if forward in ['nat', 'route', 'none']:
xml += """<virtualport type='openvswitch'/>""" xml += """stp='on' delay='0'"""
if forward != 'bridge': if forward == 'bridge':
xml += f"""name='{bridge}'"""
xml += """/>"""
if openvswitch is True:
xml += """<virtualport type='openvswitch'/>"""
if forward not in ['bridge', 'macvtap']:
if ipv4: if ipv4:
xml += f"""<ip address='{gateway}' netmask='{mask}'>""" xml += f"""<ip address='{gateway}' netmask='{mask}'>"""
if dhcp4: if dhcp4:
@ -114,7 +124,7 @@ class wvmNetwork(wvmConnect):
try: try:
return self.net.bridgeName() return self.net.bridgeName()
except: except:
return None return util.get_xml_path(self._XMLDesc(0), "/network/forward/interface/@dev")
def start(self): def start(self):
self.net.create() self.net.create()

View file

@ -19,8 +19,11 @@ urlpatterns = [
] ]
if settings.DEBUG: if settings.DEBUG:
import debug_toolbar try:
import debug_toolbar
urlpatterns += [ urlpatterns += [
path('__debug__/', include(debug_toolbar.urls)), path('__debug__/', include(debug_toolbar.urls)),
] ]
except:
pass