mirror of
https://github.com/retspen/webvirtcloud
synced 2025-03-23 05:23:00 +00:00
commit
8e4073f4b7
36 changed files with 16100 additions and 11347 deletions
README.md
accounts/templates
admin
appsettings/templates
computes
console/templates
doc/images
instances
locale
de/LC_MESSAGES
en/LC_MESSAGES
es/LC_MESSAGES
fr/LC_MESSAGES
nl/LC_MESSAGES
ru/LC_MESSAGES
tr/LC_MESSAGES
uk/LC_MESSAGES
networks
vrtManager
webvirtcloud
10
README.md
10
README.md
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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__'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 (image error) Size: 27 KiB After (image error) Size: 32 KiB |
Binary file not shown.
Before (image error) Size: 20 KiB After (image error) Size: 22 KiB |
Binary file not shown.
Before (image error) Size: 20 KiB After (image error) Size: 20 KiB |
Binary file not shown.
Before (image error) Size: 32 KiB After (image error) Size: 28 KiB |
Binary file not shown.
Before (image error) Size: 25 KiB After (image error) Size: 24 KiB |
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
@ -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'))
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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'])
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue