1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-11-01 03:54:15 +00:00

lint with black python. convert f style strings to old one. some small fixes

This commit is contained in:
catborise 2020-11-05 12:34:31 +03:00
parent c20c353a40
commit 508e3609be
54 changed files with 2123 additions and 1824 deletions

View file

@ -8,7 +8,7 @@ def apply_change_password(sender, **kwargs):
Depending on settings SHOW_PROFILE_EDIT_PASSWORD Depending on settings SHOW_PROFILE_EDIT_PASSWORD
''' '''
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import Permission, User
if hasattr(settings, 'SHOW_PROFILE_EDIT_PASSWORD'): if hasattr(settings, 'SHOW_PROFILE_EDIT_PASSWORD'):
print('\033[1m! \033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m') print('\033[1m! \033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m')
print('\033[1m* \033[92mApplying permission can_change_password for all users\033[0m') print('\033[1m* \033[92mApplying permission can_change_password for all users\033[0m')
@ -29,8 +29,8 @@ def create_admin(sender, **kwargs):
''' '''
Create initial admin user Create initial admin user
''' '''
from django.contrib.auth.models import User
from accounts.models import UserAttributes from accounts.models import UserAttributes
from django.contrib.auth.models import User
plan = kwargs.get('plan', []) plan = kwargs.get('plan', [])
for migration, rolled_back in plan: for migration, rolled_back in plan:

View file

@ -1,9 +1,8 @@
# Generated by Django 2.2.10 on 2020-01-28 07:01 # Generated by Django 2.2.10 on 2020-01-28 07:01
from django.conf import settings
import django.core.validators import django.core.validators
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):

View file

@ -1,7 +1,8 @@
from django import template
import base64 import base64
import hashlib import hashlib
from django import template
register = template.Library() register = template.Library()

View file

@ -35,11 +35,11 @@ def validate_ssh_key(key):
return False return False
# unpack the contents of data, from data[:4] , property of ssh key . # unpack the contents of data, from data[:4] , property of ssh key .
try: try:
str_len = struct.unpack('>I', data[:4])[0] str_len = struct.unpack(">I", data[:4])[0]
except struct.error: except struct.error:
return False return False
# data[4:str_len] must have string which matches with the typeofkey, another ssh key property. # data[4:str_len] must have string which matches with the typeofkey, another ssh key property.
if data[4:4 + str_len] == typeofkey: if data[4 : 4 + str_len] == typeofkey:
return True return True
else: else:
return False return False
@ -47,15 +47,15 @@ def validate_ssh_key(key):
def send_email_with_otp(user, device): def send_email_with_otp(user, device):
send_mail( send_mail(
_('OTP QR Code'), _("OTP QR Code"),
_('Please view HTML version of this message.'), _("Please view HTML version of this message."),
None, None,
[user.email], [user.email],
html_message=render_to_string( html_message=render_to_string(
'accounts/email/otp.html', "accounts/email/otp.html",
{ {
'totp_url': device.config_url, "totp_url": device.config_url,
'user': user, "user": user,
}, },
), ),
fail_silently=False, fail_silently=False,

View file

@ -23,40 +23,52 @@ def profile(request):
if profile_form.is_valid(): if profile_form.is_valid():
profile_form.save() profile_form.save()
messages.success(request, _('Profile updated')) messages.success(request, _("Profile updated"))
return redirect('accounts:profile') return redirect("accounts:profile")
return render(request, "profile.html", { return render(
'publickeys': publickeys, request,
'profile_form': profile_form, "profile.html",
'ssh_key_form': ssh_key_form, {
}) "publickeys": publickeys,
"profile_form": profile_form,
"ssh_key_form": ssh_key_form,
},
)
def ssh_key_create(request): def ssh_key_create(request):
key_form = UserSSHKeyForm(request.POST or None, user=request.user) key_form = UserSSHKeyForm(request.POST or None, user=request.user)
if key_form.is_valid(): if key_form.is_valid():
key_form.save() key_form.save()
messages.success(request, _('SSH key added')) messages.success(request, _("SSH key added"))
return redirect('accounts:profile') return redirect("accounts:profile")
return render(request, 'common/form.html', { return render(
'form': key_form, request,
'title': _('Add SSH key'), "common/form.html",
}) {
"form": key_form,
"title": _("Add SSH key"),
},
)
def ssh_key_delete(request, pk): def ssh_key_delete(request, pk):
ssh_key = get_object_or_404(UserSSHKey, pk=pk, user=request.user) ssh_key = get_object_or_404(UserSSHKey, pk=pk, user=request.user)
if request.method == 'POST': if request.method == "POST":
ssh_key.delete() ssh_key.delete()
messages.success(request, _('SSH key deleted')) messages.success(request, _("SSH key deleted"))
return redirect('accounts:profile') return redirect("accounts:profile")
return render(request, 'common/confirm_delete.html', { return render(
'object': ssh_key, request,
'title': _('Delete SSH key'), "common/confirm_delete.html",
}) {
"object": ssh_key,
"title": _("Delete SSH key"),
},
)
@superuser_only @superuser_only
@ -67,13 +79,16 @@ def account(request, user_id):
publickeys = UserSSHKey.objects.filter(user_id=user_id) publickeys = UserSSHKey.objects.filter(user_id=user_id)
return render( return render(
request, "account.html", { request,
'user': user, "account.html",
'user_insts': user_insts, {
'instances': instances, "user": user,
'publickeys': publickeys, "user_insts": user_insts,
'otp_enabled': settings.OTP_ENABLED, "instances": instances,
}) "publickeys": publickeys,
"otp_enabled": settings.OTP_ENABLED,
},
)
@permission_required("accounts.change_password", raise_exception=True) @permission_required("accounts.change_password", raise_exception=True)
@ -118,7 +133,7 @@ def user_instance_update(request, pk):
return render( return render(
request, request,
'common/form.html', "common/form.html",
{ {
"form": form, "form": form,
"title": _("Update User Instance"), "title": _("Update User Instance"),
@ -150,29 +165,33 @@ def email_otp(request):
if form.is_valid(): if form.is_valid():
UserModel = get_user_model() UserModel = get_user_model()
try: try:
user = UserModel.objects.get(email=form.cleaned_data['email']) user = UserModel.objects.get(email=form.cleaned_data["email"])
except UserModel.DoesNotExist: except UserModel.DoesNotExist:
pass pass
else: else:
device = get_user_totp_device(user) device = get_user_totp_device(user)
send_email_with_otp(user, device) send_email_with_otp(user, device)
messages.success(request, _('OTP Sent to %s') % form.cleaned_data['email']) messages.success(request, _("OTP Sent to %(email)s") % {"email": form.cleaned_data["email"]})
return redirect('accounts:login') return redirect("accounts:login")
return render(request, 'accounts/email_otp_form.html', { return render(
'form': form, request,
'title': _('Email OTP'), "accounts/email_otp_form.html",
}) {
"form": form,
"title": _("Email OTP"),
},
)
@superuser_only @superuser_only
def admin_email_otp(request, user_id): def admin_email_otp(request, user_id):
user = get_object_or_404(get_user_model(), pk=user_id) user = get_object_or_404(get_user_model(), pk=user_id)
device = get_user_totp_device(user) device = get_user_totp_device(user)
if user.email != '': if user.email != "":
send_email_with_otp(user, device) send_email_with_otp(user, device)
messages.success(request, _('OTP QR code was emailed to user %s') % user) messages.success(request, _("OTP QR code was emailed to user %(user)s") % {"user": user})
else: else:
messages.error(request, _('User email not set, failed to send QR code')) messages.error(request, _("User email not set, failed to send QR code"))
return redirect('accounts:account', user.id) return redirect("accounts:account", user.id)

View file

@ -1,6 +1,6 @@
from django import forms from django import forms
from django.contrib.auth.models import Group, User
from django.contrib.auth.forms import ReadOnlyPasswordHashField from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.auth.models import Group, User
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.text import format_lazy from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -13,7 +13,7 @@ from .models import Permission
class GroupForm(forms.ModelForm): class GroupForm(forms.ModelForm):
permissions = forms.ModelMultipleChoiceField( permissions = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple, widget=forms.CheckboxSelectMultiple,
queryset=Permission.objects.filter(content_type__model='permissionset'), queryset=Permission.objects.filter(content_type__model="permissionset"),
required=False, required=False,
) )
@ -25,12 +25,12 @@ class GroupForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(GroupForm, self).__init__(*args, **kwargs) super(GroupForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None) instance = getattr(self, "instance", None)
if instance and instance.id: if instance and instance.id:
self.fields['users'].initial = self.instance.user_set.all() self.fields["users"].initial = self.instance.user_set.all()
def save_m2m(self): def save_m2m(self):
self.instance.user_set.set(self.cleaned_data['users']) self.instance.user_set.set(self.cleaned_data["users"])
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
instance = super(GroupForm, self).save() instance = super(GroupForm, self).save()
@ -39,36 +39,36 @@ class GroupForm(forms.ModelForm):
class Meta: class Meta:
model = Group model = Group
fields = '__all__' fields = "__all__"
class UserForm(forms.ModelForm): class UserForm(forms.ModelForm):
user_permissions = forms.ModelMultipleChoiceField( user_permissions = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple, widget=forms.CheckboxSelectMultiple,
queryset=Permission.objects.filter(content_type__model='permissionset'), queryset=Permission.objects.filter(content_type__model="permissionset"),
label=_('Permissions'), label=_("Permissions"),
required=False, required=False,
) )
groups = forms.ModelMultipleChoiceField( groups = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple, widget=forms.CheckboxSelectMultiple,
queryset=Group.objects.all(), queryset=Group.objects.all(),
label=_('Groups'), label=_("Groups"),
required=False, required=False,
) )
class Meta: class Meta:
model = User model = User
fields = [ fields = [
'username', "username",
'groups', "groups",
'first_name', "first_name",
'last_name', "last_name",
'email', "email",
'user_permissions', "user_permissions",
'is_staff', "is_staff",
'is_active', "is_active",
'is_superuser', "is_superuser",
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -76,12 +76,20 @@ class UserForm(forms.ModelForm):
if self.instance.id: if self.instance.id:
password = ReadOnlyPasswordHashField( password = ReadOnlyPasswordHashField(
label=_("Password"), label=_("Password"),
help_text=format_lazy(_("""Raw passwords are not stored, so there is no way to see help_text=format_lazy(
this user's password, but you can change the password using <a href='{}'>this form</a>."""), _(
reverse_lazy('admin:user_update_password', """Raw passwords are not stored, so there is no way to see this user's password,
args=[self.instance.id,])) 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 self.fields["Password"] = password
class UserCreateForm(UserForm): class UserCreateForm(UserForm):
@ -90,20 +98,20 @@ class UserCreateForm(UserForm):
class Meta: class Meta:
model = User model = User
fields = [ fields = [
'username', "username",
'password', "password",
'groups', "groups",
'first_name', "first_name",
'last_name', "last_name",
'email', "email",
'user_permissions', "user_permissions",
'is_staff', "is_staff",
'is_active', "is_active",
'is_superuser', "is_superuser",
] ]
class UserAttributesForm(forms.ModelForm): class UserAttributesForm(forms.ModelForm):
class Meta: class Meta:
model = UserAttributes model = UserAttributes
exclude = ['user', 'can_clone_instances'] exclude = ["user", "can_clone_instances"]

View file

@ -50,7 +50,7 @@ def group_update(request, pk):
form = forms.GroupForm(request.POST or None, instance=group) form = forms.GroupForm(request.POST or None, instance=group)
if form.is_valid(): if form.is_valid():
form.save() form.save()
return redirect('admin:group_list') return redirect("admin:group_list")
return render( return render(
request, request,
@ -107,11 +107,7 @@ def user_create(request):
return render( return render(
request, request,
"admin/user_form.html", "admin/user_form.html",
{ {"user_form": user_form, "attributes_form": attributes_form, "title": _("Create User")},
"user_form": user_form,
"attributes_form": attributes_form,
"title": _("Create User")
},
) )
@ -124,29 +120,25 @@ def user_update(request, pk):
if user_form.is_valid() and attributes_form.is_valid(): if user_form.is_valid() and attributes_form.is_valid():
user_form.save() user_form.save()
attributes_form.save() attributes_form.save()
next = request.GET.get('next') next = request.GET.get("next")
return redirect(next or "admin:user_list") return redirect(next or "admin:user_list")
return render( return render(
request, request,
"admin/user_form.html", "admin/user_form.html",
{ {"user_form": user_form, "attributes_form": attributes_form, "title": _("Update User")},
"user_form": user_form,
"attributes_form": attributes_form,
"title": _("Update User")
},
) )
@superuser_only @superuser_only
def user_update_password(request, pk): def user_update_password(request, pk):
user = get_object_or_404(User, pk=pk) user = get_object_or_404(User, pk=pk)
if request.method == 'POST': if request.method == "POST":
form = AdminPasswordChangeForm(user, request.POST) form = AdminPasswordChangeForm(user, request.POST)
if form.is_valid(): if form.is_valid():
user = form.save() user = form.save()
update_session_auth_hash(request, user) # Important! update_session_auth_hash(request, user) # Important!
messages.success(request, _("User password changed: {}".format(user.username))) messages.success(request, _("Password changed for %(user)s") % {"user": user.username})
return redirect("admin:user_list") return redirect("admin:user_list")
else: else:
messages.error(request, _("Wrong Data Provided")) messages.error(request, _("Wrong Data Provided"))

View file

@ -29,13 +29,13 @@ def appsettings(request):
# Bootstrap settings related with filesystems, because of that they are excluded from other settings # Bootstrap settings related with filesystems, because of that they are excluded from other settings
appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name") appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name")
if request.method == 'POST': if request.method == "POST":
if 'SASS_DIR' in request.POST: if "SASS_DIR" in request.POST:
try: try:
sass_dir.value = request.POST.get("SASS_DIR", "") sass_dir.value = request.POST.get("SASS_DIR", "")
sass_dir.save() sass_dir.save()
msg = _(f"SASS directory path is changed. Now: {sass_dir.value}") msg = _("SASS directory path is changed. Now: %(dir)s") % {"dir": sass_dir.value}
messages.success(request, msg) messages.success(request, msg)
except Exception as err: except Exception as err:
msg = err msg = err
@ -44,7 +44,7 @@ def appsettings(request):
addlogmsg(request.user.username, "", msg) addlogmsg(request.user.username, "", msg)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'BOOTSTRAP_THEME' in request.POST: if "BOOTSTRAP_THEME" in request.POST:
theme = request.POST.get("BOOTSTRAP_THEME", "") theme = request.POST.get("BOOTSTRAP_THEME", "")
scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';" scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';"
scss_bootswatch = f"@import '{sass_dir.value}/wvc-theme/{theme}/bootswatch';" scss_bootswatch = f"@import '{sass_dir.value}/wvc-theme/{theme}/bootswatch';"
@ -54,15 +54,17 @@ def appsettings(request):
with open(sass_dir.value + "/wvc-main.scss", "w") as main: with open(sass_dir.value + "/wvc-main.scss", "w") as main:
main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch + "\n") main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch + "\n")
css_compressed = sass.compile(string=scss_var + "\n" + scss_boot + "\n" + scss_bootswatch, css_compressed = sass.compile(
output_style='compressed') string=scss_var + "\n" + scss_boot + "\n" + scss_bootswatch,
output_style="compressed",
)
with open("static/css/" + main_css, "w") as css: with open("static/css/" + main_css, "w") as css:
css.write(css_compressed) css.write(css_compressed)
bootstrap_theme.value = theme bootstrap_theme.value = theme
bootstrap_theme.save() bootstrap_theme.save()
msg = _(f"Theme changed. Now: {theme}") msg = _("Theme is changed. Now: %(theme)s") % {"theme": theme}
messages.success(request, msg) messages.success(request, msg)
except Exception as err: except Exception as err:
msg = err msg = err
@ -77,7 +79,7 @@ def appsettings(request):
setting.value = request.POST.get(setting.key, "") setting.value = request.POST.get(setting.key, "")
setting.save() setting.save()
msg = _(f"{setting.name} is changed. Now: {setting.value}") msg = _("%(setting)s is changed. Now: %(value)s") % {"setting": setting.name, "value": setting.value}
messages.success(request, msg) messages.success(request, msg)
except Exception as err: except Exception as err:
msg = err msg = err
@ -86,4 +88,4 @@ def appsettings(request):
addlogmsg(request.user.username, "", msg) addlogmsg(request.user.username, "", msg)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
return render(request, 'appsettings.html', locals()) return render(request, "appsettings.html", locals())

View file

@ -1,7 +1,6 @@
from secrets.views import secrets from secrets.views import secrets
from django.urls import include, path from django.urls import include, path
# from instances.views import create_instance, create_instance_select_type # from instances.views import create_instance, create_instance_select_type
from interfaces.views import interface, interfaces from interfaces.views import interface, interfaces
from networks.views import network, networks from networks.views import network, networks

View file

@ -1,8 +1,8 @@
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
import re import re
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
have_symbol = re.compile('[^a-zA-Z0-9._-]+') have_symbol = re.compile('[^a-zA-Z0-9._-]+')
wrong_ip = re.compile('^0.|^255.') wrong_ip = re.compile('^0.|^255.')
wrong_name = re.compile('[^a-zA-Z0-9._-]+') wrong_name = re.compile('[^a-zA-Z0-9._-]+')

View file

@ -1,18 +1,23 @@
import json import json
from django.contrib import messages from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect, render
from django.shortcuts import get_object_or_404, redirect, render, reverse
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from libvirt import libvirtError from libvirt import libvirtError
from accounts.models import UserInstance
from admin.decorators import superuser_only from admin.decorators import superuser_only
from computes.forms import (SocketComputeForm, SshComputeForm, TcpComputeForm, TlsComputeForm) from computes.forms import SocketComputeForm, SshComputeForm, TcpComputeForm, TlsComputeForm
from computes.models import Compute from computes.models import Compute
from instances.models import Instance from instances.models import Instance
from vrtManager.connection import (CONN_SOCKET, CONN_SSH, CONN_TCP, CONN_TLS, connection_manager, wvmConnect) from vrtManager.connection import (
CONN_SOCKET,
CONN_SSH,
CONN_TCP,
CONN_TLS,
connection_manager,
wvmConnect,
)
from vrtManager.hostdetails import wvmHostDetails from vrtManager.hostdetails import wvmHostDetails
from . import utils from . import utils
@ -25,15 +30,17 @@ def computes(request):
:return: :return:
""" """
computes = Compute.objects.filter().order_by('name') computes = Compute.objects.filter().order_by("name")
return render(request, 'computes/list.html', {'computes': computes}) return render(request, "computes/list.html", {"computes": computes})
@superuser_only @superuser_only
def overview(request, compute_id): def overview(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
status = 'true' if connection_manager.host_is_up(compute.type, compute.hostname) is True else 'false' status = (
"true" if connection_manager.host_is_up(compute.type, compute.hostname) is True else "false"
)
conn = wvmHostDetails( conn = wvmHostDetails(
compute.hostname, compute.hostname,
@ -49,7 +56,7 @@ def overview(request, compute_id):
lib_version = conn.get_lib_version() lib_version = conn.get_lib_version()
conn.close() conn.close()
return render(request, 'overview.html', locals()) return render(request, "overview.html", locals())
@superuser_only @superuser_only
@ -57,9 +64,9 @@ def instances(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
utils.refresh_instance_database(compute) utils.refresh_instance_database(compute)
instances = Instance.objects.filter(compute=compute).prefetch_related('userinstance_set') instances = Instance.objects.filter(compute=compute).prefetch_related("userinstance_set")
return render(request, 'computes/instances.html', {'compute': compute, 'instances': instances}) return render(request, "computes/instances.html", {"compute": compute, "instances": instances})
@superuser_only @superuser_only
@ -67,9 +74,9 @@ def compute_create(request, FormClass):
form = FormClass(request.POST or None) form = FormClass(request.POST or None)
if form.is_valid(): if form.is_valid():
form.save() form.save()
return redirect(reverse('computes')) return redirect(reverse("computes"))
return render(request, 'computes/form.html', {'form': form}) return render(request, "computes/form.html", {"form": form})
@superuser_only @superuser_only
@ -88,22 +95,22 @@ def compute_update(request, compute_id):
form = FormClass(request.POST or None, instance=compute) form = FormClass(request.POST or None, instance=compute)
if form.is_valid(): if form.is_valid():
form.save() form.save()
return redirect(reverse('computes')) return redirect(reverse("computes"))
return render(request, 'computes/form.html', {'form': form}) return render(request, "computes/form.html", {"form": form})
@superuser_only @superuser_only
def compute_delete(request, compute_id): def compute_delete(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
if request.method == 'POST': if request.method == "POST":
compute.delete() compute.delete()
return redirect('computes') return redirect("computes")
return render( return render(
request, request,
'common/confirm_delete.html', "common/confirm_delete.html",
{'object': compute}, {"object": compute},
) )
@ -126,17 +133,19 @@ def compute_graph(request, compute_id):
mem_usage = conn.get_memory_usage() mem_usage = conn.get_memory_usage()
conn.close() conn.close()
except libvirtError: except libvirtError:
cpu_usage = {'usage': 0} cpu_usage = {"usage": 0}
mem_usage = {'usage': 0} mem_usage = {"usage": 0}
current_time = 0 current_time = 0
data = json.dumps({ data = json.dumps(
'cpudata': cpu_usage['usage'], {
'memdata': mem_usage, "cpudata": cpu_usage["usage"],
'timeline': current_time, "memdata": mem_usage,
}) "timeline": current_time,
}
)
response = HttpResponse() response = HttpResponse()
response['Content-Type'] = "text/javascript" response["Content-Type"] = "text/javascript"
response.write(data) response.write(data)
return response return response
@ -163,14 +172,14 @@ def get_compute_disk_buses(request, compute_id, arch, machine, disk):
disk_device_types = conn.get_disk_device_types(arch, machine) disk_device_types = conn.get_disk_device_types(arch, machine)
if disk in disk_device_types: if disk in disk_device_types:
if disk == 'disk': if disk == "disk":
data['bus'] = sorted(disk_device_types) data["bus"] = sorted(disk_device_types)
elif disk == 'cdrom': elif disk == "cdrom":
data['bus'] = ['ide', 'sata', 'scsi'] data["bus"] = ["ide", "sata", "scsi"]
elif disk == 'floppy': elif disk == "floppy":
data['bus'] = ['fdc'] data["bus"] = ["fdc"]
elif disk == 'lun': elif disk == "lun":
data['bus'] = ['scsi'] data["bus"] = ["scsi"]
except libvirtError: except libvirtError:
pass pass
@ -193,7 +202,7 @@ def get_compute_machine_types(request, compute_id, arch):
compute.password, compute.password,
compute.type, compute.type,
) )
data['machines'] = conn.get_machine_types(arch) data["machines"] = conn.get_machine_types(arch)
except libvirtError: except libvirtError:
pass pass
@ -217,7 +226,7 @@ def get_compute_video_models(request, compute_id, arch, machine):
compute.password, compute.password,
compute.type, compute.type,
) )
data['videos'] = conn.get_video_models(arch, machine) data["videos"] = conn.get_video_models(arch, machine)
except libvirtError: except libvirtError:
pass pass
@ -241,8 +250,8 @@ def get_dom_capabilities(request, compute_id, arch, machine):
compute.password, compute.password,
compute.type, compute.type,
) )
data['videos'] = conn.get_disk_device_types(arch, machine) data["videos"] = conn.get_disk_device_types(arch, machine)
data['bus'] = conn.get_disk_device_types(arch, machine) data["bus"] = conn.get_disk_device_types(arch, machine)
except libvirtError: except libvirtError:
pass pass

View file

@ -1,4 +1,5 @@
import random, string import random
import string
haystack = string.ascii_letters + string.digits + string.punctuation haystack = string.ascii_letters + string.digits + string.punctuation
print(''.join([random.SystemRandom().choice(haystack.replace('/', '').replace('\'', '').replace('\"', '')) for _ in range(50)])) print(''.join([random.SystemRandom().choice(haystack.replace('/', '').replace('\'', '').replace('\"', '')) for _ in range(50)]))

View file

@ -4,14 +4,13 @@
# See the COPYING file in the top-level directory. # See the COPYING file in the top-level directory.
import functools import functools
import logging as log
import os import os
import queue import queue
import socket
import signal import signal
import socket
import threading import threading
import logging as log
class _TunnelScheduler(object): class _TunnelScheduler(object):
""" """

View file

@ -6,7 +6,11 @@ from libvirt import libvirtError
from appsettings.settings import app_settings from appsettings.settings import app_settings
from instances.models import Instance from instances.models import Instance
from vrtManager.instance import wvmInstance from vrtManager.instance import wvmInstance
from webvirtcloud.settings import WS_PUBLIC_HOST, WS_PUBLIC_PATH, WS_PUBLIC_PORT from webvirtcloud.settings import (
WS_PUBLIC_HOST,
WS_PUBLIC_PATH,
WS_PUBLIC_PORT,
)
def console(request): def console(request):
@ -61,7 +65,7 @@ def console(request):
if console_type is None: if console_type is None:
console_error = "Fail to get console. Please check the console configuration of your VM." console_error = "Fail to get console. Please check the console configuration of your VM."
else: else:
console_error = f"Console type: {console_type} no support" console_error = "Console type '%(type)s' has not support" % {"type": console_type}
response = render(request, "console-vnc-lite.html", locals()) response = render(request, "console-vnc-lite.html", locals())
response.set_cookie("token", token) response.set_cookie("token", token)

View file

@ -1,4 +1,5 @@
from django.urls import path from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [

View file

@ -1,14 +1,16 @@
import json import json
import socket import socket
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from libvirt import libvirtError from libvirt import libvirtError
from accounts.models import UserInstance, UserSSHKey from accounts.models import UserInstance, UserSSHKey
from computes.models import Compute from computes.models import Compute
from vrtManager.instance import wvmInstance from vrtManager.instance import wvmInstance
OS_VERSIONS = ['latest', ''] OS_VERSIONS = ["latest", ""]
OS_UUID = "iid-dswebvirtcloud" OS_UUID = "iid-dswebvirtcloud"
@ -17,7 +19,7 @@ def os_index(request):
:param request: :param request:
:return: :return:
""" """
response = '\n'.join(OS_VERSIONS) response = "\n".join(OS_VERSIONS)
return HttpResponse(response) return HttpResponse(response)
@ -28,13 +30,13 @@ def os_metadata_json(request, version):
:return: :return:
""" """
if version == 'latest': if version == "latest":
ip = get_client_ip(request) ip = get_client_ip(request)
hostname = get_hostname_by_ip(ip) hostname = get_hostname_by_ip(ip)
response = {'uuid': OS_UUID, 'hostname': hostname} response = {"uuid": OS_UUID, "hostname": hostname}
return HttpResponse(json.dumps(response)) return HttpResponse(json.dumps(response))
else: else:
err = f"Invalid version: {version}" err = "Invalid version: %(version)s" % {"version": version}
raise Http404(err) raise Http404(err)
@ -44,10 +46,10 @@ def os_userdata(request, version):
:param version: :param version:
:return: :return:
""" """
if version == 'latest': if version == "latest":
ip = get_client_ip(request) ip = get_client_ip(request)
hostname = get_hostname_by_ip(ip) hostname = get_hostname_by_ip(ip)
vname = hostname.split('.')[0] vname = hostname.split(".")[0]
instance_keys = [] instance_keys = []
userinstances = UserInstance.objects.filter(instance__name=vname) userinstances = UserInstance.objects.filter(instance__name=vname)
@ -57,9 +59,9 @@ def os_userdata(request, version):
for k in keys: for k in keys:
instance_keys.append(k.keypublic) instance_keys.append(k.keypublic)
return render(request, 'user_data', locals()) return render(request, "user_data", locals())
else: else:
err = f"Invalid version: {version}" err = "Invalid version: %(version)s" % {"version": version}
raise Http404(err) raise Http404(err)
@ -68,11 +70,11 @@ def get_client_ip(request):
:param request: :param request:
:return: :return:
""" """
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
if x_forwarded_for: if x_forwarded_for:
ip = x_forwarded_for.split(',')[-1].strip() ip = x_forwarded_for.split(",")[-1].strip()
else: else:
ip = request.META.get('REMOTE_ADDR') ip = request.META.get("REMOTE_ADDR")
return ip return ip
@ -97,16 +99,12 @@ def get_vdi_url(request, compute_id, vname):
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
try: try:
conn = wvmInstance(compute.hostname, conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, vname)
compute.login,
compute.password,
compute.type,
vname)
fqdn = get_hostname_by_ip(compute.hostname) fqdn = get_hostname_by_ip(compute.hostname)
url = f"{conn.get_console_type()}://{fqdn}:{conn.get_console_port()}" url = f"{conn.get_console_type()}://{fqdn}:{conn.get_console_port()}"
response = url response = url
return HttpResponse(response) return HttpResponse(response)
except libvirtError: except libvirtError:
err = f"Error getting VDI URL for {vname}" err = "Error getting VDI URL for %(name)s" % {"name": vname}
raise Http404(err) raise Http404(err)

View file

@ -25,8 +25,8 @@ def apply_passwordless_console(sender, **kwargs):
''' '''
Apply new passwordless_console permission for all users Apply new passwordless_console permission for all users
''' '''
from django.contrib.auth.models import Permission
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
User = get_user_model() User = get_user_model()
plan = kwargs.get('plan', []) plan = kwargs.get('plan', [])
for migration, rolled_back in plan: for migration, rolled_back in plan:

View file

@ -1,7 +1,6 @@
# Generated by Django 2.2.10 on 2020-01-28 07:01 # Generated by Django 2.2.10 on 2020-01-28 07:01
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):

View file

@ -19,7 +19,7 @@
<div class="tab-content"> <div class="tab-content">
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="takesnapshot"> <div role="tabpanel" class="tab-pane tab-pane-bordered active" id="takesnapshot">
{% if instance.status == 5 %} {% if instance.status == 5 %}
<p>{% trans "This may take more than an hour, depending on how much content is on your droplet and how large the disk is." %}</p> <p>{% trans "This may take more than an hour, depending on how much content is on your instance and how large the disk is." %}</p>
<form action="{% url 'instances:snapshot' instance.id %}" class="form-inline" method="post" role="form" aria-label="Create snapshot form"> <form action="{% url 'instances:snapshot' instance.id %}" class="form-inline" method="post" role="form" aria-label="Create snapshot form">
{% csrf_token %} {% csrf_token %}
<div class="form-group row"> <div class="form-group row">

View file

@ -1,6 +1,7 @@
from django import template
import re import re
from django import template
register = template.Library() register = template.Library()

View file

@ -8,12 +8,11 @@ from django.contrib.auth.models import Permission
from django.http.response import Http404 from django.http.response import Http404
from django.shortcuts import reverse from django.shortcuts import reverse
from django.test import TestCase from django.test import TestCase
from instances.views import instance
from libvirt import VIR_DOMAIN_UNDEFINE_NVRAM from libvirt import VIR_DOMAIN_UNDEFINE_NVRAM
from vrtManager.create import wvmCreate from vrtManager.create import wvmCreate
from vrtManager.util import randomUUID from vrtManager.util import randomUUID
from instances.views import instance
from .models import Flavor, Instance from .models import Flavor, Instance
from .utils import refr from .utils import refr

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
import re import re
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _

View file

@ -26,19 +26,30 @@ def interfaces(request, compute_id):
try: try:
netdevs = conn.get_net_devices() netdevs = conn.get_net_devices()
except: except:
netdevs = ['eth0', 'eth1'] netdevs = ["eth0", "eth1"]
for iface in ifaces: for iface in ifaces:
ifaces_all.append(conn.get_iface_info(iface)) ifaces_all.append(conn.get_iface_info(iface))
if request.method == 'POST': if request.method == "POST":
if 'create' in request.POST: if "create" in request.POST:
form = AddInterface(request.POST) form = AddInterface(request.POST)
if form.is_valid(): if form.is_valid():
data = form.cleaned_data data = form.cleaned_data
conn.create_iface(data['name'], data['itype'], data['start_mode'], data['netdev'], data['ipv4_type'], conn.create_iface(
data['ipv4_addr'], data['ipv4_gw'], data['ipv6_type'], data['ipv6_addr'], data["name"],
data['ipv6_gw'], data['stp'], data['delay']) data["itype"],
data["start_mode"],
data["netdev"],
data["ipv4_type"],
data["ipv4_addr"],
data["ipv4_gw"],
data["ipv6_type"],
data["ipv6_addr"],
data["ipv6_gw"],
data["stp"],
data["delay"],
)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
else: else:
for msg_err in form.errors.values(): for msg_err in form.errors.values():
@ -47,7 +58,7 @@ def interfaces(request, compute_id):
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
return render(request, 'interfaces.html', locals()) return render(request, "interfaces.html", locals())
@superuser_only @superuser_only
@ -75,18 +86,18 @@ def interface(request, compute_id, iface):
bridge = conn.get_bridge() bridge = conn.get_bridge()
slave_ifaces = conn.get_bridge_slave_ifaces() 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:
conn.stop_iface() conn.stop_iface()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'start' in request.POST: if "start" in request.POST:
conn.start_iface() conn.start_iface()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'delete' in request.POST: if "delete" in request.POST:
conn.delete_iface() conn.delete_iface()
return HttpResponseRedirect(reverse('interfaces', args=[compute_id])) return HttpResponseRedirect(reverse("interfaces", args=[compute_id]))
conn.close() conn.close()
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
return render(request, 'interface.html', locals()) return render(request, "interface.html", locals())

View file

@ -1,12 +1,11 @@
from django.db.models import Model, CharField, DateTimeField from django.db.models import CharField, DateTimeField, Model
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
class Logs(Model): class Logs(Model):
user = CharField(_('user'), max_length=50) user = CharField(_("user"), max_length=50)
instance = CharField(_('instance'), max_length=50) instance = CharField(_("instance"), max_length=50)
message = CharField(_('message'), max_length=255) message = CharField(_("message"), max_length=255)
date = DateTimeField(_('date'), auto_now=True) date = DateTimeField(_("date"), auto_now=True)
def __str__(self): def __str__(self):
return self.instance return self.instance

View file

@ -1,6 +1,7 @@
from django.urls import path from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('vm_logs/<vname>/', views.vm_logs, name='vm_logs'), path("vm_logs/<vname>/", views.vm_logs, name="vm_logs"),
] ]

View file

@ -1,8 +1,6 @@
import json import json
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse
from django.shortcuts import render
from django.urls import reverse
from admin.decorators import superuser_only from admin.decorators import superuser_only
from instances.models import Instance from instances.models import Instance
@ -29,14 +27,14 @@ def vm_logs(request, vname):
""" """
vm = Instance.objects.get(name=vname) vm = Instance.objects.get(name=vname)
logs_ = Logs.objects.filter(instance=vm.name, date__gte=vm.created).order_by('-date') logs_ = Logs.objects.filter(instance=vm.name, date__gte=vm.created).order_by("-date")
logs = [] logs = []
for l in logs_: for l in logs_:
log = dict() log = dict()
log['user'] = l.user log["user"] = l.user
log['instance'] = l.instance log["instance"] = l.instance
log['message'] = l.message log["message"] = l.message
log['date'] = l.date.strftime('%x %X') log["date"] = l.date.strftime("%x %X")
logs.append(log) logs.append(log)
return HttpResponse(json.dumps(logs)) return HttpResponse(json.dumps(logs))

View file

@ -1,15 +1,21 @@
import re import re
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
class AddNetPool(forms.Form): class AddNetPool(forms.Form):
name = forms.CharField(error_messages={'required': _('No pool name has been entered')}, name = forms.CharField(error_messages={"required": _("No pool name has been entered")}, max_length=20)
max_length=20) subnet = forms.CharField(
subnet = forms.CharField(error_messages={'required': _('No IPv4 subnet has been entered')}, error_messages={"required": _("No IPv4 subnet has been entered")},
max_length=20, required=False) max_length=20,
subnet6 = forms.CharField(error_messages={'required': _('No IPv6 subnet has been entered')}, required=False,
max_length=42, required=False) )
subnet6 = forms.CharField(
error_messages={"required": _("No IPv6 subnet has been entered")},
max_length=42,
required=False,
)
forward = forms.CharField(max_length=100) forward = forms.CharField(max_length=100)
dhcp4 = forms.BooleanField(required=False) dhcp4 = forms.BooleanField(required=False)
dhcp6 = forms.BooleanField(required=False) dhcp6 = forms.BooleanField(required=False)
@ -18,38 +24,38 @@ class AddNetPool(forms.Form):
openvswitch = forms.BooleanField(required=False) openvswitch = forms.BooleanField(required=False)
def clean_name(self): def clean_name(self):
name = self.cleaned_data['name'] name = self.cleaned_data["name"]
have_symbol = re.match('^[a-zA-Z0-9\.\_\-]+$', name) have_symbol = re.match(r"^[a-zA-Z0-9\.\_\-]+$", name)
if not have_symbol: if not have_symbol:
raise forms.ValidationError(_('The pool name must not contain any special characters')) raise forms.ValidationError(_("The pool name must not contain any special characters"))
elif len(name) > 20: elif len(name) > 20:
raise forms.ValidationError(_('The pool name must not exceed 20 characters')) raise forms.ValidationError(_("The pool name must not exceed 20 characters"))
return name return name
def clean_subnet(self): def clean_subnet(self):
subnet = self.cleaned_data['subnet'] subnet = self.cleaned_data["subnet"]
have_symbol = re.match('^[0-9./]+$', subnet if subnet else ".") have_symbol = re.match("^[0-9./]+$", subnet if subnet else ".")
if not have_symbol: if not have_symbol:
raise forms.ValidationError(_('The IPv4 subnet must not contain any special characters')) raise forms.ValidationError(_("The IPv4 subnet must not contain any special characters"))
elif len(subnet) > 20: elif len(subnet) > 20:
raise forms.ValidationError(_('The IPv4 subnet must not exceed 20 characters')) raise forms.ValidationError(_("The IPv4 subnet must not exceed 20 characters"))
return subnet return subnet
def clean_subnet6(self): def clean_subnet6(self):
subnet = self.cleaned_data['subnet6'] subnet = self.cleaned_data["subnet6"]
have_symbol = re.match('^[0-9a-fA-F:/]+$', subnet if subnet else ":") have_symbol = re.match("^[0-9a-fA-F:/]+$", subnet if subnet else ":")
if not have_symbol: if not have_symbol:
raise forms.ValidationError(_('The IPv6 subnet must not contain any special characters')) raise forms.ValidationError(_("The IPv6 subnet must not contain any special characters"))
elif len(subnet) > 42: elif len(subnet) > 42:
raise forms.ValidationError(_('The IPv6 subnet must not exceed 42 characters')) raise forms.ValidationError(_("The IPv6 subnet must not exceed 42 characters"))
return subnet return subnet
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'] in ['bridge', 'macvtap']: if self.cleaned_data["forward"] in ["bridge", "macvtap"]:
have_symbol = re.match('^[a-zA-Z0-9\.\_\:\-]+$', bridge_name) have_symbol = re.match(r"^[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"))
elif len(bridge_name) > 20: elif len(bridge_name) > 20:
raise forms.ValidationError(_('The pool bridge name must not exceed 20 characters')) raise forms.ValidationError(_("The pool bridge name must not exceed 20 characters"))
return bridge_name return bridge_name

View file

@ -30,35 +30,37 @@ def networks(request, compute_id):
compute.type, compute.type,
) )
networks = conn.get_networks_info() networks = conn.get_networks_info()
dhcp4 = netmask4 = gateway4 = '' dhcp4 = netmask4 = gateway4 = ""
dhcp6 = prefix6 = gateway6 = '' dhcp6 = prefix6 = gateway6 = ""
ipv4 = ipv6 = False ipv4 = ipv6 = False
if request.method == 'POST': if request.method == "POST":
if 'create' in request.POST: if "create" in request.POST:
form = AddNetPool(request.POST) form = AddNetPool(request.POST)
if form.is_valid(): if form.is_valid():
data = form.cleaned_data data = form.cleaned_data
if data['name'] in networks: if data["name"] in networks:
msg = _("Network pool name already in use") msg = _("Network pool name already in use")
messages.error(request, msg) messages.error(request, msg)
errors = True errors = True
if data['forward'] in ['bridge', 'macvtap'] and data['bridge_name'] == '': if data["forward"] in ["bridge", "macvtap"] and data["bridge_name"] == "":
messages.error(request, _('Please enter bridge/dev name')) messages.error(request, _("Please enter bridge/dev name"))
errors = True errors = True
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"])
if data['subnet6']: if data["subnet6"]:
ipv6 = True ipv6 = True
gateway6, prefix6, dhcp6 = network_size(data['subnet6'], data['dhcp6']) gateway6, prefix6, dhcp6 = network_size(data["subnet6"], data["dhcp6"])
if prefix6 != '64': if prefix6 != "64":
messages.error(request, _('For libvirt, the IPv6 network prefix must be /64')) messages.error(
request, _("For libvirt, the IPv6 network prefix must be /64")
)
errors = True errors = True
if not errors: if not errors:
conn.create_network( conn.create_network(
data['name'], data["name"],
data['forward'], data["forward"],
ipv4, ipv4,
gateway4, gateway4,
netmask4, netmask4,
@ -67,11 +69,13 @@ def networks(request, compute_id):
gateway6, gateway6,
prefix6, prefix6,
dhcp6, dhcp6,
data['bridge_name'], data["bridge_name"],
data['openvswitch'], data["openvswitch"],
data['fixed'], data["fixed"],
)
return HttpResponseRedirect(
reverse("network", args=[compute_id, data["name"]])
) )
return HttpResponseRedirect(reverse('network', args=[compute_id, data['name']]))
else: else:
for msg_err in form.errors.values(): for msg_err in form.errors.values():
messages.error(request, msg_err.as_text()) messages.error(request, msg_err.as_text())
@ -79,7 +83,7 @@ def networks(request, compute_id):
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
return render(request, 'networks.html', locals()) return render(request, "networks.html", locals())
@superuser_only @superuser_only
@ -128,112 +132,119 @@ def network(request, compute_id, pool):
xml = conn._XMLDesc(0) xml = conn._XMLDesc(0)
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
return HttpResponseRedirect(reverse('networks', args=compute_id)) return HttpResponseRedirect(reverse("networks", args=compute_id))
if request.method == 'POST': if request.method == "POST":
if 'start' in request.POST: if "start" in request.POST:
try: try:
conn.start() conn.start()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
if 'stop' in request.POST: if "stop" in request.POST:
try: try:
conn.stop() conn.stop()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
if 'delete' in request.POST: if "delete" in request.POST:
try: try:
conn.delete() conn.delete()
return HttpResponseRedirect(reverse('networks', args=[compute_id])) return HttpResponseRedirect(reverse("networks", args=[compute_id]))
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
if 'set_autostart' in request.POST: if "set_autostart" in request.POST:
try: try:
conn.set_autostart(1) conn.set_autostart(1)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
if 'unset_autostart' in request.POST: if "unset_autostart" in request.POST:
try: try:
conn.set_autostart(0) conn.set_autostart(0)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
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", "")
family = request.POST.get('family', 'ipv4') family = request.POST.get("family", "ipv4")
if family == 'ipv4': if family == "ipv4":
mac_duid = request.POST.get('mac', '') mac_duid = request.POST.get("mac", "")
if family == 'ipv6': if family == "ipv6":
mac_duid = request.POST.get('id', '') mac_duid = request.POST.get("id", "")
try: try:
ret_val = conn.modify_fixed_address(name, address, mac_duid, family) ret_val = conn.modify_fixed_address(name, address, mac_duid, family)
messages.success(request, _(f"{family.upper()} Fixed Address Operation Completed.")) messages.success(request, _("Fixed address operation completed for %(family)s") % {"family": family.upper()})
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
except ValueError as val_err: except ValueError as val_err:
messages.error(request, val_err) messages.error(request, val_err)
if 'delete_fixed_address' in request.POST: if "delete_fixed_address" in request.POST:
ip = request.POST.get('address', '') ip = request.POST.get("address", "")
family = request.POST.get('family', 'ipv4') family = request.POST.get("family", "ipv4")
conn.delete_fixed_address(ip, family) conn.delete_fixed_address(ip, family)
messages.success(request, _(f"{family.upper()} Fixed Address is Deleted.")) messages.success(request, _("%(family)s Fixed Address is Deleted.") % {"family": family.upper()})
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') family = request.POST.get("family", "ipv4")
try: try:
conn.modify_dhcp_range(range_start, range_end, family) conn.modify_dhcp_range(range_start, range_end, family)
messages.success(request, _(f"{family.upper()} DHCP Range is Changed.")) messages.success(request, _("%(family)s DHCP Range is Changed.") % {"family": family.upper()})
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
if 'edit_network' in request.POST: if "edit_network" in request.POST:
edit_xml = request.POST.get('edit_xml', '') edit_xml = request.POST.get("edit_xml", "")
if edit_xml: if edit_xml:
conn.edit_network(edit_xml) conn.edit_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:
messages.success(request, _("Network XML is changed.")) messages.success(request, _("Network XML is changed."))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'set_qos' in request.POST: if "set_qos" in request.POST:
qos_dir = request.POST.get('qos_direction', '') qos_dir = request.POST.get("qos_direction", "")
average = request.POST.get('qos_average') or 0 average = request.POST.get("qos_average") or 0
peak = request.POST.get('qos_peak') or 0 peak = request.POST.get("qos_peak") or 0
burst = request.POST.get('qos_burst') or 0 burst = request.POST.get("qos_burst") or 0
try: try:
conn.set_qos(qos_dir, average, peak, burst) conn.set_qos(qos_dir, average, peak, burst)
if conn.is_active(): if conn.is_active():
messages.success( messages.success(
request, request,
_(f"{qos_dir.capitalize()} QoS is set. Network XML is changed.") + _("%(qos_dir)s QoS is updated. Network XML is changed. Stop and start network to activate new config") % {"qos_dir": qos_dir.capitalize()}
_("Stop and start network to activate new config")) )
else: else:
messages.success(request, _("{} QoS is set").format(qos_dir.capitalize())) messages.success(request, _("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()})
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'unset_qos' in request.POST: if "unset_qos" in request.POST:
qos_dir = request.POST.get('qos_direction', '') qos_dir = request.POST.get("qos_direction", "")
conn.unset_qos(qos_dir) conn.unset_qos(qos_dir)
if conn.is_active(): if conn.is_active():
messages.success( messages.success(
request, request,
_(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. ") + _("%(qos_dir)s QoS is deleted. Network XML is changed. \
_("Stop and start network to activate new config.")) Stop and start network to activate new config") % {"qos_dir": qos_dir.capitalize()}
)
else: else:
messages.success(request, _(f"{qos_dir.capitalize()} QoS is deleted")) messages.success(request, _("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()})
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
conn.close() conn.close()
return render(request, 'network.html', locals()) return render(request, "network.html", locals())

View file

@ -5,4 +5,4 @@ from django.apps import AppConfig
class NwfiltersConfig(AppConfig): class NwfiltersConfig(AppConfig):
name = 'nwfilters' name = "nwfilters"

View file

@ -25,48 +25,55 @@ def nwfilters(request, compute_id):
try: try:
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type) conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
if request.method == 'POST': for nwf in conn.get_nwfilters():
if 'create_nwfilter' in request.POST: nwfilters_all.append(conn.get_nwfilter_info(nwf))
xml = request.POST.get('nwfilter_xml', '')
if request.method == "POST":
if "create_nwfilter" in request.POST:
xml = request.POST.get("nwfilter_xml", "")
if xml: if xml:
try: try:
util.etree.fromstring(xml) util.etree.fromstring(xml)
name = util.get_xml_path(xml, '/filter/@name') name = util.get_xml_path(xml, "/filter/@name")
uuid = util.get_xml_path(xml, '/filter/uuid') uuid = util.get_xml_path(xml, "/filter/uuid")
except util.etree.ParseError: except util.etree.ParseError:
name = None name = None
for nwf in nwfilters: for nwf in nwfilters_all:
if name == nwf.name(): if name == nwf["name"]:
error_msg = _("A network filter with this name already exists") error_msg = _("A network filter with this name already exists")
raise Exception(error_msg) raise Exception(error_msg)
if uuid == nwf.UUIDString(): if uuid == nwf["uuid"]:
error_msg = _("A network filter with this UUID already exists") error_msg = _("A network filter with this UUID already exists")
raise Exception(error_msg) raise Exception(error_msg)
else: else:
try: try:
msg = _("Creating NWFilter: %s" % name) msg = _("%(filter)s network filter is created") % {"filter": name}
conn.create_nwfilter(xml) conn.create_nwfilter(xml)
addlogmsg(request.user.username, compute.hostname, msg) addlogmsg(request.user.username, compute.hostname, msg)
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
addlogmsg(request.user.username, compute.hostname, lib_err) addlogmsg(request.user.username, compute.hostname, lib_err)
if 'del_nwfilter' in request.POST: if "del_nwfilter" in request.POST:
name = request.POST.get('nwfiltername', '') name = request.POST.get("nwfiltername", "")
msg = _(f"Deleting NWFilter: {name}") msg = _("%(filter)s network filter is deleted") % {"filter": name}
in_use = False in_use = False
nwfilter = conn.get_nwfilter(name) nwfilter = conn.get_nwfilter(name)
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:
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()
if name in dom_filterrefs: if name in dom_filterrefs:
in_use = True in_use = True
msg = _(f"NWFilter is in use by {inst}. Cannot be deleted.") msg = _("NWFilter is in use by %(instance)s. Cannot be deleted.") % {"instance": inst}
messages.error(request, msg) messages.error(request, msg)
addlogmsg(request.user.username, compute.hostname, msg) addlogmsg(request.user.username, compute.hostname, msg)
i_conn.close() i_conn.close()
@ -77,18 +84,15 @@ def nwfilters(request, compute_id):
nwfilter.undefine() nwfilter.undefine()
addlogmsg(request.user.username, compute.hostname, msg) addlogmsg(request.user.username, compute.hostname, msg)
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 = _(f"Cloning NWFilter {name} as {cln_name}") msg = _("Cloning NWFilter %(name)s as %(clone)s") % {"name":name, "clone": cln_name}
addlogmsg(request.user.username, compute.hostname, msg) addlogmsg(request.user.username, compute.hostname, msg)
for nwf in conn.get_nwfilters():
nwfilters_all.append(conn.get_nwfilter_info(nwf))
conn.close() conn.close()
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
@ -97,10 +101,14 @@ def nwfilters(request, compute_id):
messages.error(request, err) messages.error(request, err)
addlogmsg(request.user.username, compute.hostname, err) addlogmsg(request.user.username, compute.hostname, err)
return render(request, 'nwfilters.html', { return render(
'nwfilters': nwfilters_all, request,
'compute': compute, "nwfilters.html",
}) {
"nwfilters": nwfilters_all,
"compute": compute,
},
)
def nwfilter(request, compute_id, nwfltr): def nwfilter(request, compute_id, nwfltr):
@ -114,7 +122,9 @@ def nwfilter(request, compute_id, nwfltr):
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
try: try:
nwfilter = wvmNWFilter(compute.hostname, compute.login, compute.password, compute.type, nwfltr) nwfilter = wvmNWFilter(
compute.hostname, compute.login, compute.password, compute.type, nwfltr
)
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type) conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
for nwf in conn.get_nwfilters(): for nwf in conn.get_nwfilters():
@ -126,10 +136,10 @@ def nwfilter(request, compute_id, nwfltr):
rules = nwfilter.get_rules() rules = nwfilter.get_rules()
refs = nwfilter.get_filter_refs() refs = nwfilter.get_filter_refs()
if request.method == 'POST': if request.method == "POST":
if 'edit_nwfilter' in request.POST: if "edit_nwfilter" in request.POST:
new_xml = request.POST.get('edit_xml', '') new_xml = request.POST.get("edit_xml", "")
if new_xml: if new_xml:
nwfilter.delete() nwfilter.delete()
@ -139,10 +149,10 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml) conn.create_nwfilter(xml)
raise libvirtError(lib_err) raise libvirtError(lib_err)
if 'del_nwfilter_rule' in request.POST: if "del_nwfilter_rule" in request.POST:
action = request.POST.get('action', '') action = request.POST.get("action", "")
direction = request.POST.get('direction', '') direction = request.POST.get("direction", "")
priority = request.POST.get('priority', '') priority = request.POST.get("priority", "")
new_xml = nwfilter.delete_rule(action, direction, priority) new_xml = nwfilter.delete_rule(action, direction, priority)
nwfilter.delete() nwfilter.delete()
@ -152,8 +162,8 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml) conn.create_nwfilter(xml)
raise libvirtError(lib_err) raise libvirtError(lib_err)
if 'del_nwfilter_ref' in request.POST: if "del_nwfilter_ref" in request.POST:
ref_name = request.POST.get('ref') ref_name = request.POST.get("ref")
new_xml = nwfilter.delete_ref(ref_name) new_xml = nwfilter.delete_ref(ref_name)
nwfilter.delete() nwfilter.delete()
try: try:
@ -162,8 +172,8 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml) conn.create_nwfilter(xml)
raise libvirtError(lib_err) raise libvirtError(lib_err)
if 'add_nwfilter_rule' in request.POST: if "add_nwfilter_rule" in request.POST:
rule_xml = request.POST.get('nwfilterrule_xml', '') rule_xml = request.POST.get("nwfilterrule_xml", "")
if not rule_xml: if not rule_xml:
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
new_xml = nwfilter.add_rule(rule_xml) new_xml = nwfilter.add_rule(rule_xml)
@ -174,8 +184,8 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml) conn.create_nwfilter(xml)
raise libvirtError(lib_err) raise libvirtError(lib_err)
if 'add_nwfilter_ref' in request.POST: if "add_nwfilter_ref" in request.POST:
ref_name = request.POST.get('nwfilters_select', '') ref_name = request.POST.get("nwfilters_select", "")
if not ref_name: if not ref_name:
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
new_xml = nwfilter.add_ref(ref_name) new_xml = nwfilter.add_ref(ref_name)
@ -194,4 +204,4 @@ def nwfilter(request, compute_id, nwfltr):
except Exception as error_msg: except Exception as error_msg:
messages.error(request, error_msg) messages.error(request, error_msg)
return render(request, 'nwfilter.html', locals()) return render(request, "nwfilter.html", locals())

View file

@ -5,8 +5,14 @@ from computes.models import Compute
from django.contrib import messages from django.contrib import messages
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render from django.shortcuts import get_object_or_404, render
from libvirt import (VIR_SECRET_USAGE_TYPE_CEPH, VIR_SECRET_USAGE_TYPE_ISCSI, VIR_SECRET_USAGE_TYPE_NONE, from libvirt import (
VIR_SECRET_USAGE_TYPE_TLS, VIR_SECRET_USAGE_TYPE_VOLUME, libvirtError) VIR_SECRET_USAGE_TYPE_CEPH,
VIR_SECRET_USAGE_TYPE_ISCSI,
VIR_SECRET_USAGE_TYPE_NONE,
VIR_SECRET_USAGE_TYPE_TLS,
VIR_SECRET_USAGE_TYPE_VOLUME,
libvirtError,
)
from vrtManager.secrets import wvmSecrets from vrtManager.secrets import wvmSecrets
@ -36,36 +42,38 @@ def secrets(request, compute_id):
secrt = conn.get_secret(uuid) secrt = conn.get_secret(uuid)
try: try:
secrt_value = conn.get_secret_value(uuid) secrt_value = conn.get_secret_value(uuid)
except libvirtError as lib_err: except libvirtError:
secrt_value = None secrt_value = None
secrets_all.append({ secrets_all.append(
'usage': secrt.usageID(), {
'uuid': secrt.UUIDString(), "usage": secrt.usageID(),
'usageType': secret_usage_types[secrt.usageType()], "uuid": secrt.UUIDString(),
'value': secrt_value "usageType": secret_usage_types[secrt.usageType()],
}) "value": secrt_value,
if request.method == 'POST': }
if 'create' in request.POST: )
if request.method == "POST":
if "create" in request.POST:
form = AddSecret(request.POST) form = AddSecret(request.POST)
if form.is_valid(): if form.is_valid():
data = form.cleaned_data data = form.cleaned_data
conn.create_secret( conn.create_secret(
data['ephemeral'], data["ephemeral"],
data['private'], data["private"],
data['usage_type'], data["usage_type"],
data['data'], data["data"],
) )
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
else: else:
for msg_err in form.errors.values(): for msg_err in form.errors.values():
messages.error(request, msg_err.as_text()) messages.error(request, msg_err.as_text())
if 'delete' in request.POST: if "delete" in request.POST:
uuid = request.POST.get('uuid', '') uuid = request.POST.get("uuid", "")
conn.delete_secret(uuid) conn.delete_secret(uuid)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'set_value' in request.POST: if "set_value" in request.POST:
uuid = request.POST.get('uuid', '') uuid = request.POST.get("uuid", "")
value = request.POST.get('value', '') value = request.POST.get("value", "")
try: try:
conn.set_secret_value(uuid, value) conn.set_secret_value(uuid, value)
except Exception as err: except Exception as err:
@ -74,4 +82,4 @@ def secrets(request, compute_id):
except libvirtError as err: except libvirtError as err:
messages.error(request, err) messages.error(request, err)
return render(request, 'secrets.html', locals()) return render(request, "secrets.html", locals())

View file

@ -1,4 +1,5 @@
import re import re
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _

View file

@ -8,7 +8,6 @@ from django.utils.translation import gettext_lazy as _
from libvirt import libvirtError from libvirt import libvirtError
from admin.decorators import superuser_only from admin.decorators import superuser_only
from appsettings.models import AppSettings
from appsettings.settings import app_settings from appsettings.settings import app_settings
from computes.models import Compute from computes.models import Compute
from storages.forms import AddStgPool, CloneImage, CreateVolumeForm from storages.forms import AddStgPool, CloneImage, CreateVolumeForm
@ -31,34 +30,46 @@ def storages(request, compute_id):
storages = conn.get_storages_info() storages = conn.get_storages_info()
secrets = conn.get_secrets() secrets = conn.get_secrets()
if request.method == 'POST': if request.method == "POST":
if 'create' in request.POST: if "create" in request.POST:
form = AddStgPool(request.POST) form = AddStgPool(request.POST)
if form.is_valid(): if form.is_valid():
data = form.cleaned_data data = form.cleaned_data
if data['name'] in storages: if data["name"] in storages:
msg = _("Pool name already use") msg = _("Pool name already use")
messages.error(request, msg) messages.error(request, msg)
errors = True errors = True
if data['stg_type'] == 'rbd': if data["stg_type"] == "rbd":
if not data['secret']: if not data["secret"]:
msg = _("You need create secret for pool") msg = _("You need create secret for pool")
messages.error(request, msg) messages.error(request, msg)
errors = True errors = True
if not data['ceph_pool'] and not data['ceph_host'] and not data['ceph_user']: if not data["ceph_pool"] and not data["ceph_host"] and not data["ceph_user"]:
msg = _("You need input all fields for creating ceph pool") msg = _("You need input all fields for creating ceph pool")
messages.error(request, msg) messages.error(request, msg)
errors = True errors = True
if not errors: if not errors:
if data['stg_type'] == 'rbd': if data["stg_type"] == "rbd":
conn.create_storage_ceph(data['stg_type'], data['name'], data['ceph_pool'], data['ceph_host'], conn.create_storage_ceph(
data['ceph_user'], data['secret']) data["stg_type"],
elif data['stg_type'] == 'netfs': data["name"],
conn.create_storage_netfs(data['stg_type'], data['name'], data['netfs_host'], data['source'], data["ceph_pool"],
data['source_format'], data['target']) data["ceph_host"],
data["ceph_user"],
data["secret"],
)
elif data["stg_type"] == "netfs":
conn.create_storage_netfs(
data["stg_type"],
data["name"],
data["netfs_host"],
data["source"],
data["source_format"],
data["target"],
)
else: else:
conn.create_storage(data['stg_type'], data['name'], data['source'], data['target']) conn.create_storage(data["stg_type"], data["name"], data["source"], data["target"])
return HttpResponseRedirect(reverse('storage', args=[compute_id, data['name']])) return HttpResponseRedirect(reverse("storage", args=[compute_id, data["name"]]))
else: else:
for msg_err in form.errors.values(): for msg_err in form.errors.values():
messages.error(request, msg_err.as_text()) messages.error(request, msg_err.as_text())
@ -66,7 +77,7 @@ def storages(request, compute_id):
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
return render(request, 'storages.html', locals()) return render(request, "storages.html", locals())
@superuser_only @superuser_only
@ -77,9 +88,10 @@ def storage(request, compute_id, pool):
:param pool: :param pool:
:return: :return:
""" """
def handle_uploaded_file(path, f_name): def handle_uploaded_file(path, f_name):
target = path + '/' + str(f_name) target = path + "/" + str(f_name)
destination = open(target, 'wb+') destination = open(target, "wb+")
for chunk in f_name.chunks(): for chunk in f_name.chunks():
destination.write(chunk) destination.write(chunk)
destination.close() destination.close()
@ -93,7 +105,7 @@ def storage(request, compute_id, pool):
storages = conn.get_storages() storages = conn.get_storages()
state = conn.is_active() state = conn.is_active()
size, free = conn.get_size() size, free = conn.get_size()
used = (size - free) used = size - free
if state: if state:
percent = (used * 100) // size percent = (used * 100) // size
else: else:
@ -109,55 +121,58 @@ def storage(request, compute_id, pool):
else: else:
volumes = None volumes = None
if request.method == 'POST': if request.method == "POST":
if 'start' in request.POST: if "start" in request.POST:
conn.start() conn.start()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'stop' in request.POST: if "stop" in request.POST:
conn.stop() conn.stop()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'delete' in request.POST: if "delete" in request.POST:
conn.delete() conn.delete()
return HttpResponseRedirect(reverse('storages', args=[compute_id])) return HttpResponseRedirect(reverse("storages", args=[compute_id]))
if 'set_autostart' in request.POST: if "set_autostart" in request.POST:
conn.set_autostart(1) conn.set_autostart(1)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'unset_autostart' in request.POST: if "unset_autostart" in request.POST:
conn.set_autostart(0) conn.set_autostart(0)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'del_volume' in request.POST: if "del_volume" in request.POST:
volname = request.POST.get('volname', '') volname = request.POST.get("volname", "")
vol = conn.get_volume(volname) vol = conn.get_volume(volname)
vol.delete(0) vol.delete(0)
messages.success(request, _(f"Volume: {volname} is deleted.")) messages.success(request, _("Volume: %(volume)s is deleted.") % {"vol": volname})
return redirect(reverse('storage', args=[compute.id, pool])) return redirect(reverse("storage", args=[compute.id, pool]))
# return HttpResponseRedirect(request.get_full_path()) # return HttpResponseRedirect(request.get_full_path())
if 'iso_upload' in request.POST: if "iso_upload" in request.POST:
if str(request.FILES['file']) in conn.update_volumes(): if str(request.FILES["file"]) in conn.update_volumes():
error_msg = _("ISO image already exist") error_msg = _("ISO image already exist")
messages.error(request, error_msg) messages.error(request, error_msg)
else: else:
handle_uploaded_file(path, request.FILES['file']) handle_uploaded_file(path, request.FILES["file"])
messages.success(request, _(f"ISO: {request.FILES['file']} is uploaded.")) messages.success(request, _("ISO: %(file)s is uploaded.") % {"file": request.FILES["file"]})
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'cln_volume' in request.POST: if "cln_volume" in request.POST:
form = CloneImage(request.POST) form = CloneImage(request.POST)
if form.is_valid(): if form.is_valid():
data = form.cleaned_data data = form.cleaned_data
img_name = data['name'] img_name = data["name"]
meta_prealloc = 0 meta_prealloc = 0
if img_name in conn.update_volumes(): if img_name in conn.update_volumes():
msg = _("Name of volume already in use") msg = _("Name of volume already in use")
messages.error(request, msg) messages.error(request, msg)
if data['convert']: if data["convert"]:
format = data['format'] format = data["format"]
if data['meta_prealloc'] and data['format'] == 'qcow2': if data["meta_prealloc"] and data["format"] == "qcow2":
meta_prealloc = True meta_prealloc = True
else: else:
format = None format = None
try: try:
name = conn.clone_volume(data['image'], data['name'], format, meta_prealloc) name = conn.clone_volume(data["image"], data["name"], format, meta_prealloc)
messages.success(request, _(f"{data['image']} image cloned as {name} successfully")) messages.success(
request,
_("%(image)s image cloned as %(clone)s successfully") % {"image": data["image"], "name": name},
)
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
messages.error(request, lib_err) messages.error(request, lib_err)
@ -167,11 +182,17 @@ def storage(request, compute_id, pool):
conn.close() conn.close()
return render(request, 'storage.html', locals()) return render(request, "storage.html", locals())
@superuser_only @superuser_only
def create_volume(request, compute_id, pool): def create_volume(request, compute_id, pool):
"""
:param request:
:param compute_id: compute id
:param pool: pool name
:return:
"""
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
meta_prealloc = False meta_prealloc = False
@ -182,26 +203,26 @@ def create_volume(request, compute_id, pool):
form = CreateVolumeForm(request.POST or None) form = CreateVolumeForm(request.POST or None)
if form.is_valid(): if form.is_valid():
data = form.cleaned_data data = form.cleaned_data
if data['meta_prealloc'] and data['format'] == 'qcow2': if data["meta_prealloc"] and data["format"] == "qcow2":
meta_prealloc = True meta_prealloc = True
disk_owner_uid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID) disk_owner_uid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
disk_owner_gid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID) disk_owner_gid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID)
name = conn.create_volume( name = conn.create_volume(
data['name'], data["name"],
data['size'], data["size"],
data['format'], data["format"],
meta_prealloc, meta_prealloc,
disk_owner_uid, disk_owner_uid,
disk_owner_gid, disk_owner_gid,
) )
messages.success(request, _(f"Image file {name} is created successfully")) messages.success(request, _("Image file %(name)s is created successfully") % {"name": name})
else: else:
for msg_err in form.errors.values(): for msg_err in form.errors.values():
messages.error(request, msg_err.as_text()) messages.error(request, msg_err.as_text())
return redirect(reverse('storage', args=[compute.id, pool])) return redirect(reverse("storage", args=[compute.id, pool]))
def get_volumes(request, compute_id, pool): def get_volumes(request, compute_id, pool):
@ -216,7 +237,7 @@ def get_volumes(request, compute_id, pool):
try: try:
conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool) conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
conn.refresh() conn.refresh()
data['vols'] = sorted(conn.get_volumes()) data["vols"] = sorted(conn.get_volumes())
except libvirtError: except libvirtError:
pass pass
return HttpResponse(json.dumps(data)) return HttpResponse(json.dumps(data))

View file

@ -6,7 +6,7 @@ Further Information might be available at:
https://github.com/haypo/python-ipy https://github.com/haypo/python-ipy
""" """
__version__ = '1.00' __version__ = "1.00"
import bisect import bisect
import collections import collections
@ -17,16 +17,16 @@ import types
# this should include www.iana.org/assignments/ipv4-address-space # this should include www.iana.org/assignments/ipv4-address-space
# and www.iana.org/assignments/multicast-addresses # and www.iana.org/assignments/multicast-addresses
IPv4ranges = { IPv4ranges = {
'0': 'PUBLIC', # fall back "0": "PUBLIC", # fall back
'00000000': 'PRIVATE', # 0/8 "00000000": "PRIVATE", # 0/8
'00001010': 'PRIVATE', # 10/8 "00001010": "PRIVATE", # 10/8
'0110010001': 'CARRIER_GRADE_NAT', # 100.64/10 "0110010001": "CARRIER_GRADE_NAT", # 100.64/10
'01111111': 'LOOPBACK', # 127.0/8 "01111111": "LOOPBACK", # 127.0/8
'1': 'PUBLIC', # fall back "1": "PUBLIC", # fall back
'1010100111111110': 'PRIVATE', # 169.254/16 "1010100111111110": "PRIVATE", # 169.254/16
'101011000001': 'PRIVATE', # 172.16/12 "101011000001": "PRIVATE", # 172.16/12
'1100000010101000': 'PRIVATE', # 192.168/16 "1100000010101000": "PRIVATE", # 192.168/16
'111': 'RESERVED', # 224/3 "111": "RESERVED", # 224/3
} }
# Definition of the Ranges for IPv6 IPs # Definition of the Ranges for IPv6 IPs
@ -34,92 +34,92 @@ IPv4ranges = {
# http://www.iana.org/assignments/ipv6-unicast-address-assignments/ # http://www.iana.org/assignments/ipv6-unicast-address-assignments/
# http://www.iana.org/assignments/ipv6-multicast-addresses/ # http://www.iana.org/assignments/ipv6-multicast-addresses/
IPv6ranges = { IPv6ranges = {
'00000000': 'RESERVED', # ::/8 "00000000": "RESERVED", # ::/8
'0' * 96: 'RESERVED', # ::/96 Formerly IPV4COMP [RFC4291] "0" * 96: "RESERVED", # ::/96 Formerly IPV4COMP [RFC4291]
'0' * 128: 'UNSPECIFIED', # ::/128 "0" * 128: "UNSPECIFIED", # ::/128
'0' * 127 + '1': 'LOOPBACK', # ::1/128 "0" * 127 + "1": "LOOPBACK", # ::1/128
'0' * 80 + '1' * 16: 'IPV4MAP', # ::ffff:0:0/96 "0" * 80 + "1" * 16: "IPV4MAP", # ::ffff:0:0/96
'00000000011001001111111110011011' + '0' * 64: 'WKP46TRANS', # 0064:ff9b::/96 Well-Known-Prefix [RFC6052] "00000000011001001111111110011011" + "0" * 64: "WKP46TRANS", # 0064:ff9b::/96 Well-Known-Prefix [RFC6052]
'00000001': 'UNASSIGNED', # 0100::/8 "00000001": "UNASSIGNED", # 0100::/8
'0000001': 'RESERVED', # 0200::/7 Formerly NSAP [RFC4048] "0000001": "RESERVED", # 0200::/7 Formerly NSAP [RFC4048]
'0000010': 'RESERVED', # 0400::/7 Formerly IPX [RFC3513] "0000010": "RESERVED", # 0400::/7 Formerly IPX [RFC3513]
'0000011': 'RESERVED', # 0600::/7 "0000011": "RESERVED", # 0600::/7
'00001': 'RESERVED', # 0800::/5 "00001": "RESERVED", # 0800::/5
'0001': 'RESERVED', # 1000::/4 "0001": "RESERVED", # 1000::/4
'001': 'GLOBAL-UNICAST', # 2000::/3 [RFC4291] "001": "GLOBAL-UNICAST", # 2000::/3 [RFC4291]
'00100000000000010000000': 'SPECIALPURPOSE', # 2001::/23 [RFC4773] "00100000000000010000000": "SPECIALPURPOSE", # 2001::/23 [RFC4773]
'00100000000000010000000000000000': 'TEREDO', # 2001::/32 [RFC4380] "00100000000000010000000000000000": "TEREDO", # 2001::/32 [RFC4380]
'00100000000000010000000000000010' + '0' * 16: 'BMWG', # 2001:0002::/48 Benchmarking [RFC5180] "00100000000000010000000000000010" + "0" * 16: "BMWG", # 2001:0002::/48 Benchmarking [RFC5180]
'0010000000000001000000000001': 'ORCHID', # 2001:0010::/28 (Temp until 2014-03-21) [RFC4843] "0010000000000001000000000001": "ORCHID", # 2001:0010::/28 (Temp until 2014-03-21) [RFC4843]
'00100000000000010000001': 'ALLOCATED APNIC', # 2001:0200::/23 "00100000000000010000001": "ALLOCATED APNIC", # 2001:0200::/23
'00100000000000010000010': 'ALLOCATED ARIN', # 2001:0400::/23 "00100000000000010000010": "ALLOCATED ARIN", # 2001:0400::/23
'00100000000000010000011': 'ALLOCATED RIPE NCC', # 2001:0600::/23 "00100000000000010000011": "ALLOCATED RIPE NCC", # 2001:0600::/23
'00100000000000010000100': 'ALLOCATED RIPE NCC', # 2001:0800::/23 "00100000000000010000100": "ALLOCATED RIPE NCC", # 2001:0800::/23
'00100000000000010000101': 'ALLOCATED RIPE NCC', # 2001:0a00::/23 "00100000000000010000101": "ALLOCATED RIPE NCC", # 2001:0a00::/23
'00100000000000010000110': 'ALLOCATED APNIC', # 2001:0c00::/23 "00100000000000010000110": "ALLOCATED APNIC", # 2001:0c00::/23
'00100000000000010000110110111000': 'DOCUMENTATION', # 2001:0db8::/32 [RFC3849] "00100000000000010000110110111000": "DOCUMENTATION", # 2001:0db8::/32 [RFC3849]
'00100000000000010000111': 'ALLOCATED APNIC', # 2001:0e00::/23 "00100000000000010000111": "ALLOCATED APNIC", # 2001:0e00::/23
'00100000000000010001001': 'ALLOCATED LACNIC', # 2001:1200::/23 "00100000000000010001001": "ALLOCATED LACNIC", # 2001:1200::/23
'00100000000000010001010': 'ALLOCATED RIPE NCC', # 2001:1400::/23 "00100000000000010001010": "ALLOCATED RIPE NCC", # 2001:1400::/23
'00100000000000010001011': 'ALLOCATED RIPE NCC', # 2001:1600::/23 "00100000000000010001011": "ALLOCATED RIPE NCC", # 2001:1600::/23
'00100000000000010001100': 'ALLOCATED ARIN', # 2001:1800::/23 "00100000000000010001100": "ALLOCATED ARIN", # 2001:1800::/23
'00100000000000010001101': 'ALLOCATED RIPE NCC', # 2001:1a00::/23 "00100000000000010001101": "ALLOCATED RIPE NCC", # 2001:1a00::/23
'0010000000000001000111': 'ALLOCATED RIPE NCC', # 2001:1c00::/22 "0010000000000001000111": "ALLOCATED RIPE NCC", # 2001:1c00::/22
'00100000000000010010': 'ALLOCATED RIPE NCC', # 2001:2000::/20 "00100000000000010010": "ALLOCATED RIPE NCC", # 2001:2000::/20
'001000000000000100110': 'ALLOCATED RIPE NCC', # 2001:3000::/21 "001000000000000100110": "ALLOCATED RIPE NCC", # 2001:3000::/21
'0010000000000001001110': 'ALLOCATED RIPE NCC', # 2001:3800::/22 "0010000000000001001110": "ALLOCATED RIPE NCC", # 2001:3800::/22
'0010000000000001001111': 'RESERVED', # 2001:3c00::/22 Possible future allocation to RIPE NCC "0010000000000001001111": "RESERVED", # 2001:3c00::/22 Possible future allocation to RIPE NCC
'00100000000000010100000': 'ALLOCATED RIPE NCC', # 2001:4000::/23 "00100000000000010100000": "ALLOCATED RIPE NCC", # 2001:4000::/23
'00100000000000010100001': 'ALLOCATED AFRINIC', # 2001:4200::/23 "00100000000000010100001": "ALLOCATED AFRINIC", # 2001:4200::/23
'00100000000000010100010': 'ALLOCATED APNIC', # 2001:4400::/23 "00100000000000010100010": "ALLOCATED APNIC", # 2001:4400::/23
'00100000000000010100011': 'ALLOCATED RIPE NCC', # 2001:4600::/23 "00100000000000010100011": "ALLOCATED RIPE NCC", # 2001:4600::/23
'00100000000000010100100': 'ALLOCATED ARIN', # 2001:4800::/23 "00100000000000010100100": "ALLOCATED ARIN", # 2001:4800::/23
'00100000000000010100101': 'ALLOCATED RIPE NCC', # 2001:4a00::/23 "00100000000000010100101": "ALLOCATED RIPE NCC", # 2001:4a00::/23
'00100000000000010100110': 'ALLOCATED RIPE NCC', # 2001:4c00::/23 "00100000000000010100110": "ALLOCATED RIPE NCC", # 2001:4c00::/23
'00100000000000010101': 'ALLOCATED RIPE NCC', # 2001:5000::/20 "00100000000000010101": "ALLOCATED RIPE NCC", # 2001:5000::/20
'0010000000000001100': 'ALLOCATED APNIC', # 2001:8000::/19 "0010000000000001100": "ALLOCATED APNIC", # 2001:8000::/19
'00100000000000011010': 'ALLOCATED APNIC', # 2001:a000::/20 "00100000000000011010": "ALLOCATED APNIC", # 2001:a000::/20
'00100000000000011011': 'ALLOCATED APNIC', # 2001:b000::/20 "00100000000000011011": "ALLOCATED APNIC", # 2001:b000::/20
'0010000000000010': '6TO4', # 2002::/16 "6to4" [RFC3056] "0010000000000010": "6TO4", # 2002::/16 "6to4" [RFC3056]
'001000000000001100': 'ALLOCATED RIPE NCC', # 2003::/18 "001000000000001100": "ALLOCATED RIPE NCC", # 2003::/18
'001001000000': 'ALLOCATED APNIC', # 2400::/12 "001001000000": "ALLOCATED APNIC", # 2400::/12
'001001100000': 'ALLOCATED ARIN', # 2600::/12 "001001100000": "ALLOCATED ARIN", # 2600::/12
'00100110000100000000000': 'ALLOCATED ARIN', # 2610::/23 "00100110000100000000000": "ALLOCATED ARIN", # 2610::/23
'00100110001000000000000': 'ALLOCATED ARIN', # 2620::/23 "00100110001000000000000": "ALLOCATED ARIN", # 2620::/23
'001010000000': 'ALLOCATED LACNIC', # 2800::/12 "001010000000": "ALLOCATED LACNIC", # 2800::/12
'001010100000': 'ALLOCATED RIPE NCC', # 2a00::/12 "001010100000": "ALLOCATED RIPE NCC", # 2a00::/12
'001011000000': 'ALLOCATED AFRINIC', # 2c00::/12 "001011000000": "ALLOCATED AFRINIC", # 2c00::/12
'00101101': 'RESERVED', # 2d00::/8 "00101101": "RESERVED", # 2d00::/8
'0010111': 'RESERVED', # 2e00::/7 "0010111": "RESERVED", # 2e00::/7
'0011': 'RESERVED', # 3000::/4 "0011": "RESERVED", # 3000::/4
'010': 'RESERVED', # 4000::/3 "010": "RESERVED", # 4000::/3
'011': 'RESERVED', # 6000::/3 "011": "RESERVED", # 6000::/3
'100': 'RESERVED', # 8000::/3 "100": "RESERVED", # 8000::/3
'101': 'RESERVED', # a000::/3 "101": "RESERVED", # a000::/3
'110': 'RESERVED', # c000::/3 "110": "RESERVED", # c000::/3
'1110': 'RESERVED', # e000::/4 "1110": "RESERVED", # e000::/4
'11110': 'RESERVED', # f000::/5 "11110": "RESERVED", # f000::/5
'111110': 'RESERVED', # f800::/6 "111110": "RESERVED", # f800::/6
'1111110': 'ULA', # fc00::/7 [RFC4193] "1111110": "ULA", # fc00::/7 [RFC4193]
'111111100': 'RESERVED', # fe00::/9 "111111100": "RESERVED", # fe00::/9
'1111111010': 'LINKLOCAL', # fe80::/10 "1111111010": "LINKLOCAL", # fe80::/10
'1111111011': 'RESERVED', # fec0::/10 Formerly SITELOCAL [RFC4291] "1111111011": "RESERVED", # fec0::/10 Formerly SITELOCAL [RFC4291]
'11111111': 'MULTICAST', # ff00::/8 "11111111": "MULTICAST", # ff00::/8
'1111111100000001': 'NODE-LOCAL MULTICAST', # ff01::/16 "1111111100000001": "NODE-LOCAL MULTICAST", # ff01::/16
'1111111100000010': 'LINK-LOCAL MULTICAST', # ff02::/16 "1111111100000010": "LINK-LOCAL MULTICAST", # ff02::/16
'1111111100000100': 'ADMIN-LOCAL MULTICAST', # ff04::/16 "1111111100000100": "ADMIN-LOCAL MULTICAST", # ff04::/16
'1111111100000101': 'SITE-LOCAL MULTICAST', # ff05::/16 "1111111100000101": "SITE-LOCAL MULTICAST", # ff05::/16
'1111111100001000': 'ORG-LOCAL MULTICAST', # ff08::/16 "1111111100001000": "ORG-LOCAL MULTICAST", # ff08::/16
'1111111100001110': 'GLOBAL MULTICAST', # ff0e::/16 "1111111100001110": "GLOBAL MULTICAST", # ff0e::/16
'1111111100001111': 'RESERVED MULTICAST', # ff0f::/16 "1111111100001111": "RESERVED MULTICAST", # ff0f::/16
'111111110011': 'PREFIX-BASED MULTICAST', # ff30::/12 [RFC3306] "111111110011": "PREFIX-BASED MULTICAST", # ff30::/12 [RFC3306]
'111111110111': 'RP-EMBEDDED MULTICAST', # ff70::/12 [RFC3956] "111111110111": "RP-EMBEDDED MULTICAST", # ff70::/12 [RFC3956]
} }
MAX_IPV4_ADDRESS = 0xffffffff MAX_IPV4_ADDRESS = 0xFFFFFFFF
MAX_IPV6_ADDRESS = 0xffffffffffffffffffffffffffffffff MAX_IPV6_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
IPV6_TEST_MAP = 0xffffffffffffffffffffffff00000000 IPV6_TEST_MAP = 0xFFFFFFFFFFFFFFFFFFFFFFFF00000000
IPV6_MAP_MASK = 0x00000000000000000000ffff00000000 IPV6_MAP_MASK = 0x00000000000000000000FFFF00000000
if sys.version_info >= (3,): if sys.version_info >= (3,):
INT_TYPES = (int,) INT_TYPES = (int,)
@ -202,7 +202,7 @@ class IPint(object):
elif isinstance(data, STR_TYPES): elif isinstance(data, STR_TYPES):
# TODO: refactor me! # TODO: refactor me!
# splitting of a string into IP and prefixlen et. al. # splitting of a string into IP and prefixlen et. al.
x = data.split('-') x = data.split("-")
if len(x) == 2: if len(x) == 2:
# a.b.c.0-a.b.c.255 specification ? # a.b.c.0-a.b.c.255 specification ?
(ip, last) = x (ip, last) = x
@ -219,10 +219,10 @@ class IPint(object):
# make sure the broadcast is the same as the last ip # make sure the broadcast is the same as the last ip
# otherwise it will return /16 for something like: # otherwise it will return /16 for something like:
# 192.168.0.0-192.168.191.255 # 192.168.0.0-192.168.191.255
if IP('%s/%s' % (ip, 32 - netbits)).broadcast().int() != last: if IP("%s/%s" % (ip, 32 - netbits)).broadcast().int() != last:
raise ValueError("the range %s is not on a network boundary." % data) raise ValueError("the range %s is not on a network boundary." % data)
elif len(x) == 1: elif len(x) == 1:
x = data.split('/') x = data.split("/")
# if no prefix is given use defaults # if no prefix is given use defaults
if len(x) == 1: if len(x) == 1:
ip = x[0] ip = x[0]
@ -231,7 +231,7 @@ class IPint(object):
raise ValueError("only one '/' allowed in IP Address") raise ValueError("only one '/' allowed in IP Address")
else: else:
(ip, prefixlen) = x (ip, prefixlen) = x
if prefixlen.find('.') != -1: if prefixlen.find(".") != -1:
# check if the user might have used a netmask like # check if the user might have used a netmask like
# a.b.c.d/255.255.255.0 # a.b.c.d/255.255.255.0
(netmask, vers) = parseAddress(prefixlen) (netmask, vers) = parseAddress(prefixlen)
@ -255,8 +255,7 @@ class IPint(object):
if make_net: if make_net:
self.ip = self.ip & _prefixlenToNetmask(self._prefixlen, self._ipversion) self.ip = self.ip & _prefixlenToNetmask(self._prefixlen, self._ipversion)
if not _checkNetaddrWorksWithPrefixlen(self.ip, if not _checkNetaddrWorksWithPrefixlen(self.ip, self._prefixlen, self._ipversion):
self._prefixlen, self._ipversion):
raise ValueError("%s has invalid prefix length (%s)" % (repr(self), self._prefixlen)) raise ValueError("%s has invalid prefix length (%s)" % (repr(self), self._prefixlen))
else: else:
raise TypeError("Unsupported data type: %s" % type(data)) raise TypeError("Unsupported data type: %s" % type(data))
@ -314,8 +313,7 @@ class IPint(object):
want == 3 -lastip 1.2.3.0-1.2.3.255 want == 3 -lastip 1.2.3.0-1.2.3.255
""" """
if (self._ipversion == 4 and self._prefixlen == 32) or \ if (self._ipversion == 4 and self._prefixlen == 32) or (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 is None: if want is None:
@ -335,7 +333,7 @@ class IPint(object):
# default # default
return "/%d" % (self._prefixlen) return "/%d" % (self._prefixlen)
else: else:
return '' return ""
# We have different flavours to convert to: # We have different flavours to convert to:
# strFullsize 127.0.0.1 2001:0658:022a:cafe:0200:c0ff:fe8d:08fa # strFullsize 127.0.0.1 2001:0658:022a:cafe:0200:c0ff:fe8d:08fa
@ -357,7 +355,7 @@ class IPint(object):
if self.WantPrefixLen is None and wantprefixlen is 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)
def strCompressed(self, wantprefixlen=None): def strCompressed(self, wantprefixlen=None):
"""Return a string representation in compressed format using '::' Notation. """Return a string representation in compressed format using '::' Notation.
@ -376,12 +374,12 @@ class IPint(object):
if self._ipversion == 4: if self._ipversion == 4:
return self.strFullsize(wantprefixlen) return self.strFullsize(wantprefixlen)
else: else:
if self.ip >> 32 == 0xffff: if self.ip >> 32 == 0xFFFF:
ipv4 = intToIp(self.ip & MAX_IPV4_ADDRESS, 4) ipv4 = intToIp(self.ip & MAX_IPV4_ADDRESS, 4)
text = "::ffff:" + ipv4 + self._printPrefix(wantprefixlen) text = "::ffff:" + ipv4 + self._printPrefix(wantprefixlen)
return text return text
# find the longest sequence of '0' # find the longest sequence of '0'
hextets = [int(x, 16) for x in self.strFullsize(0).split(':')] hextets = [int(x, 16) for x in self.strFullsize(0).split(":")]
# every element of followingzeros will contain the number of zeros # every element of followingzeros will contain the number of zeros
# following the corresponding element of hextets # following the corresponding element of hextets
followingzeros = [0] * 8 followingzeros = [0] * 8
@ -392,15 +390,15 @@ class IPint(object):
if max(followingzeros) > 1: if max(followingzeros) > 1:
# genererate string with the longest number of zeros cut out # genererate string with the longest number of zeros cut out
# now we need hextets as strings # now we need hextets as strings
hextets = [x for x in self.strNormal(0).split(':')] hextets = [x for x in self.strNormal(0).split(":")]
while compressionpos < len(hextets) and hextets[compressionpos] == '0': while compressionpos < len(hextets) and hextets[compressionpos] == "0":
del (hextets[compressionpos]) del hextets[compressionpos]
hextets.insert(compressionpos, '') hextets.insert(compressionpos, "")
if compressionpos + 1 >= len(hextets): if compressionpos + 1 >= len(hextets):
hextets.append('') hextets.append("")
if compressionpos == 0: if compressionpos == 0:
hextets = [''] + hextets hextets = [""] + hextets
return ':'.join(hextets) + self._printPrefix(wantprefixlen) return ":".join(hextets) + self._printPrefix(wantprefixlen)
else: else:
return self.strNormal(0) + self._printPrefix(wantprefixlen) return self.strNormal(0) + self._printPrefix(wantprefixlen)
@ -419,7 +417,7 @@ class IPint(object):
if self._ipversion == 4: if self._ipversion == 4:
ret = self.strFullsize(0) ret = self.strFullsize(0)
elif self._ipversion == 6: elif self._ipversion == 6:
ret = ':'.join(["%x" % x for x in [int(x, 16) for x in self.strFullsize(0).split(':')]]) ret = ":".join(["%x" % x for x in [int(x, 16) for x in self.strFullsize(0).split(":")]])
else: else:
raise ValueError("only IPv4 and IPv6 supported") raise ValueError("only IPv4 and IPv6 supported")
@ -451,7 +449,7 @@ class IPint(object):
if self.WantPrefixLen is None and wantprefixlen is None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 0 wantprefixlen = 0
x = '0x%x' % self.ip x = "0x%x" % self.ip
return x + self._printPrefix(wantprefixlen) return x + self._printPrefix(wantprefixlen)
def strDec(self, wantprefixlen=None): def strDec(self, wantprefixlen=None):
@ -466,7 +464,7 @@ class IPint(object):
if self.WantPrefixLen is None and wantprefixlen is None: if self.WantPrefixLen is None and wantprefixlen is None:
wantprefixlen = 0 wantprefixlen = 0
x = '%d' % self.ip x = "%d" % self.ip
return x + self._printPrefix(wantprefixlen) return x + self._printPrefix(wantprefixlen)
def iptype(self): def iptype(self):
@ -581,10 +579,8 @@ class IPint(object):
raise ValueError("Only adjacent networks can be added together.") raise ValueError("Only adjacent networks can be added together.")
ret = IP(self.int(), ipversion=self._ipversion) ret = IP(self.int(), ipversion=self._ipversion)
ret._prefixlen = self.prefixlen() - 1 ret._prefixlen = self.prefixlen() - 1
if not _checkNetaddrWorksWithPrefixlen(ret.ip, ret._prefixlen, if not _checkNetaddrWorksWithPrefixlen(ret.ip, ret._prefixlen, ret._ipversion):
ret._ipversion): raise ValueError("The resulting %s has invalid prefix length (%s)" % (repr(ret), ret._prefixlen))
raise ValueError("The resulting %s has invalid prefix length (%s)"
% (repr(ret), ret._prefixlen))
return ret return ret
def __sub__(self, other): def __sub__(self, other):
@ -692,7 +688,7 @@ class IPint(object):
IP('10.0.0.0/24') IP('10.0.0.0/24')
""" """
return ("IPint('%s')" % (self.strCompressed(1))) return "IPint('%s')" % (self.strCompressed(1))
def __cmp__(self, other): def __cmp__(self, other):
"""Called by comparison operations. """Called by comparison operations.
@ -777,7 +773,7 @@ class IPint(object):
thehash = int(-1) thehash = int(-1)
ip = self.ip ip = self.ip
while ip > 0: while ip > 0:
thehash = thehash ^ (ip & 0x7fffffff) thehash = thehash ^ (ip & 0x7FFFFFFF)
ip = ip >> 32 ip = ip >> 32
thehash = thehash ^ self._prefixlen thehash = thehash ^ self._prefixlen
return int(thehash) return int(thehash)
@ -817,11 +813,11 @@ class IP(IPint):
def _getIPv4Map(self): def _getIPv4Map(self):
if self._ipversion != 6: if self._ipversion != 6:
return None return None
if (self.ip >> 32) != 0xffff: if (self.ip >> 32) != 0xFFFF:
return None return None
ipv4 = self.ip & MAX_IPV4_ADDRESS ipv4 = self.ip & MAX_IPV4_ADDRESS
if self._prefixlen != 128: if self._prefixlen != 128:
ipv4 = '%s/%s' % (ipv4, 32 - (128 - self._prefixlen)) ipv4 = "%s/%s" % (ipv4, 32 - (128 - self._prefixlen))
return IP(ipv4, ipversion=4) return IP(ipv4, ipversion=4)
def reverseNames(self): def reverseNames(self):
@ -872,7 +868,7 @@ class IP(IPint):
raise NotImplementedError("can't create IPv6 reverse names at sub nibble level") raise NotImplementedError("can't create IPv6 reverse names at sub nibble level")
s = list(s) s = list(s)
s.reverse() s.reverse()
s = '.'.join(s) s = ".".join(s)
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2 first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
return ["%s.ip6.arpa." % s[first_nibble_index:]] return ["%s.ip6.arpa." % s[first_nibble_index:]]
else: else:
@ -897,32 +893,34 @@ class IP(IPint):
if self._ipversion == 4: if self._ipversion == 4:
s = self.strFullsize(0) s = self.strFullsize(0)
s = s.split('.') s = s.split(".")
s.reverse() s.reverse()
first_byte_index = int(4 - (self._prefixlen // 8)) first_byte_index = int(4 - (self._prefixlen // 8))
if self._prefixlen % 8 != 0: if self._prefixlen % 8 != 0:
nibblepart = "%s-%s" % ( nibblepart = "%s-%s" % (
s[3 - (self._prefixlen // 8)], intToIp(self.ip + self.len() - 1, 4).split('.')[-1]) s[3 - (self._prefixlen // 8)],
nibblepart += '.' intToIp(self.ip + self.len() - 1, 4).split(".")[-1],
)
nibblepart += "."
else: else:
nibblepart = "" nibblepart = ""
s = '.'.join(s[first_byte_index:]) s = ".".join(s[first_byte_index:])
return "%s%s.in-addr.arpa." % (nibblepart, s) return "%s%s.in-addr.arpa." % (nibblepart, s)
elif self._ipversion == 6: elif self._ipversion == 6:
ipv4 = self._getIPv4Map() ipv4 = self._getIPv4Map()
if ipv4 is not None: if ipv4 is not None:
return ipv4.reverseName() return ipv4.reverseName()
s = '%032x' % self.ip s = "%032x" % self.ip
if self._prefixlen % 4 != 0: if self._prefixlen % 4 != 0:
nibblepart = "%s-%x" % (s[self._prefixlen:], self.ip + self.len() - 1) nibblepart = "%s-%x" % (s[self._prefixlen :], self.ip + self.len() - 1)
nibblepart += '.' nibblepart += "."
else: else:
nibblepart = "" nibblepart = ""
s = list(s) s = list(s)
s.reverse() s.reverse()
s = '.'.join(s) s = ".".join(s)
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2 first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
return "%s%s.ip6.arpa." % (nibblepart, s[first_nibble_index:]) return "%s%s.ip6.arpa." % (nibblepart, s[first_nibble_index:])
else: else:
@ -937,9 +935,9 @@ class IP(IPint):
>>> print(IP('127.0.0.1').make_net('255.0.0.0')) >>> print(IP('127.0.0.1').make_net('255.0.0.0'))
127.0.0.0/8 127.0.0.0/8
""" """
if '/' in str(netmask): if "/" in str(netmask):
raise ValueError("invalid netmask (%s)" % netmask) raise ValueError("invalid netmask (%s)" % netmask)
return IP('%s/%s' % (self, netmask), make_net=True) return IP("%s/%s" % (self, netmask), make_net=True)
def __getitem__(self, key): def __getitem__(self, key):
"""Called to implement evaluation of self[key]. """Called to implement evaluation of self[key].
@ -968,7 +966,7 @@ class IP(IPint):
IP('10.0.0.0/8') IP('10.0.0.0/8')
""" """
return ("IP('%s')" % (self.strCompressed(1))) return "IP('%s')" % (self.strCompressed(1))
def get_mac(self): def get_mac(self):
""" """
@ -980,15 +978,15 @@ class IP(IPint):
""" """
if self._ipversion != 6: if self._ipversion != 6:
return None return None
if (self.ip & 0x20000ffff000000) != 0x20000fffe000000: if (self.ip & 0x20000FFFF000000) != 0x20000FFFE000000:
return None return None
return '%02x:%02x:%02x:%02x:%02x:%02x' % ( return "%02x:%02x:%02x:%02x:%02x:%02x" % (
(((self.ip >> 56) & 0xff) & 0xfd), (((self.ip >> 56) & 0xFF) & 0xFD),
(self.ip >> 48) & 0xff, (self.ip >> 48) & 0xFF,
(self.ip >> 40) & 0xff, (self.ip >> 40) & 0xFF,
(self.ip >> 16) & 0xff, (self.ip >> 16) & 0xFF,
(self.ip >> 8) & 0xff, (self.ip >> 8) & 0xFF,
self.ip & 0xff, self.ip & 0xFF,
) )
def v46map(self): def v46map(self):
@ -1003,14 +1001,11 @@ class IP(IPint):
IP('192.168.1.1') IP('192.168.1.1')
""" """
if self._ipversion == 4: if self._ipversion == 4:
return IP(str(IPV6_MAP_MASK + self.ip) + return IP(str(IPV6_MAP_MASK + self.ip) + "/%s" % (self._prefixlen + 96))
"/%s" % (self._prefixlen + 96))
else: else:
if self.ip & IPV6_TEST_MAP == IPV6_MAP_MASK: if self.ip & IPV6_TEST_MAP == IPV6_MAP_MASK:
return IP(str(self.ip - IPV6_MAP_MASK) + return IP(str(self.ip - IPV6_MAP_MASK) + "/%s" % (self._prefixlen - 96))
"/%s" % (self._prefixlen - 96)) raise ValueError("%s cannot be converted to an IPv4 address." % repr(self))
raise ValueError("%s cannot be converted to an IPv4 address."
% repr(self))
class IPSet(collections.MutableSet): class IPSet(collections.MutableSet):
@ -1022,7 +1017,7 @@ class IPSet(collections.MutableSet):
# Make sure we only accept IP objects # Make sure we only accept IP objects
for prefix in iterable: for prefix in iterable:
if not isinstance(prefix, IP): if not isinstance(prefix, IP):
raise ValueError('Only IP objects can be added to an IPSet') raise ValueError("Only IP objects can be added to an IPSet")
# Store and optimize # Store and optimize
self.prefixes = iterable[:] self.prefixes = iterable[:]
@ -1083,7 +1078,7 @@ class IPSet(collections.MutableSet):
return IPSet(result) return IPSet(result)
def __repr__(self): def __repr__(self):
return '%s([' % self.__class__.__name__ + ', '.join(map(repr, self.prefixes)) + '])' return "%s([" % self.__class__.__name__ + ", ".join(map(repr, self.prefixes)) + "])"
def len(self): def len(self):
return sum(prefix.len() for prefix in self.prefixes) return sum(prefix.len() for prefix in self.prefixes)
@ -1096,7 +1091,7 @@ class IPSet(collections.MutableSet):
# Check type # Check type
for prefix in value: for prefix in value:
if not isinstance(prefix, IP): if not isinstance(prefix, IP):
raise ValueError('Only IP objects can be added to an IPSet') raise ValueError("Only IP objects can be added to an IPSet")
# Append and optimize # Append and optimize
self.prefixes.extend(value) self.prefixes.extend(value)
@ -1114,7 +1109,7 @@ class IPSet(collections.MutableSet):
# Remove # Remove
for del_prefix in value: for del_prefix in value:
if not isinstance(del_prefix, IP): if not isinstance(del_prefix, IP):
raise ValueError('Only IP objects can be removed from an IPSet') raise ValueError("Only IP objects can be removed from an IPSet")
# First check if this prefix contains anything in our list # First check if this prefix contains anything in our list
found = False found = False
@ -1134,7 +1129,7 @@ class IPSet(collections.MutableSet):
found = False found = False
for i in range(len(self.prefixes)): for i in range(len(self.prefixes)):
if del_prefix in self.prefixes[i]: if del_prefix in self.prefixes[i]:
self.prefixes[i:i + 1] = self.prefixes[i] - del_prefix self.prefixes[i : i + 1] = self.prefixes[i] - del_prefix
break break
self.optimize() self.optimize()
@ -1279,13 +1274,13 @@ def _parseAddressIPv6(ipstr):
fill_pos = len(items) fill_pos = len(items)
index += 2 index += 2
continue continue
pos = text.find(':') pos = text.find(":")
if pos == 0: if pos == 0:
# Invalid IPv6, eg. '1::2:' # Invalid IPv6, eg. '1::2:'
raise ValueError("%r: Invalid IPv6 address" % ipstr) raise ValueError("%r: Invalid IPv6 address" % ipstr)
if pos != -1: if pos != -1:
items.append(text[:pos]) items.append(text[:pos])
if text[pos:pos + 2] == "::": if text[pos : pos + 2] == "::":
index += pos index += pos
else: else:
index += pos + 1 index += pos + 1
@ -1297,13 +1292,13 @@ def _parseAddressIPv6(ipstr):
items.append(text) items.append(text)
break break
if items and '.' in items[-1]: if items and "." in items[-1]:
# IPv6 ending with IPv4 like '::ffff:192.168.0.1' # IPv6 ending with IPv4 like '::ffff:192.168.0.1'
if (fill_pos is not None) and not (fill_pos <= len(items) - 1): if (fill_pos is not None) and not (fill_pos <= len(items) - 1):
# Invalid IPv6: 'ffff:192.168.0.1::' # Invalid IPv6: 'ffff:192.168.0.1::'
raise ValueError("%r: Invalid IPv6 address: '::' after IPv4" % ipstr) raise ValueError("%r: Invalid IPv6 address: '::' after IPv4" % ipstr)
value = parseAddress(items[-1])[0] value = parseAddress(items[-1])[0]
items = items[:-1] + ["%04x" % (value >> 16), "%04x" % (value & 0xffff)] items = items[:-1] + ["%04x" % (value >> 16), "%04x" % (value & 0xFFFF)]
# Expand fill_pos to fill with '0' # Expand fill_pos to fill with '0'
# ['1','2'] with fill_pos=1 => ['1', '0', '0', '0', '0', '0', '0', '2'] # ['1','2'] with fill_pos=1 => ['1', '0', '0', '0', '0', '0', '0', '2']
@ -1311,7 +1306,7 @@ def _parseAddressIPv6(ipstr):
diff = 8 - len(items) diff = 8 - len(items)
if diff <= 0: if diff <= 0:
raise ValueError("%r: Invalid IPv6 address: '::' is not needed" % ipstr) raise ValueError("%r: Invalid IPv6 address: '::' is not needed" % ipstr)
items = items[:fill_pos] + ['0'] * diff + items[fill_pos:] items = items[:fill_pos] + ["0"] * diff + items[fill_pos:]
# Here we have a list of 8 strings # Here we have a list of 8 strings
if len(items) != 8: if len(items) != 8:
@ -1324,7 +1319,7 @@ def _parseAddressIPv6(ipstr):
for item in items: for item in items:
try: try:
item = int(item, 16) item = int(item, 16)
error = not (0 <= item <= 0xffff) error = not (0 <= item <= 0xFFFF)
except ValueError: except ValueError:
error = True error = True
if error: if error:
@ -1388,7 +1383,7 @@ def parseAddress(ipstr, ipversion=0):
except ValueError: except ValueError:
intval = None intval = None
if ipstr.startswith('0x') and hexval is not None: if ipstr.startswith("0x") and hexval is not None:
if hexval > MAX_IPV6_ADDRESS: if hexval > MAX_IPV6_ADDRESS:
raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, hexval)) raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, hexval))
if hexval <= MAX_IPV4_ADDRESS: if hexval <= MAX_IPV4_ADDRESS:
@ -1396,19 +1391,19 @@ def parseAddress(ipstr, ipversion=0):
else: else:
return (hexval, 6) return (hexval, 6)
if ipstr.find(':') != -1: if ipstr.find(":") != -1:
return (_parseAddressIPv6(ipstr), 6) return (_parseAddressIPv6(ipstr), 6)
elif len(ipstr) == 32 and hexval is not None: elif len(ipstr) == 32 and hexval is not None:
# assume IPv6 in pure hexadecimal notation # assume IPv6 in pure hexadecimal notation
return (hexval, 6) return (hexval, 6)
elif ipstr.find('.') != -1 or (intval is not None and intval < 256 and ipversion != 6): elif ipstr.find(".") != -1 or (intval is not None and intval < 256 and ipversion != 6):
# assume IPv4 ('127' gets interpreted as '127.0.0.0') # assume IPv4 ('127' gets interpreted as '127.0.0.0')
bytes = ipstr.split('.') bytes = ipstr.split(".")
if len(bytes) > 4: if len(bytes) > 4:
raise ValueError("IPv4 Address with more than 4 bytes") raise ValueError("IPv4 Address with more than 4 bytes")
bytes += ['0'] * (4 - len(bytes)) bytes += ["0"] * (4 - len(bytes))
bytes = [int(x) for x in bytes] bytes = [int(x) for x in bytes]
for x in bytes: for x in bytes:
if x > 255 or x < 0: if x > 255 or x < 0:
@ -1438,12 +1433,12 @@ def intToIp(ip, version):
if ip < 0: if ip < 0:
raise ValueError("IPs can't be negative: %d" % (ip)) raise ValueError("IPs can't be negative: %d" % (ip))
ret = '' ret = ""
if version == 4: if version == 4:
if ip > MAX_IPV4_ADDRESS: if ip > MAX_IPV4_ADDRESS:
raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, ip)) raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, ip))
for l in xrange(4): for l in xrange(4):
ret = str(ip & 0xff) + '.' + ret ret = str(ip & 0xFF) + "." + ret
ip = ip >> 8 ip = ip >> 8
ret = ret[:-1] ret = ret[:-1]
elif version == 6: elif version == 6:
@ -1453,7 +1448,7 @@ def intToIp(ip, version):
for x in xrange(1, 33): for x in xrange(1, 33):
ret = l[-x] + ret ret = l[-x] + ret
if x % 4 == 0: if x % 4 == 0:
ret = ':' + ret ret = ":" + ret
ret = ret[1:] ret = ret[1:]
else: else:
raise ValueError("only IPv4 and IPv6 supported") raise ValueError("only IPv4 and IPv6 supported")
@ -1494,10 +1489,24 @@ def _countFollowingZeros(l):
return 1 + _countFollowingZeros(l[1:]) return 1 + _countFollowingZeros(l[1:])
_BitTable = {'0': '0000', '1': '0001', '2': '0010', '3': '0011', _BitTable = {
'4': '0100', '5': '0101', '6': '0110', '7': '0111', "0": "0000",
'8': '1000', '9': '1001', 'a': '1010', 'b': '1011', "1": "0001",
'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'} "2": "0010",
"3": "0011",
"4": "0100",
"5": "0101",
"6": "0110",
"7": "0111",
"8": "1000",
"9": "1001",
"a": "1010",
"b": "1011",
"c": "1100",
"d": "1101",
"e": "1110",
"f": "1111",
}
def _intToBin(val): def _intToBin(val):
@ -1506,11 +1515,11 @@ def _intToBin(val):
if val < 0: if val < 0:
raise ValueError("Only positive values allowed") raise ValueError("Only positive values allowed")
s = "%x" % val s = "%x" % val
ret = '' ret = ""
for x in s: for x in s:
ret += _BitTable[x] ret += _BitTable[x]
# remove leading zeros # remove leading zeros
while ret[0] == '0' and len(ret) > 1: while ret[0] == "0" and len(ret) > 1:
ret = ret[1:] ret = ret[1:]
return ret return ret
@ -1595,7 +1604,7 @@ def _checkNetmask(netmask, masklen):
def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version): def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
"""Check if a base addess of a network is compatible with a prefixlen""" """Check if a base addess of a network is compatible with a prefixlen"""
try: try:
return (net & _prefixlenToNetmask(prefixlen, version) == net) return net & _prefixlenToNetmask(prefixlen, version) == net
except ValueError: except ValueError:
return False return False
@ -1637,8 +1646,8 @@ def _remove_subprefix(prefix, subprefix):
# Start cutting in half, recursively # Start cutting in half, recursively
prefixes = [ prefixes = [
IP('%s/%d' % (prefix[0], prefix._prefixlen + 1)), IP("%s/%d" % (prefix[0], prefix._prefixlen + 1)),
IP('%s/%d' % (prefix[int(prefix.len() / 2)], prefix._prefixlen + 1)), IP("%s/%d" % (prefix[int(prefix.len() / 2)], prefix._prefixlen + 1)),
] ]
if subprefix in prefixes[0]: if subprefix in prefixes[0]:
return _remove_subprefix(prefixes[0], subprefix) + IPSet([prefixes[1]]) return _remove_subprefix(prefixes[0], subprefix) + IPSet([prefixes[1]])

View file

@ -1,11 +1,12 @@
import libvirt
import threading
import socket
import re import re
from vrtManager import util import socket
from vrtManager.rwlock import ReadWriteLock import threading
import libvirt
from django.conf import settings from django.conf import settings
from libvirt import libvirtError from libvirt import libvirtError
from vrtManager import util
from vrtManager.rwlock import ReadWriteLock
CONN_SOCKET = 4 CONN_SOCKET = 4
CONN_TLS = 3 CONN_TLS = 3
@ -18,6 +19,7 @@ TCP_PORT = 16509
class wvmEventLoop(threading.Thread): class wvmEventLoop(threading.Thread):
""" Event Loop Class""" """ Event Loop Class"""
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
# register the default event implementation # register the default event implementation
# of libvirt, as we do not have an existing # of libvirt, as we do not have an existing
@ -25,7 +27,7 @@ class wvmEventLoop(threading.Thread):
libvirt.virEventRegisterDefaultImpl() libvirt.virEventRegisterDefaultImpl()
if name is None: if name is None:
name = 'libvirt event loop' name = "libvirt event loop"
super(wvmEventLoop, self).__init__(group, target, name, args, kwargs) super(wvmEventLoop, self).__init__(group, target, name, args, kwargs)
@ -46,6 +48,7 @@ class wvmConnection(object):
class representing a single connection stored in the Connection Manager class representing a single connection stored in the Connection Manager
# to-do: may also need some locking to ensure to not connect simultaniously in 2 threads # to-do: may also need some locking to ensure to not connect simultaniously in 2 threads
""" """
def __init__(self, host, login, passwd, conn): def __init__(self, host, login, passwd, conn):
""" """
Sets all class attributes and tries to open the connection Sets all class attributes and tries to open the connection
@ -86,10 +89,12 @@ class wvmConnection(object):
# * set keep alive interval # * set keep alive interval
# * set connection close/fail handler # * set connection close/fail handler
try: try:
self.connection.setKeepAlive(connection_manager.keepalive_interval, connection_manager.keepalive_count) self.connection.setKeepAlive(
connection_manager.keepalive_interval, connection_manager.keepalive_count
)
try: try:
self.connection.registerCloseCallback(self.__connection_close_callback, None) self.connection.registerCloseCallback(self.__connection_close_callback, None)
except: except Exception:
# Temporary fix for libvirt > libvirt-0.10.2-41 # Temporary fix for libvirt > libvirt-0.10.2-41
pass pass
except libvirtError as e: except libvirtError as e:
@ -134,49 +139,49 @@ class wvmConnection(object):
def __connect_tcp(self): def __connect_tcp(self):
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE] flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
auth = [flags, self.__libvirt_auth_credentials_callback, None] auth = [flags, self.__libvirt_auth_credentials_callback, None]
uri = f'qemu+tcp://{self.host}/system' uri = f"qemu+tcp://{self.host}/system"
try: try:
self.connection = libvirt.openAuth(uri, auth, 0) self.connection = libvirt.openAuth(uri, auth, 0)
self.last_error = None self.last_error = None
except libvirtError as e: except libvirtError as e:
self.last_error = f'Connection Failed: {str(e)}' self.last_error = f"Connection Failed: {str(e)}"
self.connection = None self.connection = None
def __connect_ssh(self): def __connect_ssh(self):
uri = 'qemu+ssh://%s@%s/system' % (self.login, self.host) uri = "qemu+ssh://%s@%s/system" % (self.login, self.host)
try: try:
self.connection = libvirt.open(uri) self.connection = libvirt.open(uri)
self.last_error = None self.last_error = None
except libvirtError as e: except libvirtError as e:
self.last_error = f'Connection Failed: {str(e)} --- ' + repr(libvirt.virGetLastError()) self.last_error = f"Connection Failed: {str(e)} --- " + repr(libvirt.virGetLastError())
self.connection = None self.connection = None
def __connect_tls(self): def __connect_tls(self):
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE] flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
auth = [flags, self.__libvirt_auth_credentials_callback, None] auth = [flags, self.__libvirt_auth_credentials_callback, None]
uri = 'qemu+tls://%s@%s/system' % (self.login, self.host) uri = "qemu+tls://%s@%s/system" % (self.login, self.host)
try: try:
self.connection = libvirt.openAuth(uri, auth, 0) self.connection = libvirt.openAuth(uri, auth, 0)
self.last_error = None self.last_error = None
except libvirtError as e: except libvirtError as e:
self.last_error = f'Connection Failed: {str(e)}' self.last_error = f"Connection Failed: {str(e)}"
self.connection = None self.connection = None
def __connect_socket(self): def __connect_socket(self):
uri = 'qemu:///system' uri = "qemu:///system"
try: try:
self.connection = libvirt.open(uri) self.connection = libvirt.open(uri)
self.last_error = None self.last_error = None
except libvirtError as e: except libvirtError as e:
self.last_error = f'Connection Failed: {str(e)}' self.last_error = f"Connection Failed: {str(e)}"
self.connection = None self.connection = None
def close(self): def close(self):
@ -202,23 +207,23 @@ class wvmConnection(object):
# unregister callback (as it is no longer valid if this instance gets deleted) # unregister callback (as it is no longer valid if this instance gets deleted)
try: try:
self.connection.unregisterCloseCallback() self.connection.unregisterCloseCallback()
except: except Exception:
pass pass
def __str__(self): def __str__(self):
if self.type == CONN_TCP: if self.type == CONN_TCP:
type_str = 'tcp' type_str = "tcp"
elif self.type == CONN_SSH: elif self.type == CONN_SSH:
type_str = 'ssh' type_str = "ssh"
elif self.type == CONN_TLS: elif self.type == CONN_TLS:
type_str = 'tls' type_str = "tls"
else: else:
type_str = 'invalid_type' type_str = "invalid_type"
return f'qemu+{type_str}://{self.login}@{self.host}/system' return f"qemu+{type_str}://{self.login}@{self.host}/system"
def __repr__(self): def __repr__(self):
return f'<wvmConnection {str(self)}>' return f"<wvmConnection {str(self)}>"
class wvmConnectionManager(object): class wvmConnectionManager(object):
@ -307,7 +312,7 @@ class wvmConnectionManager(object):
socket_host = socket.socket(socket.AF_INET, socket.SOCK_STREAM) socket_host = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
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:
@ -320,7 +325,7 @@ class wvmConnectionManager(object):
socket_host.connect((hostname, TLS_PORT)) socket_host.connect((hostname, TLS_PORT))
if conn_type == CONN_SOCKET: if conn_type == CONN_SOCKET:
socket_host = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) socket_host = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
socket_host.connect('/var/run/libvirt/libvirt-sock') socket_host.connect("/var/run/libvirt/libvirt-sock")
socket_host.close() socket_host.close()
return True return True
except Exception as err: except Exception as err:
@ -328,8 +333,8 @@ class wvmConnectionManager(object):
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,
) )
@ -353,15 +358,16 @@ class wvmConnect(object):
def get_dom_cap_xml(self, arch, machine): def get_dom_cap_xml(self, arch, machine):
""" Return domain capabilities xml""" """ Return domain capabilities xml"""
emulatorbin = self.get_emulator(arch) emulatorbin = self.get_emulator(arch)
virttype = 'kvm' if 'kvm' in self.get_hypervisors_domain_types()[arch] else 'qemu' virttype = "kvm" if "kvm" in self.get_hypervisors_domain_types()[arch] else "qemu"
machine_types = self.get_machine_types(arch) machine_types = self.get_machine_types(arch)
if not machine or machine not in machine_types: if not machine or machine not in machine_types:
machine = 'pc' if 'pc' in machine_types else machine_types[0] machine = "pc" if "pc" in machine_types else machine_types[0]
return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype) return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype)
def get_capabilities(self, arch): def get_capabilities(self, arch):
""" Host Capabilities for specified architecture """ """ Host Capabilities for specified architecture """
def guests(ctx): def guests(ctx):
result = dict() result = dict()
for arch_el in ctx.xpath("/capabilities/guest/arch[@name='{}']".format(arch)): for arch_el in ctx.xpath("/capabilities/guest/arch[@name='{}']".format(arch)):
@ -371,11 +377,9 @@ class wvmConnect(object):
result["machines"] = [] result["machines"] = []
for m in arch_el.xpath("machine"): for m in arch_el.xpath("machine"):
result["machines"].append({ result["machines"].append(
"machine": m.text, {"machine": m.text, "max_cpu": m.get("maxCpus"), "canonical": m.get("canonical")}
"max_cpu": m.get("maxCpus"), )
"canonical": m.get("canonical")
})
guest_el = arch_el.getparent() guest_el = arch_el.getparent()
for f in guest_el.xpath("features"): for f in guest_el.xpath("features"):
@ -400,7 +404,7 @@ class wvmConnect(object):
result["os_support"] = util.get_xml_path(xml, "/domainCapabilities/os/@supported") result["os_support"] = util.get_xml_path(xml, "/domainCapabilities/os/@supported")
result["loader_support"] = util.get_xml_path(xml, "/domainCapabilities/os/loader/@supported") result["loader_support"] = util.get_xml_path(xml, "/domainCapabilities/os/loader/@supported")
if result["loader_support"] == 'yes': if result["loader_support"] == "yes":
result["loaders"] = self.get_os_loaders(arch, machine) result["loaders"] = self.get_os_loaders(arch, machine)
result["loader_enums"] = self.get_os_loader_enums(arch, machine) result["loader_enums"] = self.get_os_loader_enums(arch, machine)
@ -410,27 +414,29 @@ class wvmConnect(object):
result["cpu_custom_models"] = self.get_cpu_custom_types(arch, machine) result["cpu_custom_models"] = self.get_cpu_custom_types(arch, machine)
result["disk_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/disk/@supported") result["disk_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/disk/@supported")
if result["disk_support"] == 'yes': if result["disk_support"] == "yes":
result["disk_devices"] = self.get_disk_device_types(arch, machine) result["disk_devices"] = self.get_disk_device_types(arch, machine)
result["disk_bus"] = self.get_disk_bus_types(arch, machine) result["disk_bus"] = self.get_disk_bus_types(arch, machine)
result["graphics_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/graphics/@supported") result["graphics_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/graphics/@supported")
if result["graphics_support"] == 'yes': if result["graphics_support"] == "yes":
result["graphics_types"] = self.get_graphics_types(arch, machine) result["graphics_types"] = self.get_graphics_types(arch, machine)
result["video_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/video/@supported") result["video_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/video/@supported")
if result["video_support"] == 'yes': if result["video_support"] == "yes":
result["video_types"] = self.get_video_models(arch, machine) result["video_types"] = self.get_video_models(arch, machine)
result["hostdev_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/hostdev/@supported") result["hostdev_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/hostdev/@supported")
if result["hostdev_support"] == 'yes': if result["hostdev_support"] == "yes":
result["hostdev_types"] = self.get_hostdev_modes(arch, machine) result["hostdev_types"] = self.get_hostdev_modes(arch, machine)
result["hostdev_startup_policies"] = self.get_hostdev_startup_policies(arch, machine) result["hostdev_startup_policies"] = self.get_hostdev_startup_policies(arch, machine)
result["hostdev_subsys_types"] = self.get_hostdev_subsys_types(arch, machine) result["hostdev_subsys_types"] = self.get_hostdev_subsys_types(arch, machine)
result["features_gic_support"] = util.get_xml_path(xml, "/domainCapabilities/features/gic/@supported") result["features_gic_support"] = util.get_xml_path(xml, "/domainCapabilities/features/gic/@supported")
result["features_genid_support"] = util.get_xml_path(xml, "/domainCapabilities/features/genid/@supported") result["features_genid_support"] = util.get_xml_path(xml, "/domainCapabilities/features/genid/@supported")
result["features_vmcoreinfo_support"] = util.get_xml_path(xml, "/domainCapabilities/features/vmcoreinfo/@supported") result["features_vmcoreinfo_support"] = util.get_xml_path(
xml, "/domainCapabilities/features/vmcoreinfo/@supported"
)
result["features_sev_support"] = util.get_xml_path(xml, "/domainCapabilities/features/sev/@supported") result["features_sev_support"] = util.get_xml_path(xml, "/domainCapabilities/features/sev/@supported")
return result return result
@ -510,12 +516,12 @@ class wvmConnect(object):
:return: Get cache available modes :return: Get cache available modes
""" """
return { return {
'default': 'Default', "default": "Default",
'none': 'Disabled', "none": "Disabled",
'writethrough': 'Write through', "writethrough": "Write through",
'writeback': 'Write back', "writeback": "Write back",
'directsync': 'Direct sync', # since libvirt 0.9.5 "directsync": "Direct sync", # since libvirt 0.9.5
'unsafe': 'Unsafe', # since libvirt 0.9.7 "unsafe": "Unsafe", # since libvirt 0.9.7
} }
def get_io_modes(self): def get_io_modes(self):
@ -523,9 +529,9 @@ class wvmConnect(object):
:return: available io modes :return: available io modes
""" """
return { return {
'default': 'Default', "default": "Default",
'native': 'Native', "native": "Native",
'threads': 'Threads', "threads": "Threads",
} }
def get_discard_modes(self): def get_discard_modes(self):
@ -533,9 +539,9 @@ class wvmConnect(object):
:return: available discard modes :return: available discard modes
""" """
return { return {
'default': 'Default', "default": "Default",
'ignore': 'Ignore', "ignore": "Ignore",
'unmap': 'Unmap', "unmap": "Unmap",
} }
def get_detect_zeroes_modes(self): def get_detect_zeroes_modes(self):
@ -543,21 +549,22 @@ class wvmConnect(object):
:return: available detect zeroes modes :return: available detect zeroes modes
""" """
return { return {
'default': 'Default', "default": "Default",
'on': 'On', "on": "On",
'off': 'Off', "off": "Off",
'unmap': 'Unmap', "unmap": "Unmap",
} }
def get_hypervisors_domain_types(self): def get_hypervisors_domain_types(self):
""" """
:return: hypervisor domain types :return: hypervisor domain types
""" """
def hypervisors(ctx): def hypervisors(ctx):
result = {} result = {}
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
@ -567,9 +574,10 @@ class wvmConnect(object):
""" """
:return: hypervisor and its machine types :return: hypervisor and its machine types
""" """
def machines(ctx): def machines(ctx):
result = dict() result = dict()
for arche in ctx.xpath('/capabilities/guest/arch'): for arche in ctx.xpath("/capabilities/guest/arch"):
arch = arche.get("name") arch = arche.get("name")
result[arch] = self.get_machine_types(arch) result[arch] = self.get_machine_types(arch)
@ -587,6 +595,7 @@ class wvmConnect(object):
""" """
:return: canonical(if exist) name of machine types :return: canonical(if exist) name of machine types
""" """
def machines(ctx): def machines(ctx):
result = list() result = list()
canonical_name = ctx.xpath("/capabilities/guest/arch[@name='{}']/machine[@canonical]".format(arch)) canonical_name = ctx.xpath("/capabilities/guest/arch[@name='{}']/machine[@canonical]".format(arch))
@ -602,22 +611,24 @@ class wvmConnect(object):
""" """
:return: host emulators list :return: host emulators list
""" """
def emulators(ctx): def emulators(ctx):
result = {} result = {}
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)
def get_os_loaders(self, arch='x86_64', machine='pc'): def get_os_loaders(self, arch="x86_64", machine="pc"):
""" """
:param arch: architecture :param arch: architecture
:param machine: :param machine:
:return: available os loaders list :return: available os loaders list
""" """
def get_os_loaders(ctx): def get_os_loaders(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/value")] return [v.text for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/value")]
@ -629,6 +640,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available os loaders list :return: available os loaders list
""" """
def get_os_loader_enums(ctx): def get_os_loader_enums(ctx):
result = dict() result = dict()
enums = [v for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/enum/@name")] enums = [v for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/enum/@name")]
@ -645,6 +657,7 @@ class wvmConnect(object):
:param arch: :param arch:
:return: available disk bus types list :return: available disk bus types list
""" """
def get_bus_list(ctx): def get_bus_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='bus']/value")] return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='bus']/value")]
@ -657,6 +670,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available disk device type list :return: available disk device type list
""" """
def get_device_list(ctx): def get_device_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='diskDevice']/value")] return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='diskDevice']/value")]
@ -669,6 +683,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available graphics types :return: available graphics types
""" """
def get_graphics_list(ctx): def get_graphics_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/graphics/enum[@name='type']/value")] return [v.text for v in ctx.xpath("/domainCapabilities/devices/graphics/enum[@name='type']/value")]
@ -680,6 +695,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available cpu modes :return: available cpu modes
""" """
def get_cpu_modes(ctx): def get_cpu_modes(ctx):
return [v for v in ctx.xpath("/domainCapabilities/cpu/mode[@supported='yes']/@name")] return [v for v in ctx.xpath("/domainCapabilities/cpu/mode[@supported='yes']/@name")]
@ -691,6 +707,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available graphics types :return: available graphics types
""" """
def get_custom_list(ctx): def get_custom_list(ctx):
usable_yes = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='yes']" usable_yes = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='yes']"
usable_unknown = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='unknown']" usable_unknown = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='unknown']"
@ -706,6 +723,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return. available nodedev modes :return. available nodedev modes
""" """
def get_hostdev_list(ctx): def get_hostdev_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='mode']/value")] return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='mode']/value")]
@ -717,6 +735,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available hostdev modes :return: available hostdev modes
""" """
def get_hostdev_list(ctx): def get_hostdev_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='startupPolicy']/value")] return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='startupPolicy']/value")]
@ -728,6 +747,7 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available nodedev sub system types :return: available nodedev sub system types
""" """
def get_hostdev_list(ctx): def get_hostdev_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='subsysType']/value")] return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='subsysType']/value")]
@ -737,19 +757,19 @@ class wvmConnect(object):
""" """
:return: network card models :return: network card models
""" """
return ['default', 'e1000', 'virtio'] return ["default", "e1000", "virtio"]
def get_image_formats(self): def get_image_formats(self):
""" """
:return: available image formats :return: available image formats
""" """
return ['raw', 'qcow', 'qcow2'] return ["raw", "qcow", "qcow2"]
def get_file_extensions(self): def get_file_extensions(self):
""" """
:return: available image filename extensions :return: available image filename extensions
""" """
return ['img', 'qcow', 'qcow2'] return ["img", "qcow", "qcow2"]
def get_video_models(self, arch, machine): def get_video_models(self, arch, machine):
""" """
@ -757,9 +777,10 @@ class wvmConnect(object):
:param machine: :param machine:
:return: available graphics video types :return: available graphics video types
""" """
def get_video_list(ctx): def get_video_list(ctx):
result = [] result = []
for video_enum in ctx.xpath('/domainCapabilities/devices/video/enum'): for video_enum in ctx.xpath("/domainCapabilities/devices/video/enum"):
if video_enum.xpath("@name")[0] == "modelType": if video_enum.xpath("@name")[0] == "modelType":
for values in video_enum: for values in video_enum:
result.append(values.text) result.append(values.text)
@ -787,8 +808,8 @@ class wvmConnect(object):
def get_network_forward(self, net_name): def get_network_forward(self, net_name):
def get_forward(doc): def get_forward(doc):
forward_mode = util.get_xpath(doc, '/network/forward/@mode') forward_mode = util.get_xpath(doc, "/network/forward/@mode")
return forward_mode or 'isolated' return forward_mode or "isolated"
net = self.get_network(net_name) net = self.get_network(net_name)
xml = net.XMLDesc(0) xml = net.XMLDesc(0)
@ -825,14 +846,14 @@ class wvmConnect(object):
netdevice = [] netdevice = []
def get_info(doc): def get_info(doc):
dev_type = util.get_xpath(doc, '/device/capability/@type') dev_type = util.get_xpath(doc, "/device/capability/@type")
interface = util.get_xpath(doc, '/device/capability/interface') interface = util.get_xpath(doc, "/device/capability/interface")
return dev_type, interface return dev_type, interface
for dev in self.wvm.listAllDevices(0): for dev in self.wvm.listAllDevices(0):
xml = dev.XMLDesc(0) xml = dev.XMLDesc(0)
(dev_type, interface) = util.get_xml_path(xml, func=get_info) (dev_type, interface) = util.get_xml_path(xml, func=get_info)
if dev_type == 'net': if dev_type == "net":
netdevice.append(interface) netdevice.append(interface)
return netdevice return netdevice
@ -850,9 +871,9 @@ class wvmConnect(object):
else: else:
vcpu = util.get_xpath(doc, "/domain/vcpu") vcpu = util.get_xpath(doc, "/domain/vcpu")
title = util.get_xpath(doc, "/domain/title") title = util.get_xpath(doc, "/domain/title")
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():
@ -860,12 +881,12 @@ class wvmConnect(object):
xml = dom.XMLDesc(0) xml = dom.XMLDesc(0)
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info) (mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
vname[dom.name()] = { vname[dom.name()] = {
'status': dom.info()[0], "status": dom.info()[0],
'uuid': dom.UUIDString(), "uuid": dom.UUIDString(),
'vcpu': vcpu, "vcpu": vcpu,
'memory': mem, "memory": mem,
'title': title, "title": title,
'description': description, "description": description,
} }
return vname return vname
@ -882,20 +903,20 @@ class wvmConnect(object):
else: else:
vcpu = util.get_xpath(ctx, "/domain/vcpu") vcpu = util.get_xpath(ctx, "/domain/vcpu")
title = util.get_xpath(ctx, "/domain/title") title = util.get_xpath(ctx, "/domain/title")
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(),
'status': dom.info()[0], "status": dom.info()[0],
'uuid': dom.UUIDString(), "uuid": dom.UUIDString(),
'vcpu': vcpu, "vcpu": vcpu,
'memory': mem, "memory": mem,
'title': title, "title": title,
'description': description, "description": description,
} }
def close(self): def close(self):
@ -931,7 +952,7 @@ class wvmConnect(object):
for arch, patterns in util.UEFI_ARCH_PATTERNS.items(): for arch, patterns in util.UEFI_ARCH_PATTERNS.items():
for pattern in patterns: for pattern in patterns:
if re.match(pattern, path): if re.match(pattern, path):
return ("UEFI %(arch)s: %(path)s" % {"arch": arch, "path": path}) return "UEFI %(arch)s: %(path)s" % {"arch": arch, "path": path}
return "Custom: %(path)s" % {"path": path} return "Custom: %(path)s" % {"path": path}
@ -945,15 +966,17 @@ class wvmConnect(object):
""" """
Return True if libvirt advertises support for proper UEFI setup Return True if libvirt advertises support for proper UEFI setup
""" """
return ("readonly" in loader_enums and "yes" in loader_enums.get("readonly")) return "readonly" in loader_enums and "yes" in loader_enums.get("readonly")
def is_supports_virtio(self, arch, machine): def is_supports_virtio(self, arch, machine):
if not self.is_qemu(): if not self.is_qemu():
return False return False
# These _only_ support virtio so don't check the OS # These _only_ support virtio so don't check the OS
if arch in ["aarch64", "armv7l", "ppc64", "ppc64le", "s390x", "riscv64", "riscv32"] and \ if arch in ["aarch64", "armv7l", "ppc64", "ppc64le", "s390x", "riscv64", "riscv32"] and machine in [
machine in ["virt", "pseries"]: "virt",
"pseries",
]:
return True return True
if arch in ["x86_64", "i686"]: if arch in ["x86_64", "i686"]:

View file

@ -1,4 +1,5 @@
import string import string
from vrtManager import util from vrtManager import util
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
@ -12,15 +13,15 @@ def get_rbd_storage_data(stg):
for host in doc.xpath("/pool/source/host"): for host in doc.xpath("/pool/source/host"):
name = host.prop("name") name = host.prop("name")
if name: if name:
hosts.append({'name': name, 'port': host.prop("port")}) hosts.append({"name": name, "port": host.prop("port")})
return hosts return hosts
ceph_hosts = util.get_xml_path(xml, func=get_ceph_hosts) ceph_hosts = util.get_xml_path(xml, func=get_ceph_hosts)
secret_uuid = util.get_xml_path(xml, "/pool/source/auth/secret/@uuid") secret_uuid = util.get_xml_path(xml, "/pool/source/auth/secret/@uuid")
return ceph_user, secret_uuid, ceph_hosts return ceph_user, secret_uuid, ceph_hosts
class wvmCreate(wvmConnect): class wvmCreate(wvmConnect):
def get_storages_images(self): def get_storages_images(self):
""" """
Function return all images on all storages Function return all images on all storages
@ -31,10 +32,10 @@ class wvmCreate(wvmConnect):
stg = self.get_storage(storage) stg = self.get_storage(storage)
try: try:
stg.refresh(0) stg.refresh(0)
except: except Exception:
pass pass
for img in stg.listVolumes(): for img in stg.listVolumes():
if img.lower().endswith('.iso'): if img.lower().endswith(".iso"):
pass pass
else: else:
images.append(img) images.append(img)
@ -52,11 +53,11 @@ class wvmCreate(wvmConnect):
size = int(size) * 1073741824 size = int(size) * 1073741824
stg = self.get_storage(storage) stg = self.get_storage(storage)
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type") storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
if storage_type == 'dir': if storage_type == "dir":
if image_format in ('qcow', 'qcow2'): if image_format in ("qcow", "qcow2"):
name += '.' + image_format name += "." + image_format
else: else:
name += '.img' name += ".img"
alloc = 0 alloc = 0
else: else:
alloc = size alloc = size
@ -91,12 +92,12 @@ class wvmCreate(wvmConnect):
def get_volume_type(self, path): def get_volume_type(self, path):
vol = self.get_volume_by_path(path) vol = self.get_volume_by_path(path)
vol_type = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type") vol_type = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
if vol_type == 'unknown' or vol_type == 'iso': if vol_type == "unknown" or vol_type == "iso":
return 'raw' return "raw"
if vol_type: if vol_type:
return vol_type return vol_type
else: else:
return 'raw' return "raw"
def get_volume_path(self, volume, pool=None): def get_volume_path(self, volume, pool=None):
if not pool: if not pool:
@ -125,8 +126,8 @@ class wvmCreate(wvmConnect):
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type") storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type") format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
if storage_type == 'dir': if storage_type == "dir":
clone += '.img' clone += ".img"
else: else:
metadata = False metadata = False
xml = f""" xml = f"""
@ -159,9 +160,27 @@ class wvmCreate(wvmConnect):
vol = self.get_volume_by_path(path) vol = self.get_volume_by_path(path)
vol.delete() vol.delete()
def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, volumes, def create_instance(
networks, nwfilter, graphics, virtio, listen_addr, self,
video="vga", console_pass="random", mac=None, qemu_ga=True): name,
memory,
vcpu,
vcpu_mode,
uuid,
arch,
machine,
firmware,
volumes,
networks,
nwfilter,
graphics,
virtio,
listen_addr,
video="vga",
console_pass="random",
mac=None,
qemu_ga=True,
):
""" """
Create VM function Create VM function
""" """
@ -178,33 +197,37 @@ class wvmCreate(wvmConnect):
<memory unit='KiB'>{memory}</memory> <memory unit='KiB'>{memory}</memory>
<vcpu>{vcpu}</vcpu>""" <vcpu>{vcpu}</vcpu>"""
if dom_caps["os_support"] == 'yes': if dom_caps["os_support"] == "yes":
xml += f"""<os> xml += f"""<os>
<type arch='{arch}' machine='{machine}'>{caps["os_type"]}</type>""" <type arch='{arch}' machine='{machine}'>{caps["os_type"]}</type>"""
xml += """ <boot dev='hd'/> xml += """ <boot dev='hd'/>
<boot dev='cdrom'/> <boot dev='cdrom'/>
<bootmenu enable='yes'/>""" <bootmenu enable='yes'/>"""
if firmware: if firmware:
if firmware["secure"] == 'yes': if firmware["secure"] == "yes":
xml += """<loader readonly='%s' type='%s' secure='%s'>%s</loader>""" % (firmware["readonly"], xml += """<loader readonly='%s' type='%s' secure='%s'>%s</loader>""" % (
firmware["readonly"],
firmware["type"], firmware["type"],
firmware["secure"], firmware["secure"],
firmware["loader"]) firmware["loader"],
if firmware["secure"] == 'no': )
xml += """<loader readonly='%s' type='%s'>%s</loader>""" % (firmware["readonly"], if firmware["secure"] == "no":
xml += """<loader readonly='%s' type='%s'>%s</loader>""" % (
firmware["readonly"],
firmware["type"], firmware["type"],
firmware["loader"]) firmware["loader"],
)
xml += """</os>""" xml += """</os>"""
if caps["features"]: if caps["features"]:
xml += """<features>""" xml += """<features>"""
if 'acpi' in caps["features"]: if "acpi" in caps["features"]:
xml += """<acpi/>""" xml += """<acpi/>"""
if 'apic' in caps["features"]: if "apic" in caps["features"]:
xml += """<apic/>""" xml += """<apic/>"""
if 'pae' in caps["features"]: if "pae" in caps["features"]:
xml += """<pae/>""" xml += """<pae/>"""
if firmware.get("secure", 'no') == 'yes': if firmware.get("secure", "no") == "yes":
xml += """<smm state="on"/>""" xml += """<smm state="on"/>"""
xml += """</features>""" xml += """</features>"""
@ -235,56 +258,69 @@ class wvmCreate(wvmConnect):
for volume in volumes: for volume in volumes:
disk_opts = '' disk_opts = ""
if volume['cache_mode'] is not None and volume['cache_mode'] != 'default': if volume["cache_mode"] is not None and volume["cache_mode"] != "default":
disk_opts += f"cache='{volume['cache_mode']}' " disk_opts += f"cache='{volume['cache_mode']}' "
if volume['io_mode'] is not None and volume['io_mode'] != 'default': if volume["io_mode"] is not None and volume["io_mode"] != "default":
disk_opts += f"io='{volume['io_mode']}' " disk_opts += f"io='{volume['io_mode']}' "
if volume['discard_mode'] is not None and volume['discard_mode'] != 'default': if volume["discard_mode"] is not None and volume["discard_mode"] != "default":
disk_opts += f"discard='{volume['discard_mode']}' " disk_opts += f"discard='{volume['discard_mode']}' "
if volume['detect_zeroes_mode'] is not None and volume['detect_zeroes_mode'] != 'default': if volume["detect_zeroes_mode"] is not None and volume["detect_zeroes_mode"] != "default":
disk_opts += f"detect_zeroes='{volume['detect_zeroes_mode']}' " disk_opts += f"detect_zeroes='{volume['detect_zeroes_mode']}' "
stg = self.get_storage_by_vol_path(volume['path']) stg = self.get_storage_by_vol_path(volume["path"])
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type") stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
if volume['device'] == 'cdrom': add_cd = False if volume["device"] == "cdrom":
add_cd = False
if stg_type == 'rbd': if stg_type == "rbd":
ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg) ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg)
xml += """<disk type='network' device='disk'> xml += """<disk type='network' device='disk'>
<driver name='qemu' type='%s' %s />""" % (volume['type'], disk_opts) <driver name='qemu' type='%s' %s />""" % (
volume["type"],
disk_opts,
)
xml += """ <auth username='%s'> xml += """ <auth username='%s'>
<secret type='ceph' uuid='%s'/> <secret type='ceph' uuid='%s'/>
</auth> </auth>
<source protocol='rbd' name='%s'>""" % (ceph_user, secret_uuid, volume['path']) <source protocol='rbd' name='%s'>""" % (
ceph_user,
secret_uuid,
volume["path"],
)
if isinstance(ceph_hosts, list): if isinstance(ceph_hosts, list):
for host in ceph_hosts: for host in ceph_hosts:
if host.get('port'): if host.get("port"):
xml += """ xml += """
<host name='%s' port='%s'/>""" % (host.get('name'), host.get('port')) <host name='%s' port='%s'/>""" % (
host.get("name"),
host.get("port"),
)
else: else:
xml += """ xml += """
<host name='%s'/>""" % host.get('name') <host name='%s'/>""" % host.get(
"name"
)
xml += """</source>""" xml += """</source>"""
else: else:
xml += """<disk type='file' device='%s'>""" % volume['device'] xml += """<disk type='file' device='%s'>""" % volume["device"]
xml += """ <driver name='qemu' type='%s' %s/>""" % (volume['type'], disk_opts) xml += """ <driver name='qemu' type='%s' %s/>""" % (volume["type"], disk_opts)
xml += f""" <source file='%s'/>""" % volume['path'] xml += """ <source file='%s'/>""" % volume["path"]
if volume.get('bus') == 'virtio': if volume.get("bus") == "virtio":
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume.get('bus')) xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume.get("bus"))
elif volume.get('bus') == 'ide': elif volume.get("bus") == "ide":
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), volume.get('bus')) xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), volume.get("bus"))
elif volume.get('bus') == 'fdc': elif volume.get("bus") == "fdc":
xml += """<target dev='fd%s' bus='%s'/>""" % (fd_disk_letters.pop(0), volume.get('bus')) xml += """<target dev='fd%s' bus='%s'/>""" % (fd_disk_letters.pop(0), volume.get("bus"))
elif volume.get('bus') == 'sata' or volume.get('bus') == 'scsi': elif volume.get("bus") == "sata" or volume.get("bus") == "scsi":
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume.get('bus')) xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume.get("bus"))
else: else:
xml += """<target dev='sd%s'/>""" % sd_disk_letters.pop(0) xml += """<target dev='sd%s'/>""" % sd_disk_letters.pop(0)
xml += """</disk>""" xml += """</disk>"""
if volume.get('bus') == 'scsi': if volume.get("bus") == "scsi":
xml += f"""<controller type='scsi' model='{volume.get('scsi_model')}'/>""" xml += f"""<controller type='scsi' model='{volume.get('scsi_model')}'/>"""
if add_cd: if add_cd:
@ -292,17 +328,17 @@ class wvmCreate(wvmConnect):
<driver name='qemu' type='raw'/> <driver name='qemu' type='raw'/>
<source file = '' /> <source file = '' />
<readonly/>""" <readonly/>"""
if 'ide' in dom_caps['disk_bus']: if "ide" in dom_caps["disk_bus"]:
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), 'ide') xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), "ide")
elif 'sata' in dom_caps['disk_bus']: elif "sata" in dom_caps["disk_bus"]:
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'sata') xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), "sata")
elif 'scsi' in dom_caps['disk_bus']: elif "scsi" in dom_caps["disk_bus"]:
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'scsi') xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), "scsi")
else: else:
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), 'virtio') xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), "virtio")
xml += """</disk>""" xml += """</disk>"""
for net in networks.split(','): for net in networks.split(","):
xml += """<interface type='network'>""" xml += """<interface type='network'>"""
if mac: if mac:
xml += f"""<mac address='{mac}'/>""" xml += f"""<mac address='{mac}'/>"""
@ -319,10 +355,10 @@ class wvmCreate(wvmConnect):
if not console_pass == "": if not console_pass == "":
console_pass = "passwd='" + console_pass + "'" console_pass = "passwd='" + console_pass + "'"
if 'usb' in dom_caps['disk_bus']: if "usb" in dom_caps["disk_bus"]:
xml += """<input type='mouse' bus='{}'/>""".format('virtio' if virtio else 'usb') xml += """<input type='mouse' bus='{}'/>""".format("virtio" if virtio else "usb")
xml += """<input type='keyboard' bus='{}'/>""".format('virtio' if virtio else 'usb') xml += """<input type='keyboard' bus='{}'/>""".format("virtio" if virtio else "usb")
xml += """<input type='tablet' bus='{}'/>""".format('virtio' if virtio else 'usb') xml += """<input type='tablet' bus='{}'/>""".format("virtio" if virtio else "usb")
else: else:
xml += """<input type='mouse'/>""" xml += """<input type='mouse'/>"""
xml += """<input type='keyboard'/>""" xml += """<input type='keyboard'/>"""

View file

@ -1,14 +1,15 @@
import time import time
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from vrtManager.util import get_xml_path from vrtManager.util import get_xml_path
def cpu_version(doc): def cpu_version(doc):
for info in doc.xpath('/sysinfo/processor/entry'): for info in doc.xpath("/sysinfo/processor/entry"):
elem = info.xpath('@name')[0] elem = info.xpath("@name")[0]
if elem == 'version': if elem == "version":
return info.text return info.text
return 'Unknown' return "Unknown"
class wvmHostDetails(wvmConnect): class wvmHostDetails(wvmConnect):
@ -19,14 +20,12 @@ class wvmHostDetails(wvmConnect):
all_mem = self.wvm.getInfo()[1] * 1048576 all_mem = self.wvm.getInfo()[1] * 1048576
freemem = self.wvm.getMemoryStats(-1, 0) freemem = self.wvm.getMemoryStats(-1, 0)
if isinstance(freemem, dict): if isinstance(freemem, dict):
free = (freemem['buffers'] + free = (freemem["buffers"] + freemem["free"] + freemem["cached"]) * 1024
freemem['free'] +
freemem['cached']) * 1024
percent = abs(100 - ((free * 100) // all_mem)) percent = abs(100 - ((free * 100) // all_mem))
usage = (all_mem - free) usage = all_mem - free
mem_usage = {'total': all_mem, 'usage': usage, 'percent': percent} mem_usage = {"total": all_mem, "usage": usage, "percent": percent}
else: else:
mem_usage = {'total': None, 'usage': None, 'percent': None} mem_usage = {"total": None, "usage": None, "percent": None}
return mem_usage return mem_usage
def get_cpu_usage(self): def get_cpu_usage(self):
@ -38,7 +37,7 @@ class wvmHostDetails(wvmConnect):
cpu = self.wvm.getCPUStats(-1, 0) cpu = self.wvm.getCPUStats(-1, 0)
if isinstance(cpu, dict): if isinstance(cpu, dict):
for num in range(2): for num in range(2):
idle = self.wvm.getCPUStats(-1, 0)['idle'] idle = self.wvm.getCPUStats(-1, 0)["idle"]
total = sum(self.wvm.getCPUStats(-1, 0).values()) total = sum(self.wvm.getCPUStats(-1, 0).values())
diff_idle = idle - prev_idle diff_idle = idle - prev_idle
diff_total = total - prev_total diff_total = total - prev_total
@ -51,8 +50,8 @@ class wvmHostDetails(wvmConnect):
if diff_usage < 0: if diff_usage < 0:
diff_usage = 0 diff_usage = 0
else: else:
return {'usage': None} return {"usage": None}
return {'usage': diff_usage} return {"usage": diff_usage}
def get_node_info(self): def get_node_info(self):
""" """

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
from xml.etree import ElementTree from xml.etree import ElementTree
from libvirt import VIR_INTERFACE_XML_INACTIVE
from vrtManager.connection import wvmConnect
from vrtManager import util
from libvirt import VIR_INTERFACE_XML_INACTIVE
from vrtManager import util
from vrtManager.connection import wvmConnect
class wvmInterfaces(wvmConnect): class wvmInterfaces(wvmConnect):
@ -12,36 +12,37 @@ class wvmInterfaces(wvmConnect):
mac = iface.MACString() mac = iface.MACString()
itype = util.get_xml_path(xml, "/interface/@type") itype = util.get_xml_path(xml, "/interface/@type")
state = iface.isActive() state = iface.isActive()
return {'name': name, 'type': itype, 'state': state, 'mac': mac} return {"name": name, "type": itype, "state": state, "mac": mac}
def define_iface(self, xml, flag=0): def define_iface(self, xml, flag=0):
self.wvm.interfaceDefineXML(xml, flag) self.wvm.interfaceDefineXML(xml, flag)
def create_iface(self, name, itype, mode, netdev, ipv4_type, ipv4_addr, ipv4_gw, def create_iface(
ipv6_type, ipv6_addr, ipv6_gw, stp, delay): self, name, itype, mode, netdev, ipv4_type, ipv4_addr, ipv4_gw, ipv6_type, ipv6_addr, ipv6_gw, stp, delay
):
xml = f"""<interface type='{itype}' name='{name}'> xml = f"""<interface type='{itype}' name='{name}'>
<start mode='{mode}'/>""" <start mode='{mode}'/>"""
if ipv4_type == 'dhcp': if ipv4_type == "dhcp":
xml += """<protocol family='ipv4'> xml += """<protocol family='ipv4'>
<dhcp/> <dhcp/>
</protocol>""" </protocol>"""
if ipv4_type == 'static': if ipv4_type == "static":
address, prefix = ipv4_addr.split('/') address, prefix = ipv4_addr.split("/")
xml += f"""<protocol family='ipv4'> xml += f"""<protocol family='ipv4'>
<ip address='{address}' prefix='{prefix}'/> <ip address='{address}' prefix='{prefix}'/>
<route gateway='{ipv4_gw}'/> <route gateway='{ipv4_gw}'/>
</protocol>""" </protocol>"""
if ipv6_type == 'dhcp': if ipv6_type == "dhcp":
xml += """<protocol family='ipv6'> xml += """<protocol family='ipv6'>
<dhcp/> <dhcp/>
</protocol>""" </protocol>"""
if ipv6_type == 'static': if ipv6_type == "static":
address, prefix = ipv6_addr.split('/') address, prefix = ipv6_addr.split("/")
xml += f"""<protocol family='ipv6'> xml += f"""<protocol family='ipv6'>
<ip address='{address}' prefix='{prefix}'/> <ip address='{address}' prefix='{prefix}'/>
<route gateway='{ipv6_gw}'/> <route gateway='{ipv6_gw}'/>
</protocol>""" </protocol>"""
if itype == 'bridge': if itype == "bridge":
xml += f"""<bridge stp='{stp}' delay='{delay}'> xml += f"""<bridge stp='{stp}' delay='{delay}'>
<interface name='{netdev}' type='ethernet'/> <interface name='{netdev}' type='ethernet'/>
</bridge>""" </bridge>"""
@ -85,9 +86,9 @@ class wvmInterface(wvmConnect):
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE) xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv4']/ip/@address") ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv4']/ip/@address")
if ipaddr: if ipaddr:
return 'static' return "static"
else: else:
return 'dhcp' return "dhcp"
except: except:
return None return None
@ -98,16 +99,16 @@ class wvmInterface(wvmConnect):
if not int_ipv4_ip or not int_ipv4_mask: if not int_ipv4_ip or not int_ipv4_mask:
return None return None
else: else:
return int_ipv4_ip + '/' + int_ipv4_mask return int_ipv4_ip + "/" + int_ipv4_mask
def get_ipv6_type(self): def get_ipv6_type(self):
try: try:
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE) xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv6']/ip/@address") ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv6']/ip/@address")
if ipaddr: if ipaddr:
return 'static' return "static"
else: else:
return 'dhcp' return "dhcp"
except: except:
return None return None
@ -118,15 +119,15 @@ class wvmInterface(wvmConnect):
if not int_ipv6_ip or not int_ipv6_mask: if not int_ipv6_ip or not int_ipv6_mask:
return None return None
else: else:
return int_ipv6_ip + '/' + int_ipv6_mask return int_ipv6_ip + "/" + int_ipv6_mask
def get_bridge(self): def get_bridge(self):
bridge = None bridge = None
if self.get_type() == 'bridge': if self.get_type() == "bridge":
bridge = util.get_xml_path(self._XMLDesc(), "/interface/bridge/interface/@name") bridge = util.get_xml_path(self._XMLDesc(), "/interface/bridge/interface/@name")
for iface in self.get_bridge_slave_ifaces(): for iface in self.get_bridge_slave_ifaces():
if iface.get('state') == 'up' and iface.get('speed') is not 'unknown': if iface.get("state") == "up" and iface.get("speed") != "unknown":
bridge = iface.get('name') bridge = iface.get("name")
return bridge return bridge
return bridge return bridge
else: else:
@ -134,20 +135,20 @@ class wvmInterface(wvmConnect):
def get_bridge_slave_ifaces(self): def get_bridge_slave_ifaces(self):
ifaces = list() ifaces = list()
if self.get_type() == 'bridge': if self.get_type() == "bridge":
tree = ElementTree.fromstring(self._XMLDesc()) tree = ElementTree.fromstring(self._XMLDesc())
for iface in tree.findall("./bridge/"): for iface in tree.findall("./bridge/"):
address = state = speed = None address = state = speed = None
name = iface.get('name') name = iface.get("name")
if_type = iface.get('type') if_type = iface.get("type")
link = iface.find('link') link = iface.find("link")
if link is not None: if link is not None:
state = link.get('state') state = link.get("state")
speed = link.get('speed') speed = link.get("speed")
mac = iface.find('mac') mac = iface.find("mac")
if mac is not None: if mac is not None:
address = mac.get('address') address = mac.get("address")
ifaces.append({'name': name, 'type': if_type, 'state': state, 'speed': speed, 'mac': address}) ifaces.append({"name": name, "type": if_type, "state": state, "speed": speed, "mac": address})
return ifaces return ifaces
else: else:
return None return None

View file

@ -1,11 +1,15 @@
from libvirt import (
VIR_NETWORK_SECTION_IP_DHCP_HOST,
VIR_NETWORK_UPDATE_AFFECT_CONFIG,
VIR_NETWORK_UPDATE_AFFECT_LIVE,
VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
VIR_NETWORK_UPDATE_COMMAND_DELETE,
VIR_NETWORK_UPDATE_COMMAND_MODIFY, libvirtError)
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_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 vrtManager import util from vrtManager import util
from vrtManager.IPy import IP
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from vrtManager.IPy import IP
def network_size(subnet, dhcp=None): def network_size(subnet, dhcp=None):
""" """
@ -17,7 +21,7 @@ def network_size(subnet, dhcp=None):
if addr.version() == 4: if addr.version() == 4:
dhcp_pool = [addr[2].strCompressed(), addr[addr.len() - 2].strCompressed()] dhcp_pool = [addr[2].strCompressed(), addr[addr.len() - 2].strCompressed()]
if addr.version() == 6: if addr.version() == 6:
mask = mask.lstrip('/') if '/' in mask else mask mask = mask.lstrip("/") if "/" in mask else mask
dhcp_pool = [IP(addr[0].strCompressed() + hex(256)), IP(addr[0].strCompressed() + hex(512 - 1))] dhcp_pool = [IP(addr[0].strCompressed() + hex(256)), IP(addr[0].strCompressed() + hex(512 - 1))]
if dhcp: if dhcp:
return gateway, mask, dhcp_pool return gateway, mask, dhcp_pool
@ -26,7 +30,6 @@ def network_size(subnet, dhcp=None):
class wvmNetworks(wvmConnect): class wvmNetworks(wvmConnect):
def get_networks_info(self): def get_networks_info(self):
get_networks = self.get_networks() get_networks = self.get_networks()
networks = [] networks = []
@ -39,44 +42,55 @@ class wvmNetworks(wvmConnect):
net_bridge = util.get_xml_path(net.XMLDesc(0), "/network/forward/interface/@dev") 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})
return networks return networks
def define_network(self, xml): def define_network(self, xml):
self.wvm.networkDefineXML(xml) self.wvm.networkDefineXML(xml)
def create_network(self, name, forward, def create_network(
ipv4, gateway, mask, dhcp4, self,
ipv6, gateway6, prefix6, dhcp6, name,
bridge, openvswitch, fixed=False): forward,
ipv4,
gateway,
mask,
dhcp4,
ipv6,
gateway6,
prefix6,
dhcp6,
bridge,
openvswitch,
fixed=False,
):
xml = f""" xml = f"""
<network> <network>
<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}'/>"""
if forward == 'macvtap': if forward == "macvtap":
xml += f"""<forward mode='bridge'> xml += f"""<forward mode='bridge'>
<interface dev='{bridge}'/> <interface dev='{bridge}'/>
</forward>""" </forward>"""
else: else:
xml += """<bridge """ xml += """<bridge """
if forward in ['nat', 'route', 'none']: if forward in ["nat", "route", "none"]:
xml += """stp='on' delay='0'""" xml += """stp='on' delay='0'"""
if forward == 'bridge': if forward == "bridge":
xml += f"""name='{bridge}'""" xml += f"""name='{bridge}'"""
xml += """/>""" xml += """/>"""
if openvswitch is True: if openvswitch is True:
xml += """<virtualport type='openvswitch'/>""" xml += """<virtualport type='openvswitch'/>"""
if forward not in ['bridge', 'macvtap']: 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:
xml += f"""<dhcp> xml += f"""<dhcp>
<range start='{dhcp4[0]}' end='{dhcp4[1]}' />""" <range start='{dhcp4[0]}' end='{dhcp4[1]}' />"""
if fixed: if fixed:
fist_oct = int(dhcp4[0].strip().split('.')[3]) fist_oct = int(dhcp4[0].strip().split(".")[3])
last_oct = int(dhcp4[1].strip().split('.')[3]) last_oct = int(dhcp4[1].strip().split(".")[3])
for ip in range(fist_oct, last_oct + 1): for ip in range(fist_oct, last_oct + 1):
xml += f"""<host mac='{util.randomMAC()}' ip='{gateway[:-2]}.{ip}' />""" xml += f"""<host mac='{util.randomMAC()}' ip='{gateway[:-2]}.{ip}' />"""
xml += """</dhcp>""" xml += """</dhcp>"""
@ -144,23 +158,23 @@ class wvmNetwork(wvmConnect):
if util.get_xml_path(xml, "/network/ip") is None: if util.get_xml_path(xml, "/network/ip") is None:
return ip_networks return ip_networks
tree = etree.fromstring(xml) tree = etree.fromstring(xml)
ips = tree.findall('.ip') ips = tree.findall(".ip")
for ip in ips: for ip in ips:
address_str = ip.get('address') address_str = ip.get("address")
netmask_str = ip.get('netmask') netmask_str = ip.get("netmask")
prefix = ip.get('prefix') prefix = ip.get("prefix")
family = ip.get('family', 'ipv4') family = ip.get("family", "ipv4")
base = 32 if family == 'ipv4' else 128 base = 32 if family == "ipv4" else 128
if prefix: if prefix:
prefix = int(prefix) prefix = int(prefix)
binstr = ((prefix * "1") + ((base - prefix) * "0")) binstr = (prefix * "1") + ((base - prefix) * "0")
netmask_str = str(IP(int(binstr, base=2))) netmask_str = str(IP(int(binstr, base=2)))
if netmask_str: if netmask_str:
netmask = IP(netmask_str) netmask = IP(netmask_str)
gateway = IP(address_str) gateway = IP(address_str)
network = IP(gateway.int() & netmask.int()) network = IP(gateway.int() & netmask.int())
netmask_str = netmask_str if family == 'ipv4' else str(prefix) netmask_str = netmask_str if family == "ipv4" else str(prefix)
ret = IP(str(network) + "/" + netmask_str) ret = IP(str(network) + "/" + netmask_str)
else: else:
ret = IP(str(address_str)) ret = IP(str(address_str))
@ -178,12 +192,12 @@ class wvmNetwork(wvmConnect):
forward_dev = util.get_xml_path(xml, "/network/forward/@dev") forward_dev = util.get_xml_path(xml, "/network/forward/@dev")
return [fw, forward_dev] return [fw, forward_dev]
def get_dhcp_range(self, family='ipv4'): def get_dhcp_range(self, family="ipv4"):
xml = self._XMLDesc(0) xml = self._XMLDesc(0)
if family == 'ipv4': if family == "ipv4":
dhcpstart = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@start") 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") dhcpend = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@end")
if family == 'ipv6': if family == "ipv6":
dhcpstart = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@start") 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") dhcpend = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@end")
@ -192,13 +206,13 @@ class wvmNetwork(wvmConnect):
return [IP(dhcpstart), IP(dhcpend)] return [IP(dhcpstart), IP(dhcpend)]
def get_dhcp_range_start(self, family='ipv4'): def get_dhcp_range_start(self, family="ipv4"):
dhcp = self.get_dhcp_range(family) dhcp = self.get_dhcp_range(family)
if not dhcp: if not dhcp:
return None return None
return dhcp[0] return dhcp[0]
def get_dhcp_range_end(self, family='ipv4'): def get_dhcp_range_end(self, family="ipv4"):
dhcp = self.get_dhcp_range(family) dhcp = self.get_dhcp_range(family)
if not dhcp: if not dhcp:
return None return None
@ -211,74 +225,77 @@ class wvmNetwork(wvmConnect):
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_dhcp_host_addr(self, family='ipv4'): def get_dhcp_host_addr(self, family="ipv4"):
result = list() result = list()
tree = etree.fromstring(self._XMLDesc(0)) tree = etree.fromstring(self._XMLDesc(0))
for ipdhcp in tree.findall("./ip"): for ipdhcp in tree.findall("./ip"):
if family == 'ipv4': if family == "ipv4":
if ipdhcp.get('family') is None: if ipdhcp.get("family") is None:
hosts = ipdhcp.findall('./dhcp/host') hosts = ipdhcp.findall("./dhcp/host")
for host in hosts: for host in hosts:
host_ip = host.get('ip') host_ip = host.get("ip")
mac = host.get('mac') mac = host.get("mac")
name = host.get('name', '') name = host.get("name", "")
result.append({'ip': host_ip, 'mac': mac, 'name': name}) result.append({"ip": host_ip, "mac": mac, "name": name})
return result return result
else: else:
continue continue
if family == 'ipv6': if family == "ipv6":
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host") hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
for host in hosts: for host in hosts:
host_ip = host.get('ip') host_ip = host.get("ip")
host_id = host.get('id') host_id = host.get("id")
name = host.get('name', '') name = host.get("name", "")
result.append({'ip': host_ip, 'id': host_id, 'name': name}) result.append({"ip": host_ip, "id": host_id, "name": name})
return result return result
def modify_dhcp_range(self, range_start, range_end, family='ipv4'): def modify_dhcp_range(self, range_start, range_end, family="ipv4"):
if not self.is_active(): if not self.is_active():
tree = etree.fromstring(self._XMLDesc(0)) tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4': if family == "ipv4":
dhcp_range = tree.xpath("./ip[not(@family='ipv6')]/dhcp/range") dhcp_range = tree.xpath("./ip[not(@family='ipv6')]/dhcp/range")
if family == 'ipv6': if family == "ipv6":
dhcp_range = tree.xpath("./ip[@family='ipv6']/dhcp/range") dhcp_range = tree.xpath("./ip[@family='ipv6']/dhcp/range")
dhcp_range[0].set('start', range_start) dhcp_range[0].set("start", range_start)
dhcp_range[0].set('end', range_end) dhcp_range[0].set("end", range_end)
self.wvm.networkDefineXML(etree.tostring(tree).decode()) self.wvm.networkDefineXML(etree.tostring(tree).decode())
def delete_fixed_address(self, ip, family='ipv4'): def delete_fixed_address(self, ip, family="ipv4"):
tree = etree.fromstring(self._XMLDesc(0)) tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4': if family == "ipv4":
hosts = tree.xpath("/network/ip[not(@family='ipv6')]/dhcp/host") hosts = tree.xpath("/network/ip[not(@family='ipv6')]/dhcp/host")
parent_index = self.parent_count - 2 parent_index = self.parent_count - 2
if family == 'ipv6': if family == "ipv6":
hosts = tree.xpath("/network/ip[@family='ipv6']/dhcp/host") hosts = tree.xpath("/network/ip[@family='ipv6']/dhcp/host")
parent_index = self.parent_count - 1 parent_index = self.parent_count - 1
for h in hosts: for h in hosts:
if h.get('ip') == ip: if h.get("ip") == ip:
if family == 'ipv4': if family == "ipv4":
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get('mac'), h.get('name'), ip) new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get("mac"), h.get("name"), ip)
if family == 'ipv6': if family == "ipv6":
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get('id'), h.get('name'), ip) 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, self.update(
VIR_NETWORK_UPDATE_COMMAND_DELETE,
VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml, new_xml,
parent_index, parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG) VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
)
break break
def modify_fixed_address(self, name, address, mac_duid, family='ipv4'): def modify_fixed_address(self, name, address, mac_duid, family="ipv4"):
tree = etree.fromstring(self._XMLDesc(0)) tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4': if family == "ipv4":
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address)) new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
hosts = tree.xpath("./ip[not(@family='ipv6')]/dhcp/host") hosts = tree.xpath("./ip[not(@family='ipv6')]/dhcp/host")
compare_var = 'mac' compare_var = "mac"
parent_index = self.parent_count - 2 parent_index = self.parent_count - 2
if family == 'ipv6': if family == "ipv6":
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address)) new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host") hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
compare_var = 'id' compare_var = "id"
parent_index = self.parent_count - 1 parent_index = self.parent_count - 1
new_host_xml = etree.fromstring(new_xml) new_host_xml = etree.fromstring(new_xml)
@ -288,17 +305,25 @@ class wvmNetwork(wvmConnect):
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, new_xml, self.update(
VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml,
parent_index, 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, new_xml, self.update(
VIR_NETWORK_UPDATE_COMMAND_MODIFY,
VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml,
parent_index, parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG) VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
)
def get_qos(self): def get_qos(self):
qos_values = dict() qos_values = dict()
@ -307,19 +332,19 @@ class wvmNetwork(wvmConnect):
if qos: if qos:
qos = qos[0] qos = qos[0]
in_qos = qos.find('inbound') in_qos = qos.find("inbound")
if in_qos is not None: if in_qos is not None:
in_av = in_qos.get('average') in_av = in_qos.get("average")
in_peak = in_qos.get('peak') in_peak = in_qos.get("peak")
in_burst = in_qos.get('burst') in_burst = in_qos.get("burst")
qos_values['inbound'] = {'average': in_av, 'peak': in_peak, 'burst': in_burst} qos_values["inbound"] = {"average": in_av, "peak": in_peak, "burst": in_burst}
out_qos = qos.find('outbound') out_qos = qos.find("outbound")
if out_qos is not None: if out_qos is not None:
out_av = out_qos.get('average') out_av = out_qos.get("average")
out_peak = out_qos.get('peak') out_peak = out_qos.get("peak")
out_burst = out_qos.get('burst') out_burst = out_qos.get("burst")
qos_values['outbound'] = {'average': out_av, 'peak': out_peak, 'burst': out_burst} qos_values["outbound"] = {"average": out_av, "peak": out_peak, "burst": out_burst}
return qos_values return qos_values
def set_qos(self, direction, average, peak, burst): def set_qos(self, direction, average, peak, burst):
@ -328,7 +353,7 @@ class wvmNetwork(wvmConnect):
elif direction == "outbound": elif direction == "outbound":
xml = f"<outbound average='{average}' peak='{peak}' burst='{burst}'/>" xml = f"<outbound average='{average}' peak='{peak}' burst='{burst}'/>"
else: else:
raise Exception('Direction must be inbound or outbound') raise Exception("Direction must be inbound or outbound")
tree = etree.fromstring(self._XMLDesc(0)) tree = etree.fromstring(self._XMLDesc(0))
@ -363,7 +388,7 @@ class wvmNetwork(wvmConnect):
self.leases = self.net.DHCPLeases() self.leases = self.net.DHCPLeases()
except Exception as e: except Exception as e:
self.leases = [] self.leases = []
raise f"Error getting {self} DHCP leases: {e}" raise "Error getting {} DHCP leases: {}".format(self, e)
def get_dhcp_leases(self): def get_dhcp_leases(self):
if self.leases is None: if self.leases is None:

View file

@ -1,4 +1,5 @@
from xml.etree import ElementTree from xml.etree import ElementTree
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
@ -7,7 +8,7 @@ class wvmNWFilters(wvmConnect):
nwfilter = self.get_nwfilter(name) nwfilter = self.get_nwfilter(name)
xml = nwfilter.XMLDesc(0) xml = nwfilter.XMLDesc(0)
uuid = nwfilter.UUIDString() uuid = nwfilter.UUIDString()
return {'name': name, 'uuid': uuid, 'xml': xml} return {"name": name, "uuid": uuid, "xml": xml}
def create_nwfilter(self, xml): def create_nwfilter(self, xml):
self.wvm.nwfilterDefineXML(xml) self.wvm.nwfilterDefineXML(xml)
@ -16,8 +17,8 @@ class wvmNWFilters(wvmConnect):
nwfilter = self.get_nwfilter(name) nwfilter = self.get_nwfilter(name)
if nwfilter: if nwfilter:
tree = ElementTree.fromstring(nwfilter.XMLDesc(0)) tree = ElementTree.fromstring(nwfilter.XMLDesc(0))
tree.set('name', cln_name) tree.set("name", cln_name)
uuid = tree.find('uuid') uuid = tree.find("uuid")
tree.remove(uuid) tree.remove(uuid)
self.create_nwfilter(ElementTree.tostring(tree).decode()) self.create_nwfilter(ElementTree.tostring(tree).decode())
@ -41,7 +42,7 @@ class wvmNWFilter(wvmConnect):
def get_xml(self): def get_xml(self):
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
uuid = tree.find('uuid') uuid = tree.find("uuid")
tree.remove(uuid) tree.remove(uuid)
return ElementTree.tostring(tree).decode() return ElementTree.tostring(tree).decode()
@ -49,7 +50,7 @@ class wvmNWFilter(wvmConnect):
refs = [] refs = []
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
for ref in tree.findall("./filterref"): for ref in tree.findall("./filterref"):
refs.append(ref.get('filter')) refs.append(ref.get("filter"))
return refs return refs
def get_rules(self): def get_rules(self):
@ -57,10 +58,10 @@ class wvmNWFilter(wvmConnect):
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
for r in tree.findall("./rule"): for r in tree.findall("./rule"):
rule_action = r.get('action') rule_action = r.get("action")
rule_direction = r.get('direction') rule_direction = r.get("direction")
rule_priority = r.get('priority') rule_priority = r.get("priority")
rule_statematch = r.get('statematch') rule_statematch = r.get("statematch")
rule_directives = r.find("./") rule_directives = r.find("./")
if rule_directives is not None: if rule_directives is not None:
@ -71,7 +72,7 @@ class wvmNWFilter(wvmConnect):
"direction": rule_direction, "direction": rule_direction,
"priority": rule_priority, "priority": rule_priority,
"statematch": rule_statematch, "statematch": rule_statematch,
"directives": rule_directives "directives": rule_directives,
} }
rules.append(rule_info) rules.append(rule_info)
@ -81,7 +82,7 @@ class wvmNWFilter(wvmConnect):
def delete_ref(self, name): def delete_ref(self, name):
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
for ref in tree.findall("./filterref"): for ref in tree.findall("./filterref"):
if name == ref.get('filter'): if name == ref.get("filter"):
tree.remove(ref) tree.remove(ref)
break break
return ElementTree.tostring(tree).decode() return ElementTree.tostring(tree).decode()
@ -89,7 +90,9 @@ class wvmNWFilter(wvmConnect):
def delete_rule(self, action, direction, priority): def delete_rule(self, action, direction, priority):
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
rule_tree = tree.findall("./rule[@action='%s'][@direction='%s'][@priority='%s']" % (action, direction, priority)) rule_tree = tree.findall(
"./rule[@action='%s'][@direction='%s'][@priority='%s']" % (action, direction, priority)
)
if rule_tree: if rule_tree:
tree.remove(rule_tree[0]) tree.remove(rule_tree[0])
@ -98,7 +101,7 @@ class wvmNWFilter(wvmConnect):
def add_ref(self, name): def add_ref(self, name):
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
element = ElementTree.Element("filterref") element = ElementTree.Element("filterref")
element.attrib['filter'] = name element.attrib["filter"] = name
tree.append(element) tree.append(element)
return ElementTree.tostring(tree).decode() return ElementTree.tostring(tree).decode()
@ -106,19 +109,21 @@ class wvmNWFilter(wvmConnect):
tree = ElementTree.fromstring(self._XMLDesc(0)) tree = ElementTree.fromstring(self._XMLDesc(0))
rule = ElementTree.fromstring(xml) rule = ElementTree.fromstring(xml)
rule_action = rule.get('action') rule_action = rule.get("action")
rule_direction = rule.get('direction') rule_direction = rule.get("direction")
rule_priority = rule.get('priority') rule_priority = rule.get("priority")
rule_directives = rule.find("./") rule_directives = rule.find("./")
rule_tree = tree.findall("./rule[@action='%s'][@direction='%s'][@priority='%s']" % (rule_action, rule_direction, rule_priority)) rule_tree = tree.findall(
"./rule[@action='%s'][@direction='%s'][@priority='%s']" % (rule_action, rule_direction, rule_priority)
)
if rule_tree: if rule_tree:
rule_tree[0].append(rule_directives) rule_tree[0].append(rule_directives)
else: else:
element = ElementTree.Element("rule") element = ElementTree.Element("rule")
element.attrib['action'] = rule_action element.attrib["action"] = rule_action
element.attrib['direction'] = rule_direction element.attrib["direction"] = rule_direction
element.attrib['priority'] = rule_priority element.attrib["priority"] = rule_priority
element.append(rule_directives) element.append(rule_directives)
tree.append(element) tree.append(element)

View file

@ -11,11 +11,9 @@ found at: http://code.activestate.com/recipes/502283-read-write-lock-class-rlock
# Imports # Imports
# ------- # -------
from threading import Condition, Lock, currentThread from threading import Condition, Lock, currentThread
from time import time from time import time
# Read write lock # Read write lock
# --------------- # ---------------
@ -138,9 +136,7 @@ class ReadWriteLock(object):
# else also wants to upgrade, there is no way we can do # else also wants to upgrade, there is no way we can do
# this except if one of us releases all his read locks. # this except if one of us releases all his read locks.
# Signal this to user. # Signal this to user.
raise ValueError( raise ValueError("Inevitable dead lock, denying write lock")
"Inevitable dead lock, denying write lock"
)
upgradewriter = True upgradewriter = True
self.__upgradewritercount = self.__readers.pop(me) self.__upgradewritercount = self.__readers.pop(me)
else: else:

View file

@ -1,4 +1,5 @@
import base64 import base64
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
@ -6,11 +7,11 @@ class wvmSecrets(wvmConnect):
def create_secret(self, ephemeral, private, secret_type, data): def create_secret(self, ephemeral, private, secret_type, data):
xml = f"""<secret ephemeral='{ephemeral}' private='{private}'> xml = f"""<secret ephemeral='{ephemeral}' private='{private}'>
<usage type='{secret_type}'>""" <usage type='{secret_type}'>"""
if secret_type == 'ceph': if secret_type == "ceph":
xml += f"""<name>{data}</name>""" xml += f"""<name>{data}</name>"""
if secret_type == 'volume': if secret_type == "volume":
xml += f"""<volume>{data}</volume>""" xml += f"""<volume>{data}</volume>"""
if secret_type == 'iscsi': if secret_type == "iscsi":
xml += f"""<target>{data}</target>""" xml += f"""<target>{data}</target>"""
xml += """</usage> xml += """</usage>
</secret>""" </secret>"""

View file

@ -16,13 +16,7 @@ class wvmStorages(wvmConnect):
stg_vol = None stg_vol = None
stg_size = stg.info()[1] stg_size = stg.info()[1]
storages.append( storages.append(
{ {"name": pool, "status": stg_status, "type": stg_type, "volumes": stg_vol, "size": stg_size}
"name": pool,
"status": stg_status,
"type": stg_type,
"volumes": stg_vol,
"size": stg_size
}
) )
return storages return storages
@ -103,12 +97,7 @@ class wvmStorage(wvmConnect):
return self.pool.name() return self.pool.name()
def get_status(self): def get_status(self):
status = [ status = ["Not running", "Initializing pool, not available", "Running normally", "Running degraded"]
"Not running",
"Initializing pool, not available",
"Running normally",
"Running degraded"
]
try: try:
return status[self.pool.info()[0]] return status[self.pool.info()[0]]
except ValueError: except ValueError:
@ -217,12 +206,12 @@ class wvmStorage(wvmConnect):
"name": volname, "name": volname,
"size": self.get_volume_size(volname), "size": self.get_volume_size(volname),
"allocation": self.get_volume_allocation(volname), "allocation": self.get_volume_allocation(volname),
"type": self.get_volume_type(volname) "type": self.get_volume_type(volname),
} }
) )
return vol_list return vol_list
def create_volume(self, name, size, vol_fmt='qcow2', metadata=False, disk_owner_uid=0, disk_owner_gid=0): def create_volume(self, name, size, vol_fmt="qcow2", metadata=False, disk_owner_uid=0, disk_owner_gid=0):
size = int(size) * 1073741824 size = int(size) * 1073741824
storage_type = self.get_type() storage_type = self.get_type()
alloc = size alloc = size
@ -258,7 +247,17 @@ class wvmStorage(wvmConnect):
self._createXML(xml, metadata) self._createXML(xml, metadata)
return name return name
def clone_volume(self, name, target_file, vol_fmt=None, metadata=False, mode='0644', file_suffix='img', disk_owner_uid=0, disk_owner_gid=0): def clone_volume(
self,
name,
target_file,
vol_fmt=None,
metadata=False,
mode="0644",
file_suffix="img",
disk_owner_uid=0,
disk_owner_gid=0,
):
vol = self.get_volume(name) vol = self.get_volume(name)
if not vol_fmt: if not vol_fmt:
vol_fmt = self.get_volume_type(name) vol_fmt = self.get_volume_type(name)
@ -266,10 +265,10 @@ class wvmStorage(wvmConnect):
storage_type = self.get_type() storage_type = self.get_type()
if storage_type == "dir": if storage_type == "dir":
if vol_fmt in ["qcow", "qcow2"]: if vol_fmt in ["qcow", "qcow2"]:
target_file += '.' + vol_fmt target_file += "." + vol_fmt
else: else:
suffix = '.' + file_suffix suffix = "." + file_suffix
target_file += suffix if len(suffix) > 1 else '' target_file += suffix if len(suffix) > 1 else ""
xml = f""" xml = f"""
<volume> <volume>

View file

@ -1,8 +1,9 @@
import random import random
import string
import re import re
import lxml.etree as etree import string
import libvirt import libvirt
import lxml.etree as etree
def is_kvm_available(xml): def is_kvm_available(xml):
@ -18,10 +19,8 @@ def randomMAC():
# qemu MAC # qemu MAC
oui = [0x52, 0x54, 0x00] oui = [0x52, 0x54, 0x00]
mac = oui + [random.randint(0x00, 0xff), mac = oui + [random.randint(0x00, 0xFF), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]
random.randint(0x00, 0xff), return ":".join(map(lambda x: "%02x" % x, mac))
random.randint(0x00, 0xff)]
return ':'.join(map(lambda x: "%02x" % x, mac))
def randomUUID(): def randomUUID():
@ -29,13 +28,12 @@ def randomUUID():
u = [random.randint(0, 255) for ignore in range(0, 16)] u = [random.randint(0, 255) for ignore in range(0, 16)]
u[6] = (u[6] & 0x0F) | (4 << 4) u[6] = (u[6] & 0x0F) | (4 << 4)
u[8] = (u[8] & 0x3F) | (2 << 6) u[8] = (u[8] & 0x3F) | (2 << 6)
return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2, return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2, "%02x" * 6]) % tuple(u)
"%02x" * 6]) % tuple(u)
def randomPasswd(length=12, alphabet=string.ascii_letters + string.digits): def randomPasswd(length=12, alphabet=string.ascii_letters + string.digits):
"""Generate a random password""" """Generate a random password"""
return ''.join([random.choice(alphabet) for i in range(length)]) return "".join([random.choice(alphabet) for i in range(length)])
def get_max_vcpus(conn, type=None): def get_max_vcpus(conn, type=None):
@ -57,7 +55,7 @@ def xml_escape(str):
str = str.replace("&", "&amp;") str = str.replace("&", "&amp;")
str = str.replace("'", "&apos;") str = str.replace("'", "&apos;")
str = str.replace("\"", "&quot;") str = str.replace('"', "&quot;")
str = str.replace("<", "&lt;") str = str.replace("<", "&lt;")
str = str.replace(">", "&gt;") str = str.replace(">", "&gt;")
return str return str
@ -109,7 +107,7 @@ def get_xpath(doc, path):
if ret is not None: if ret is not None:
if isinstance(ret, list): if isinstance(ret, list):
if len(ret) >= 1: if len(ret) >= 1:
if hasattr(ret[0], 'text'): if hasattr(ret[0], "text"):
result = ret[0].text result = ret[0].text
else: else:
result = ret[0] result = ret[0]
@ -146,11 +144,11 @@ def validate_uuid(val):
raise ValueError( raise ValueError(
"UUID must be a 32-digit hexadecimal number. It may take " "UUID must be a 32-digit hexadecimal number. It may take "
"the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or may " "the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or may "
"omit hyphens altogether.") "omit hyphens altogether."
)
else: # UUID had no dashes, so add them in else: # UUID had no dashes, so add them in
val = (val[0:8] + "-" + val[8:12] + "-" + val[12:16] + val = val[0:8] + "-" + val[8:12] + "-" + val[12:16] + "-" + val[16:20] + "-" + val[20:32]
"-" + val[16:20] + "-" + val[20:32])
return val return val
@ -163,7 +161,7 @@ def validate_macaddr(val):
form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val) form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val)
if form is None: if form is None:
raise ValueError(f"MAC address must be of the format AA:BB:CC:DD:EE:FF, was {val}") raise ValueError("MAC address must be of the format AA:BB:CC:DD:EE:FF, was {}".format(val))
# Mapping of UEFI binary names to their associated architectures. We # Mapping of UEFI binary names to their associated architectures. We
@ -177,7 +175,8 @@ UEFI_ARCH_PATTERNS = {
r".*OVMF_CODE\.fd", # RHEL r".*OVMF_CODE\.fd", # RHEL
r".*ovmf-x64/OVMF.*\.fd", # gerd's firmware repo r".*ovmf-x64/OVMF.*\.fd", # gerd's firmware repo
r".*ovmf-x86_64-.*", # SUSE r".*ovmf-x86_64-.*", # SUSE
r".*ovmf.*", ".*OVMF.*", # generic attempt at a catchall r".*ovmf.*",
".*OVMF.*", # generic attempt at a catchall
], ],
"aarch64": [ "aarch64": [
r".*AAVMF_CODE\.fd", # RHEL r".*AAVMF_CODE\.fd", # RHEL

View file

@ -1,29 +1,30 @@
from django import template
import re import re
from django import template
register = template.Library() register = template.Library()
@register.simple_tag @register.simple_tag
def app_active(request, app_name): def app_active(request, app_name):
if request.resolver_match.app_name == app_name: if request.resolver_match.app_name == app_name:
return 'active' return "active"
return '' return ""
@register.simple_tag @register.simple_tag
def view_active(request, view_name): def view_active(request, view_name):
if request.resolver_match.view_name == view_name: if request.resolver_match.view_name == view_name:
return 'active' return "active"
return '' return ""
@register.simple_tag @register.simple_tag
def class_active(request, pattern): def class_active(request, pattern):
if re.search(pattern, request.path): if re.search(pattern, request.path):
# Not sure why 'class="active"' returns class=""active"" # Not sure why 'class="active"' returns class=""active""
return 'active' return "active"
return '' return ""
@register.simple_tag @register.simple_tag

View file

@ -15,7 +15,7 @@ class ExceptionMiddleware:
if isinstance(exception, libvirtError): if isinstance(exception, libvirtError):
messages.error( messages.error(
request, request,
_('libvirt Error - %(exception)s') % {'exception': exception}, _("libvirt Error - %(exception)s") % {"exception": exception},
) )
return render(request, '500.html', status=500) return render(request, "500.html", status=500)
# TODO: check connecting to host via VPN # TODO: check connecting to host via VPN

View file

@ -20,9 +20,7 @@ MIDDLEWARE += [
] ]
# DebugToolBar # DebugToolBar
INTERNAL_IPS = ( INTERNAL_IPS = ("127.0.0.1",)
"127.0.0.1",
)
DEBUG_TOOLBAR_CONFIG = { DEBUG_TOOLBAR_CONFIG = {
"INTERCEPT_REDIRECTS": False, "INTERCEPT_REDIRECTS": False,
} }

View file

@ -8,102 +8,102 @@ import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = '' SECRET_KEY = ""
DEBUG = False DEBUG = False
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ["*"]
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.staticfiles', "django.contrib.staticfiles",
'bootstrap4', "bootstrap4",
'django_icons', "django_icons",
'django_otp', "django_otp",
'django_otp.plugins.otp_totp', "django_otp.plugins.otp_totp",
'accounts', "accounts",
'admin', "admin",
'appsettings', "appsettings",
'computes', "computes",
'console', "console",
'datasource', "datasource",
'networks', "networks",
'instances', "instances",
'interfaces', "interfaces",
'nwfilters', "nwfilters",
'storages', "storages",
'secrets', "secrets",
'logs', "logs",
'qr_code', "qr_code",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.locale.LocaleMiddleware', "django.middleware.locale.LocaleMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django_otp.middleware.OTPMiddleware', "django_otp.middleware.OTPMiddleware",
'login_required.middleware.LoginRequiredMiddleware', "login_required.middleware.LoginRequiredMiddleware",
'django.contrib.auth.middleware.RemoteUserMiddleware', "django.contrib.auth.middleware.RemoteUserMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
'appsettings.middleware.AppSettingsMiddleware', "appsettings.middleware.AppSettingsMiddleware",
'webvirtcloud.middleware.ExceptionMiddleware', "webvirtcloud.middleware.ExceptionMiddleware",
] ]
ROOT_URLCONF = 'webvirtcloud.urls' ROOT_URLCONF = "webvirtcloud.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [ "DIRS": [
os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, "templates"),
], ],
'APP_DIRS': True, "APP_DIRS": True,
'OPTIONS': { "OPTIONS": {
'context_processors': [ "context_processors": [
'django.template.context_processors.debug', "django.template.context_processors.debug",
'django.template.context_processors.request', "django.template.context_processors.request",
'django.contrib.auth.context_processors.auth', "django.contrib.auth.context_processors.auth",
'django.contrib.messages.context_processors.messages', "django.contrib.messages.context_processors.messages",
'appsettings.context_processors.app_settings', "appsettings.context_processors.app_settings",
], ],
'libraries': { "libraries": {
'common_tags': 'webvirtcloud.common_tags', "common_tags": "webvirtcloud.common_tags",
}, },
}, },
}, },
] ]
WSGI_APPLICATION = 'webvirtcloud.wsgi.application' WSGI_APPLICATION = "webvirtcloud.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases # https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { "default": {
'ENGINE': 'django.db.backends.sqlite3', "ENGINE": "django.db.backends.sqlite3",
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
} }
} }
AUTHENTICATION_BACKENDS = [ AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend', "django.contrib.auth.backends.ModelBackend",
] ]
LOGIN_URL = '/accounts/login/' LOGIN_URL = "/accounts/login/"
LOGOUT_REDIRECT_URL = '/accounts/login/' LOGOUT_REDIRECT_URL = "/accounts/login/"
LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = "en-us"
TIME_ZONE = 'UTC' TIME_ZONE = "UTC"
USE_I18N = True USE_I18N = True
@ -111,30 +111,27 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
STATIC_URL = '/static/' STATIC_URL = "/static/"
STATICFILES_DIRS = [ STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"), os.path.join(BASE_DIR, "static"),
] ]
LOCALE_PATHS = [ LOCALE_PATHS = [
'locale/', "locale/",
] ]
LOGGING = { LOGGING = {
"version": 1, "version": 1,
"disable_existing_loggers": False, "disable_existing_loggers": False,
"handlers": { "handlers": {
"mail_admins": { "mail_admins": {"level": "ERROR", "class": "django.utils.log.AdminEmailHandler"}
"level": "ERROR",
"class": "django.utils.log.AdminEmailHandler"
}
}, },
"loggers": { "loggers": {
"django.request": { "django.request": {
"handlers": ["mail_admins"], "handlers": ["mail_admins"],
"level": "ERROR", "level": "ERROR",
"propagate": True "propagate": True,
} }
}, },
} }
@ -147,7 +144,7 @@ LOGGING = {
WS_PORT = 6080 WS_PORT = 6080
# Websock host # Websock host
WS_HOST = '0.0.0.0' WS_HOST = "0.0.0.0"
# Websock public port - 80 or 443 if reverse-proxy, else 6080 # Websock public port - 80 or 443 if reverse-proxy, else 6080
WS_PUBLIC_PORT = 6080 WS_PUBLIC_PORT = 6080
@ -156,22 +153,53 @@ WS_PUBLIC_PORT = 6080
WS_PUBLIC_HOST = None WS_PUBLIC_HOST = None
# Websock public path # Websock public path
WS_PUBLIC_PATH = '/novncd/' WS_PUBLIC_PATH = "/novncd/"
# Websock Certificate for SSL # Websock Certificate for SSL
WS_CERT = None WS_CERT = None
# List of console listen addresses # List of console listen addresses
QEMU_CONSOLE_LISTEN_ADDRESSES = ( QEMU_CONSOLE_LISTEN_ADDRESSES = (
('127.0.0.1', 'Localhost'), ("127.0.0.1", "Localhost"),
('0.0.0.0', 'All interfaces'), ("0.0.0.0", "All interfaces"),
) )
# List taken from http://qemu.weilnetz.de/qemu-doc.html#sec_005finvocation # List taken from http://qemu.weilnetz.de/qemu-doc.html#sec_005finvocation
QEMU_KEYMAPS = ['ar', 'da', 'de', 'de-ch', 'en-gb', 'en-us', 'es', 'et', 'fi', QEMU_KEYMAPS = [
'fo', 'fr', 'fr-be', 'fr-ca', 'fr-ch', 'hr', 'hu', 'is', 'it', "ar",
'ja', 'lt', 'lv', 'mk', 'nl', 'nl-be', 'no', 'pl', 'pt', "da",
'pt-br', 'ru', 'sl', 'sv', 'th', 'tr'] "de",
"de-ch",
"en-gb",
"en-us",
"es",
"et",
"fi",
"fo",
"fr",
"fr-be",
"fr-ca",
"fr-ch",
"hr",
"hu",
"is",
"it",
"ja",
"lt",
"lv",
"mk",
"nl",
"nl-be",
"no",
"pl",
"pt",
"pt-br",
"ru",
"sl",
"sv",
"th",
"tr",
]
# Keepalive interval and count for libvirt connections # Keepalive interval and count for libvirt connections
LIBVIRT_KEEPALIVE_INTERVAL = 5 LIBVIRT_KEEPALIVE_INTERVAL = 5
@ -183,5 +211,4 @@ SHOW_PROFILE_EDIT_PASSWORD = True
OTP_ENABLED = False OTP_ENABLED = False
LOGIN_REQUIRED_IGNORE_VIEW_NAMES = ['accounts:email_otp'] LOGIN_REQUIRED_IGNORE_VIEW_NAMES = ["accounts:email_otp"]

View file

@ -1,21 +1,20 @@
from django.conf import settings
from django.urls import include, path
from appsettings.views import appsettings from appsettings.views import appsettings
from console.views import console from console.views import console
from django.conf import settings
from django.urls import include, path
from instances.views import index from instances.views import index
urlpatterns = [ urlpatterns = [
path('', index, name='index'), path("", index, name="index"),
path('admin/', include(('admin.urls', 'admin'), namespace='admin')), path("admin/", include(("admin.urls", "admin"), namespace="admin")),
path('accounts/', include('accounts.urls')), path("accounts/", include("accounts.urls")),
path('appsettings/', appsettings, name='appsettings'), path("appsettings/", appsettings, name="appsettings"),
path('computes/', include('computes.urls')), path("computes/", include("computes.urls")),
path('console/', console, name='console'), path("console/", console, name="console"),
path('datasource/', include('datasource.urls')), path("datasource/", include("datasource.urls")),
path('instances/', include('instances.urls')), path("instances/", include("instances.urls")),
path('i18n/', include('django.conf.urls.i18n')), path("i18n/", include("django.conf.urls.i18n")),
path('logs/', include('logs.urls')), path("logs/", include("logs.urls")),
] ]
if settings.DEBUG: if settings.DEBUG:
@ -23,7 +22,7 @@ if settings.DEBUG:
import debug_toolbar import debug_toolbar
urlpatterns += [ urlpatterns += [
path('__debug__/', include(debug_toolbar.urls)), path("__debug__/", include(debug_toolbar.urls)),
] ]
except ImportError: except ImportError:
pass pass

View file

@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webvirtcloud.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webvirtcloud.settings")
application = get_wsgi_application() application = get_wsgi_application()

View file

@ -16,7 +16,7 @@ exec(
compile( compile(
open("/srv/webvirtcloud/venv/bin/activate", "rb").read(), open("/srv/webvirtcloud/venv/bin/activate", "rb").read(),
"/srv/webvirtcloud/venv/bin/activate", "/srv/webvirtcloud/venv/bin/activate",
"exec" "exec",
) )
) )