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

Merge pull request #385 from catborise/master

black & isort linter fixes- bug fixes
This commit is contained in:
catborise 2020-11-05 14:28:53 +03:00 committed by GitHub
commit 9aed7c7716
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 6874 additions and 2143 deletions

View file

@ -8,7 +8,7 @@ def apply_change_password(sender, **kwargs):
Depending on settings SHOW_PROFILE_EDIT_PASSWORD
'''
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'):
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')
@ -29,8 +29,8 @@ def create_admin(sender, **kwargs):
'''
Create initial admin user
'''
from django.contrib.auth.models import User
from accounts.models import UserAttributes
from django.contrib.auth.models import User
plan = kwargs.get('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
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):

View file

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

View file

@ -35,27 +35,27 @@ def validate_ssh_key(key):
return False
# unpack the contents of data, from data[:4] , property of ssh key .
try:
str_len = struct.unpack('>I', data[:4])[0]
str_len = struct.unpack(">I", data[:4])[0]
except struct.error:
return False
# 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
else:
else:
return False
def send_email_with_otp(user, device):
send_mail(
_('OTP QR Code'),
_('Please view HTML version of this message.'),
_("OTP QR Code"),
_("Please view HTML version of this message."),
None,
[user.email],
html_message=render_to_string(
'accounts/email/otp.html',
"accounts/email/otp.html",
{
'totp_url': device.config_url,
'user': user,
"totp_url": device.config_url,
"user": user,
},
),
fail_silently=False,

View file

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

View file

@ -1,6 +1,6 @@
from django import forms
from django.contrib.auth.models import Group, User
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.contrib.auth.models import Group, User
from django.urls import reverse_lazy
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _
@ -13,7 +13,7 @@ from .models import Permission
class GroupForm(forms.ModelForm):
permissions = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Permission.objects.filter(content_type__model='permissionset'),
queryset=Permission.objects.filter(content_type__model="permissionset"),
required=False,
)
@ -25,12 +25,12 @@ class GroupForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(GroupForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
instance = getattr(self, "instance", None)
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):
self.instance.user_set.set(self.cleaned_data['users'])
self.instance.user_set.set(self.cleaned_data["users"])
def save(self, *args, **kwargs):
instance = super(GroupForm, self).save()
@ -39,36 +39,36 @@ class GroupForm(forms.ModelForm):
class Meta:
model = Group
fields = '__all__'
fields = "__all__"
class UserForm(forms.ModelForm):
user_permissions = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Permission.objects.filter(content_type__model='permissionset'),
label=_('Permissions'),
queryset=Permission.objects.filter(content_type__model="permissionset"),
label=_("Permissions"),
required=False,
)
groups = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Group.objects.all(),
label=_('Groups'),
label=_("Groups"),
required=False,
)
class Meta:
model = User
fields = [
'username',
'groups',
'first_name',
'last_name',
'email',
'user_permissions',
'is_staff',
'is_active',
'is_superuser',
"username",
"groups",
"first_name",
"last_name",
"email",
"user_permissions",
"is_staff",
"is_active",
"is_superuser",
]
def __init__(self, *args, **kwargs):
@ -76,12 +76,20 @@ class UserForm(forms.ModelForm):
if self.instance.id:
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=format_lazy(_("""Raw passwords are not stored, so there is no way to see
this user's password, but you can change the password using <a href='{}'>this form</a>."""),
reverse_lazy('admin:user_update_password',
args=[self.instance.id,]))
help_text=format_lazy(
_(
"""Raw passwords are not stored, so there is no way to see this user's password,
but you can change the password using <a href='{}'>this form</a>."""
),
reverse_lazy(
"admin:user_update_password",
args=[
self.instance.id,
],
),
),
)
self.fields['Password'] = password
self.fields["Password"] = password
class UserCreateForm(UserForm):
@ -90,20 +98,20 @@ class UserCreateForm(UserForm):
class Meta:
model = User
fields = [
'username',
'password',
'groups',
'first_name',
'last_name',
'email',
'user_permissions',
'is_staff',
'is_active',
'is_superuser',
"username",
"password",
"groups",
"first_name",
"last_name",
"email",
"user_permissions",
"is_staff",
"is_active",
"is_superuser",
]
class UserAttributesForm(forms.ModelForm):
class Meta:
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)
if form.is_valid():
form.save()
return redirect('admin:group_list')
return redirect("admin:group_list")
return render(
request,
@ -107,11 +107,7 @@ def user_create(request):
return render(
request,
"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():
user_form.save()
attributes_form.save()
next = request.GET.get('next')
next = request.GET.get("next")
return redirect(next or "admin:user_list")
return render(
request,
"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
def user_update_password(request, pk):
user = get_object_or_404(User, pk=pk)
if request.method == 'POST':
if request.method == "POST":
form = AdminPasswordChangeForm(user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important!
messages.success(request, _("User password changed: {}".format(user.username)))
messages.success(request, _("Password changed for %(user)s") % {"user": user.username})
return redirect("admin:user_list")
else:
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
appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name")
if request.method == 'POST':
if 'SASS_DIR' in request.POST:
if request.method == "POST":
if "SASS_DIR" in request.POST:
try:
sass_dir.value = request.POST.get("SASS_DIR", "")
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)
except Exception as err:
msg = err
@ -44,7 +44,7 @@ def appsettings(request):
addlogmsg(request.user.username, "", msg)
return HttpResponseRedirect(request.get_full_path())
if 'BOOTSTRAP_THEME' in request.POST:
if "BOOTSTRAP_THEME" in request.POST:
theme = request.POST.get("BOOTSTRAP_THEME", "")
scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';"
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:
main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch + "\n")
css_compressed = sass.compile(string=scss_var + "\n" + scss_boot + "\n" + scss_bootswatch,
output_style='compressed')
css_compressed = sass.compile(
string=scss_var + "\n" + scss_boot + "\n" + scss_bootswatch,
output_style="compressed",
)
with open("static/css/" + main_css, "w") as css:
css.write(css_compressed)
bootstrap_theme.value = theme
bootstrap_theme.save()
msg = _(f"Theme changed. Now: {theme}")
msg = _("Theme is changed. Now: %(theme)s") % {"theme": theme}
messages.success(request, msg)
except Exception as err:
msg = err
@ -77,7 +79,7 @@ def appsettings(request):
setting.value = request.POST.get(setting.key, "")
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)
except Exception as err:
msg = err
@ -86,4 +88,4 @@ def appsettings(request):
addlogmsg(request.user.username, "", msg)
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 django.urls import include, path
# from instances.views import create_instance, create_instance_select_type
from interfaces.views import interface, interfaces
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
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
have_symbol = re.compile('[^a-zA-Z0-9._-]+')
wrong_ip = re.compile('^0.|^255.')
wrong_name = re.compile('[^a-zA-Z0-9._-]+')

View file

@ -1,18 +1,23 @@
import json
from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render, reverse
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils import timezone
from libvirt import libvirtError
from accounts.models import UserInstance
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 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 . import utils
@ -25,15 +30,17 @@ def computes(request):
: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
def overview(request, 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(
compute.hostname,
@ -49,7 +56,7 @@ def overview(request, compute_id):
lib_version = conn.get_lib_version()
conn.close()
return render(request, 'overview.html', locals())
return render(request, "overview.html", locals())
@superuser_only
@ -57,9 +64,9 @@ def instances(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id)
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
@ -67,9 +74,9 @@ def compute_create(request, FormClass):
form = FormClass(request.POST or None)
if form.is_valid():
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
@ -88,22 +95,22 @@ def compute_update(request, compute_id):
form = FormClass(request.POST or None, instance=compute)
if form.is_valid():
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
def compute_delete(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id)
if request.method == 'POST':
if request.method == "POST":
compute.delete()
return redirect('computes')
return redirect("computes")
return render(
request,
'common/confirm_delete.html',
{'object': compute},
"common/confirm_delete.html",
{"object": compute},
)
@ -126,17 +133,19 @@ def compute_graph(request, compute_id):
mem_usage = conn.get_memory_usage()
conn.close()
except libvirtError:
cpu_usage = {'usage': 0}
mem_usage = {'usage': 0}
cpu_usage = {"usage": 0}
mem_usage = {"usage": 0}
current_time = 0
data = json.dumps({
'cpudata': cpu_usage['usage'],
'memdata': mem_usage,
'timeline': current_time,
})
data = json.dumps(
{
"cpudata": cpu_usage["usage"],
"memdata": mem_usage,
"timeline": current_time,
}
)
response = HttpResponse()
response['Content-Type'] = "text/javascript"
response["Content-Type"] = "text/javascript"
response.write(data)
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)
if disk in disk_device_types:
if disk == 'disk':
data['bus'] = sorted(disk_device_types)
elif disk == 'cdrom':
data['bus'] = ['ide', 'sata', 'scsi']
elif disk == 'floppy':
data['bus'] = ['fdc']
elif disk == 'lun':
data['bus'] = ['scsi']
if disk == "disk":
data["bus"] = sorted(disk_device_types)
elif disk == "cdrom":
data["bus"] = ["ide", "sata", "scsi"]
elif disk == "floppy":
data["bus"] = ["fdc"]
elif disk == "lun":
data["bus"] = ["scsi"]
except libvirtError:
pass
@ -193,7 +202,7 @@ def get_compute_machine_types(request, compute_id, arch):
compute.password,
compute.type,
)
data['machines'] = conn.get_machine_types(arch)
data["machines"] = conn.get_machine_types(arch)
except libvirtError:
pass
@ -217,7 +226,7 @@ def get_compute_video_models(request, compute_id, arch, machine):
compute.password,
compute.type,
)
data['videos'] = conn.get_video_models(arch, machine)
data["videos"] = conn.get_video_models(arch, machine)
except libvirtError:
pass
@ -241,8 +250,8 @@ def get_dom_capabilities(request, compute_id, arch, machine):
compute.password,
compute.type,
)
data['videos'] = conn.get_disk_device_types(arch, machine)
data['bus'] = 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)
except libvirtError:
pass

View file

@ -1,4 +1,5 @@
import random, string
import random
import string
haystack = string.ascii_letters + string.digits + string.punctuation
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.
import functools
import logging as log
import os
import queue
import socket
import signal
import socket
import threading
import logging as log
class _TunnelScheduler(object):
"""

View file

@ -6,7 +6,11 @@ from libvirt import libvirtError
from appsettings.settings import app_settings
from instances.models import Instance
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):
@ -61,7 +65,7 @@ def console(request):
if console_type is None:
console_error = "Fail to get console. Please check the console configuration of your VM."
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.set_cookie("token", token)

View file

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

View file

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

View file

@ -25,8 +25,8 @@ def apply_passwordless_console(sender, **kwargs):
'''
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.models import Permission
User = get_user_model()
plan = kwargs.get('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
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):

View file

@ -32,4 +32,4 @@ class Migration(migrations.Migration):
operations = [
migrations.RunPython(add_flavors, del_flavors),
]
]

View file

@ -19,7 +19,7 @@
<div class="tab-content">
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="takesnapshot">
{% 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">
{% csrf_token %}
<div class="form-group row">

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 _
class Logs(Model):
user = CharField(_('user'), max_length=50)
instance = CharField(_('instance'), max_length=50)
message = CharField(_('message'), max_length=255)
date = DateTimeField(_('date'), auto_now=True)
user = CharField(_("user"), max_length=50)
instance = CharField(_("instance"), max_length=50)
message = CharField(_("message"), max_length=255)
date = DateTimeField(_("date"), auto_now=True)
def __str__(self):
return self.instance

View file

@ -1,6 +1,7 @@
from django.urls import path
from . import views
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
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.http import HttpResponse
from admin.decorators import superuser_only
from instances.models import Instance
@ -29,14 +27,14 @@ def vm_logs(request, 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 = []
for l in logs_:
log = dict()
log['user'] = l.user
log['instance'] = l.instance
log['message'] = l.message
log['date'] = l.date.strftime('%x %X')
log["user"] = l.user
log["instance"] = l.instance
log["message"] = l.message
log["date"] = l.date.strftime("%x %X")
logs.append(log)
return HttpResponse(json.dumps(logs))

View file

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

View file

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

View file

@ -25,48 +25,55 @@ def nwfilters(request, compute_id):
try:
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
if request.method == 'POST':
if 'create_nwfilter' in request.POST:
xml = request.POST.get('nwfilter_xml', '')
for nwf in conn.get_nwfilters():
nwfilters_all.append(conn.get_nwfilter_info(nwf))
if request.method == "POST":
if "create_nwfilter" in request.POST:
xml = request.POST.get("nwfilter_xml", "")
if xml:
try:
util.etree.fromstring(xml)
name = util.get_xml_path(xml, '/filter/@name')
uuid = util.get_xml_path(xml, '/filter/uuid')
name = util.get_xml_path(xml, "/filter/@name")
uuid = util.get_xml_path(xml, "/filter/uuid")
except util.etree.ParseError:
name = None
for nwf in nwfilters:
if name == nwf.name():
for nwf in nwfilters_all:
if name == nwf["name"]:
error_msg = _("A network filter with this name already exists")
raise Exception(error_msg)
if uuid == nwf.UUIDString():
if uuid == nwf["uuid"]:
error_msg = _("A network filter with this UUID already exists")
raise Exception(error_msg)
else:
try:
msg = _("Creating NWFilter: %s" % name)
msg = _("%(filter)s network filter is created") % {"filter": name}
conn.create_nwfilter(xml)
addlogmsg(request.user.username, compute.hostname, msg)
except libvirtError as lib_err:
messages.error(request, lib_err)
addlogmsg(request.user.username, compute.hostname, lib_err)
if 'del_nwfilter' in request.POST:
name = request.POST.get('nwfiltername', '')
msg = _(f"Deleting NWFilter: {name}")
if "del_nwfilter" in request.POST:
name = request.POST.get("nwfiltername", "")
msg = _("%(filter)s network filter is deleted") % {"filter": name}
in_use = False
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()
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()
if name in dom_filterrefs:
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)
addlogmsg(request.user.username, compute.hostname, msg)
i_conn.close()
@ -77,18 +84,15 @@ def nwfilters(request, compute_id):
nwfilter.undefine()
addlogmsg(request.user.username, compute.hostname, msg)
if 'cln_nwfilter' in request.POST:
if "cln_nwfilter" in request.POST:
name = request.POST.get('nwfiltername', '')
cln_name = request.POST.get('cln_name', name + '-clone')
name = request.POST.get("nwfiltername", "")
cln_name = request.POST.get("cln_name", name + "-clone")
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)
for nwf in conn.get_nwfilters():
nwfilters_all.append(conn.get_nwfilter_info(nwf))
conn.close()
except libvirtError as lib_err:
messages.error(request, lib_err)
@ -97,10 +101,14 @@ def nwfilters(request, compute_id):
messages.error(request, err)
addlogmsg(request.user.username, compute.hostname, err)
return render(request, 'nwfilters.html', {
'nwfilters': nwfilters_all,
'compute': compute,
})
return render(
request,
"nwfilters.html",
{
"nwfilters": nwfilters_all,
"compute": compute,
},
)
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)
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)
for nwf in conn.get_nwfilters():
@ -126,10 +136,10 @@ def nwfilter(request, compute_id, nwfltr):
rules = nwfilter.get_rules()
refs = nwfilter.get_filter_refs()
if request.method == 'POST':
if request.method == "POST":
if 'edit_nwfilter' in request.POST:
new_xml = request.POST.get('edit_xml', '')
if "edit_nwfilter" in request.POST:
new_xml = request.POST.get("edit_xml", "")
if new_xml:
nwfilter.delete()
@ -139,10 +149,10 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml)
raise libvirtError(lib_err)
if 'del_nwfilter_rule' in request.POST:
action = request.POST.get('action', '')
direction = request.POST.get('direction', '')
priority = request.POST.get('priority', '')
if "del_nwfilter_rule" in request.POST:
action = request.POST.get("action", "")
direction = request.POST.get("direction", "")
priority = request.POST.get("priority", "")
new_xml = nwfilter.delete_rule(action, direction, priority)
nwfilter.delete()
@ -152,8 +162,8 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml)
raise libvirtError(lib_err)
if 'del_nwfilter_ref' in request.POST:
ref_name = request.POST.get('ref')
if "del_nwfilter_ref" in request.POST:
ref_name = request.POST.get("ref")
new_xml = nwfilter.delete_ref(ref_name)
nwfilter.delete()
try:
@ -162,8 +172,8 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml)
raise libvirtError(lib_err)
if 'add_nwfilter_rule' in request.POST:
rule_xml = request.POST.get('nwfilterrule_xml', '')
if "add_nwfilter_rule" in request.POST:
rule_xml = request.POST.get("nwfilterrule_xml", "")
if not rule_xml:
return HttpResponseRedirect(request.get_full_path())
new_xml = nwfilter.add_rule(rule_xml)
@ -174,8 +184,8 @@ def nwfilter(request, compute_id, nwfltr):
conn.create_nwfilter(xml)
raise libvirtError(lib_err)
if 'add_nwfilter_ref' in request.POST:
ref_name = request.POST.get('nwfilters_select', '')
if "add_nwfilter_ref" in request.POST:
ref_name = request.POST.get("nwfilters_select", "")
if not ref_name:
return HttpResponseRedirect(request.get_full_path())
new_xml = nwfilter.add_ref(ref_name)
@ -194,4 +204,4 @@ def nwfilter(request, compute_id, nwfltr):
except Exception as 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.http import HttpResponseRedirect
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,
VIR_SECRET_USAGE_TYPE_TLS, VIR_SECRET_USAGE_TYPE_VOLUME, libvirtError)
from libvirt import (
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
@ -36,36 +42,38 @@ def secrets(request, compute_id):
secrt = conn.get_secret(uuid)
try:
secrt_value = conn.get_secret_value(uuid)
except libvirtError as lib_err:
except libvirtError:
secrt_value = None
secrets_all.append({
'usage': secrt.usageID(),
'uuid': secrt.UUIDString(),
'usageType': secret_usage_types[secrt.usageType()],
'value': secrt_value
})
if request.method == 'POST':
if 'create' in request.POST:
secrets_all.append(
{
"usage": secrt.usageID(),
"uuid": secrt.UUIDString(),
"usageType": secret_usage_types[secrt.usageType()],
"value": secrt_value,
}
)
if request.method == "POST":
if "create" in request.POST:
form = AddSecret(request.POST)
if form.is_valid():
data = form.cleaned_data
conn.create_secret(
data['ephemeral'],
data['private'],
data['usage_type'],
data['data'],
data["ephemeral"],
data["private"],
data["usage_type"],
data["data"],
)
return HttpResponseRedirect(request.get_full_path())
else:
for msg_err in form.errors.values():
messages.error(request, msg_err.as_text())
if 'delete' in request.POST:
uuid = request.POST.get('uuid', '')
if "delete" in request.POST:
uuid = request.POST.get("uuid", "")
conn.delete_secret(uuid)
return HttpResponseRedirect(request.get_full_path())
if 'set_value' in request.POST:
uuid = request.POST.get('uuid', '')
value = request.POST.get('value', '')
if "set_value" in request.POST:
uuid = request.POST.get("uuid", "")
value = request.POST.get("value", "")
try:
conn.set_secret_value(uuid, value)
except Exception as err:
@ -74,4 +82,4 @@ def secrets(request, compute_id):
except libvirtError as 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
from django import forms
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 admin.decorators import superuser_only
from appsettings.models import AppSettings
from appsettings.settings import app_settings
from computes.models import Compute
from storages.forms import AddStgPool, CloneImage, CreateVolumeForm
@ -31,34 +30,46 @@ def storages(request, compute_id):
storages = conn.get_storages_info()
secrets = conn.get_secrets()
if request.method == 'POST':
if 'create' in request.POST:
if request.method == "POST":
if "create" in request.POST:
form = AddStgPool(request.POST)
if form.is_valid():
data = form.cleaned_data
if data['name'] in storages:
if data["name"] in storages:
msg = _("Pool name already use")
messages.error(request, msg)
errors = True
if data['stg_type'] == 'rbd':
if not data['secret']:
if data["stg_type"] == "rbd":
if not data["secret"]:
msg = _("You need create secret for pool")
messages.error(request, msg)
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")
messages.error(request, msg)
errors = True
if not errors:
if data['stg_type'] == 'rbd':
conn.create_storage_ceph(data['stg_type'], data['name'], data['ceph_pool'], 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'])
if data["stg_type"] == "rbd":
conn.create_storage_ceph(
data["stg_type"],
data["name"],
data["ceph_pool"],
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:
conn.create_storage(data['stg_type'], data['name'], data['source'], data['target'])
return HttpResponseRedirect(reverse('storage', args=[compute_id, data['name']]))
conn.create_storage(data["stg_type"], data["name"], data["source"], data["target"])
return HttpResponseRedirect(reverse("storage", args=[compute_id, data["name"]]))
else:
for msg_err in form.errors.values():
messages.error(request, msg_err.as_text())
@ -66,7 +77,7 @@ def storages(request, compute_id):
except libvirtError as lib_err:
messages.error(request, lib_err)
return render(request, 'storages.html', locals())
return render(request, "storages.html", locals())
@superuser_only
@ -77,9 +88,10 @@ def storage(request, compute_id, pool):
:param pool:
:return:
"""
def handle_uploaded_file(path, f_name):
target = path + '/' + str(f_name)
destination = open(target, 'wb+')
target = path + "/" + str(f_name)
destination = open(target, "wb+")
for chunk in f_name.chunks():
destination.write(chunk)
destination.close()
@ -93,7 +105,7 @@ def storage(request, compute_id, pool):
storages = conn.get_storages()
state = conn.is_active()
size, free = conn.get_size()
used = (size - free)
used = size - free
if state:
percent = (used * 100) // size
else:
@ -109,55 +121,58 @@ def storage(request, compute_id, pool):
else:
volumes = None
if request.method == 'POST':
if 'start' in request.POST:
if request.method == "POST":
if "start" in request.POST:
conn.start()
return HttpResponseRedirect(request.get_full_path())
if 'stop' in request.POST:
if "stop" in request.POST:
conn.stop()
return HttpResponseRedirect(request.get_full_path())
if 'delete' in request.POST:
if "delete" in request.POST:
conn.delete()
return HttpResponseRedirect(reverse('storages', args=[compute_id]))
if 'set_autostart' in request.POST:
return HttpResponseRedirect(reverse("storages", args=[compute_id]))
if "set_autostart" in request.POST:
conn.set_autostart(1)
return HttpResponseRedirect(request.get_full_path())
if 'unset_autostart' in request.POST:
if "unset_autostart" in request.POST:
conn.set_autostart(0)
return HttpResponseRedirect(request.get_full_path())
if 'del_volume' in request.POST:
volname = request.POST.get('volname', '')
if "del_volume" in request.POST:
volname = request.POST.get("volname", "")
vol = conn.get_volume(volname)
vol.delete(0)
messages.success(request, _(f"Volume: {volname} is deleted."))
return redirect(reverse('storage', args=[compute.id, pool]))
messages.success(request, _("Volume: %(volume)s is deleted.") % {"vol": volname})
return redirect(reverse("storage", args=[compute.id, pool]))
# return HttpResponseRedirect(request.get_full_path())
if 'iso_upload' in request.POST:
if str(request.FILES['file']) in conn.update_volumes():
if "iso_upload" in request.POST:
if str(request.FILES["file"]) in conn.update_volumes():
error_msg = _("ISO image already exist")
messages.error(request, error_msg)
else:
handle_uploaded_file(path, request.FILES['file'])
messages.success(request, _(f"ISO: {request.FILES['file']} is uploaded."))
handle_uploaded_file(path, request.FILES["file"])
messages.success(request, _("ISO: %(file)s is uploaded.") % {"file": request.FILES["file"]})
return HttpResponseRedirect(request.get_full_path())
if 'cln_volume' in request.POST:
if "cln_volume" in request.POST:
form = CloneImage(request.POST)
if form.is_valid():
data = form.cleaned_data
img_name = data['name']
img_name = data["name"]
meta_prealloc = 0
if img_name in conn.update_volumes():
msg = _("Name of volume already in use")
messages.error(request, msg)
if data['convert']:
format = data['format']
if data['meta_prealloc'] and data['format'] == 'qcow2':
if data["convert"]:
format = data["format"]
if data["meta_prealloc"] and data["format"] == "qcow2":
meta_prealloc = True
else:
format = None
try:
name = conn.clone_volume(data['image'], data['name'], format, meta_prealloc)
messages.success(request, _(f"{data['image']} image cloned as {name} successfully"))
name = conn.clone_volume(data["image"], data["name"], format, meta_prealloc)
messages.success(
request,
_("%(image)s image cloned as %(clone)s successfully") % {"image": data["image"], "name": name},
)
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
@ -167,11 +182,17 @@ def storage(request, compute_id, pool):
conn.close()
return render(request, 'storage.html', locals())
return render(request, "storage.html", locals())
@superuser_only
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)
meta_prealloc = False
@ -182,26 +203,26 @@ def create_volume(request, compute_id, pool):
form = CreateVolumeForm(request.POST or None)
if form.is_valid():
data = form.cleaned_data
if data['meta_prealloc'] and data['format'] == 'qcow2':
if data["meta_prealloc"] and data["format"] == "qcow2":
meta_prealloc = True
disk_owner_uid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
disk_owner_gid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID)
name = conn.create_volume(
data['name'],
data['size'],
data['format'],
data["name"],
data["size"],
data["format"],
meta_prealloc,
disk_owner_uid,
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:
for msg_err in form.errors.values():
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):
@ -216,7 +237,7 @@ def get_volumes(request, compute_id, pool):
try:
conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
conn.refresh()
data['vols'] = sorted(conn.get_volumes())
data["vols"] = sorted(conn.get_volumes())
except libvirtError:
pass
return HttpResponse(json.dumps(data))

View file

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

View file

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

View file

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

View file

@ -1,14 +1,15 @@
import time
from vrtManager.connection import wvmConnect
from vrtManager.util import get_xml_path
def cpu_version(doc):
for info in doc.xpath('/sysinfo/processor/entry'):
elem = info.xpath('@name')[0]
if elem == 'version':
for info in doc.xpath("/sysinfo/processor/entry"):
elem = info.xpath("@name")[0]
if elem == "version":
return info.text
return 'Unknown'
return "Unknown"
class wvmHostDetails(wvmConnect):
@ -19,14 +20,12 @@ class wvmHostDetails(wvmConnect):
all_mem = self.wvm.getInfo()[1] * 1048576
freemem = self.wvm.getMemoryStats(-1, 0)
if isinstance(freemem, dict):
free = (freemem['buffers'] +
freemem['free'] +
freemem['cached']) * 1024
free = (freemem["buffers"] + freemem["free"] + freemem["cached"]) * 1024
percent = abs(100 - ((free * 100) // all_mem))
usage = (all_mem - free)
mem_usage = {'total': all_mem, 'usage': usage, 'percent': percent}
usage = all_mem - free
mem_usage = {"total": all_mem, "usage": usage, "percent": percent}
else:
mem_usage = {'total': None, 'usage': None, 'percent': None}
mem_usage = {"total": None, "usage": None, "percent": None}
return mem_usage
def get_cpu_usage(self):
@ -38,7 +37,7 @@ class wvmHostDetails(wvmConnect):
cpu = self.wvm.getCPUStats(-1, 0)
if isinstance(cpu, dict):
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())
diff_idle = idle - prev_idle
diff_total = total - prev_total
@ -51,8 +50,8 @@ class wvmHostDetails(wvmConnect):
if diff_usage < 0:
diff_usage = 0
else:
return {'usage': None}
return {'usage': diff_usage}
return {"usage": None}
return {"usage": diff_usage}
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 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):
@ -12,36 +12,37 @@ class wvmInterfaces(wvmConnect):
mac = iface.MACString()
itype = util.get_xml_path(xml, "/interface/@type")
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):
self.wvm.interfaceDefineXML(xml, flag)
def create_iface(self, name, itype, mode, netdev, ipv4_type, ipv4_addr, ipv4_gw,
ipv6_type, ipv6_addr, ipv6_gw, stp, delay):
def create_iface(
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}'>
<start mode='{mode}'/>"""
if ipv4_type == 'dhcp':
if ipv4_type == "dhcp":
xml += """<protocol family='ipv4'>
<dhcp/>
</protocol>"""
if ipv4_type == 'static':
address, prefix = ipv4_addr.split('/')
if ipv4_type == "static":
address, prefix = ipv4_addr.split("/")
xml += f"""<protocol family='ipv4'>
<ip address='{address}' prefix='{prefix}'/>
<route gateway='{ipv4_gw}'/>
</protocol>"""
if ipv6_type == 'dhcp':
if ipv6_type == "dhcp":
xml += """<protocol family='ipv6'>
<dhcp/>
</protocol>"""
if ipv6_type == 'static':
address, prefix = ipv6_addr.split('/')
if ipv6_type == "static":
address, prefix = ipv6_addr.split("/")
xml += f"""<protocol family='ipv6'>
<ip address='{address}' prefix='{prefix}'/>
<route gateway='{ipv6_gw}'/>
</protocol>"""
if itype == 'bridge':
if itype == "bridge":
xml += f"""<bridge stp='{stp}' delay='{delay}'>
<interface name='{netdev}' type='ethernet'/>
</bridge>"""
@ -85,9 +86,9 @@ class wvmInterface(wvmConnect):
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv4']/ip/@address")
if ipaddr:
return 'static'
return "static"
else:
return 'dhcp'
return "dhcp"
except:
return None
@ -98,16 +99,16 @@ class wvmInterface(wvmConnect):
if not int_ipv4_ip or not int_ipv4_mask:
return None
else:
return int_ipv4_ip + '/' + int_ipv4_mask
return int_ipv4_ip + "/" + int_ipv4_mask
def get_ipv6_type(self):
try:
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv6']/ip/@address")
if ipaddr:
return 'static'
return "static"
else:
return 'dhcp'
return "dhcp"
except:
return None
@ -118,15 +119,15 @@ class wvmInterface(wvmConnect):
if not int_ipv6_ip or not int_ipv6_mask:
return None
else:
return int_ipv6_ip + '/' + int_ipv6_mask
return int_ipv6_ip + "/" + int_ipv6_mask
def get_bridge(self):
bridge = None
if self.get_type() == 'bridge':
if self.get_type() == "bridge":
bridge = util.get_xml_path(self._XMLDesc(), "/interface/bridge/interface/@name")
for iface in self.get_bridge_slave_ifaces():
if iface.get('state') == 'up' and iface.get('speed') is not 'unknown':
bridge = iface.get('name')
if iface.get("state") == "up" and iface.get("speed") != "unknown":
bridge = iface.get("name")
return bridge
return bridge
else:
@ -134,20 +135,20 @@ class wvmInterface(wvmConnect):
def get_bridge_slave_ifaces(self):
ifaces = list()
if self.get_type() == 'bridge':
if self.get_type() == "bridge":
tree = ElementTree.fromstring(self._XMLDesc())
for iface in tree.findall("./bridge/"):
address = state = speed = None
name = iface.get('name')
if_type = iface.get('type')
link = iface.find('link')
name = iface.get("name")
if_type = iface.get("type")
link = iface.find("link")
if link is not None:
state = link.get('state')
speed = link.get('speed')
mac = iface.find('mac')
state = link.get("state")
speed = link.get("speed")
mac = iface.find("mac")
if mac is not None:
address = mac.get('address')
ifaces.append({'name': name, 'type': if_type, 'state': state, 'speed': speed, 'mac': address})
address = mac.get("address")
ifaces.append({"name": name, "type": if_type, "state": state, "speed": speed, "mac": address})
return ifaces
else:
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 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.IPy import IP
from vrtManager.connection import wvmConnect
from vrtManager.IPy import IP
def network_size(subnet, dhcp=None):
"""
@ -17,7 +21,7 @@ def network_size(subnet, dhcp=None):
if addr.version() == 4:
dhcp_pool = [addr[2].strCompressed(), addr[addr.len() - 2].strCompressed()]
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))]
if dhcp:
return gateway, mask, dhcp_pool
@ -26,7 +30,6 @@ def network_size(subnet, dhcp=None):
class wvmNetworks(wvmConnect):
def get_networks_info(self):
get_networks = self.get_networks()
networks = []
@ -39,44 +42,55 @@ class wvmNetworks(wvmConnect):
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")
networks.append({'name': network, 'status': net_status,
'device': net_bridge, 'forward': net_forward})
networks.append({"name": network, "status": net_status, "device": net_bridge, "forward": net_forward})
return networks
def define_network(self, xml):
self.wvm.networkDefineXML(xml)
def create_network(self, name, forward,
ipv4, gateway, mask, dhcp4,
ipv6, gateway6, prefix6, dhcp6,
bridge, openvswitch, fixed=False):
def create_network(
self,
name,
forward,
ipv4,
gateway,
mask,
dhcp4,
ipv6,
gateway6,
prefix6,
dhcp6,
bridge,
openvswitch,
fixed=False,
):
xml = f"""
<network>
<name>{name}</name>"""
if forward in ['nat', 'route', 'bridge']:
if forward in ["nat", "route", "bridge"]:
xml += f"""<forward mode='{forward}'/>"""
if forward == 'macvtap':
if forward == "macvtap":
xml += f"""<forward mode='bridge'>
<interface dev='{bridge}'/>
</forward>"""
else:
xml += """<bridge """
if forward in ['nat', 'route', 'none']:
if forward in ["nat", "route", "none"]:
xml += """stp='on' delay='0'"""
if forward == 'bridge':
if forward == "bridge":
xml += f"""name='{bridge}'"""
xml += """/>"""
if openvswitch is True:
xml += """<virtualport type='openvswitch'/>"""
if forward not in ['bridge', 'macvtap']:
if forward not in ["bridge", "macvtap"]:
if ipv4:
xml += f"""<ip address='{gateway}' netmask='{mask}'>"""
if dhcp4:
xml += f"""<dhcp>
<range start='{dhcp4[0]}' end='{dhcp4[1]}' />"""
if fixed:
fist_oct = int(dhcp4[0].strip().split('.')[3])
last_oct = int(dhcp4[1].strip().split('.')[3])
fist_oct = int(dhcp4[0].strip().split(".")[3])
last_oct = int(dhcp4[1].strip().split(".")[3])
for ip in range(fist_oct, last_oct + 1):
xml += f"""<host mac='{util.randomMAC()}' ip='{gateway[:-2]}.{ip}' />"""
xml += """</dhcp>"""
@ -144,23 +158,23 @@ class wvmNetwork(wvmConnect):
if util.get_xml_path(xml, "/network/ip") is None:
return ip_networks
tree = etree.fromstring(xml)
ips = tree.findall('.ip')
ips = tree.findall(".ip")
for ip in ips:
address_str = ip.get('address')
netmask_str = ip.get('netmask')
prefix = ip.get('prefix')
family = ip.get('family', 'ipv4')
base = 32 if family == 'ipv4' else 128
address_str = ip.get("address")
netmask_str = ip.get("netmask")
prefix = ip.get("prefix")
family = ip.get("family", "ipv4")
base = 32 if family == "ipv4" else 128
if prefix:
prefix = int(prefix)
binstr = ((prefix * "1") + ((base - prefix) * "0"))
binstr = (prefix * "1") + ((base - prefix) * "0")
netmask_str = str(IP(int(binstr, base=2)))
if netmask_str:
netmask = IP(netmask_str)
gateway = IP(address_str)
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)
else:
ret = IP(str(address_str))
@ -178,12 +192,12 @@ class wvmNetwork(wvmConnect):
forward_dev = util.get_xml_path(xml, "/network/forward/@dev")
return [fw, forward_dev]
def get_dhcp_range(self, family='ipv4'):
def get_dhcp_range(self, family="ipv4"):
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")
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")
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)]
def get_dhcp_range_start(self, family='ipv4'):
def get_dhcp_range_start(self, family="ipv4"):
dhcp = self.get_dhcp_range(family)
if not dhcp:
return None
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)
if not dhcp:
return None
@ -211,74 +225,77 @@ class wvmNetwork(wvmConnect):
return True
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()
tree = etree.fromstring(self._XMLDesc(0))
for ipdhcp in tree.findall("./ip"):
if family == 'ipv4':
if ipdhcp.get('family') is None:
hosts = ipdhcp.findall('./dhcp/host')
if family == "ipv4":
if ipdhcp.get("family") is None:
hosts = ipdhcp.findall("./dhcp/host")
for host in hosts:
host_ip = host.get('ip')
mac = host.get('mac')
name = host.get('name', '')
result.append({'ip': host_ip, 'mac': mac, 'name': name})
host_ip = host.get("ip")
mac = host.get("mac")
name = host.get("name", "")
result.append({"ip": host_ip, "mac": mac, "name": name})
return result
else:
continue
if family == 'ipv6':
if family == "ipv6":
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
for host in hosts:
host_ip = host.get('ip')
host_id = host.get('id')
name = host.get('name', '')
result.append({'ip': host_ip, 'id': host_id, 'name': name})
host_ip = host.get("ip")
host_id = host.get("id")
name = host.get("name", "")
result.append({"ip": host_ip, "id": host_id, "name": name})
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():
tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4':
if family == "ipv4":
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[0].set('start', range_start)
dhcp_range[0].set('end', range_end)
dhcp_range[0].set("start", range_start)
dhcp_range[0].set("end", range_end)
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))
if family == 'ipv4':
if family == "ipv4":
hosts = tree.xpath("/network/ip[not(@family='ipv6')]/dhcp/host")
parent_index = self.parent_count - 2
if family == 'ipv6':
if family == "ipv6":
hosts = tree.xpath("/network/ip[@family='ipv6']/dhcp/host")
parent_index = self.parent_count - 1
for h in hosts:
if h.get('ip') == ip:
if family == 'ipv4':
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get('mac'), h.get('name'), ip)
if family == 'ipv6':
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get('id'), h.get('name'), ip)
if h.get("ip") == ip:
if family == "ipv4":
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get("mac"), h.get("name"), ip)
if family == "ipv6":
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get("id"), h.get("name"), ip)
self.update(VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
self.update(
VIR_NETWORK_UPDATE_COMMAND_DELETE,
VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
)
break
def modify_fixed_address(self, name, address, mac_duid, family='ipv4'):
def modify_fixed_address(self, name, address, mac_duid, family="ipv4"):
tree = etree.fromstring(self._XMLDesc(0))
if family == 'ipv4':
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
if family == "ipv4":
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
hosts = tree.xpath("./ip[not(@family='ipv6')]/dhcp/host")
compare_var = 'mac'
compare_var = "mac"
parent_index = self.parent_count - 2
if family == 'ipv6':
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
if family == "ipv6":
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
compare_var = 'id'
compare_var = "id"
parent_index = self.parent_count - 1
new_host_xml = etree.fromstring(new_xml)
@ -288,17 +305,25 @@ class wvmNetwork(wvmConnect):
host = h
break
if host is None:
self.update(VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
self.update(
VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
)
else:
# 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
else:
self.update(VIR_NETWORK_UPDATE_COMMAND_MODIFY, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
self.update(
VIR_NETWORK_UPDATE_COMMAND_MODIFY,
VIR_NETWORK_SECTION_IP_DHCP_HOST,
new_xml,
parent_index,
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
)
def get_qos(self):
qos_values = dict()
@ -307,19 +332,19 @@ class wvmNetwork(wvmConnect):
if qos:
qos = qos[0]
in_qos = qos.find('inbound')
in_qos = qos.find("inbound")
if in_qos is not None:
in_av = in_qos.get('average')
in_peak = in_qos.get('peak')
in_burst = in_qos.get('burst')
qos_values['inbound'] = {'average': in_av, 'peak': in_peak, 'burst': in_burst}
in_av = in_qos.get("average")
in_peak = in_qos.get("peak")
in_burst = in_qos.get("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:
out_av = out_qos.get('average')
out_peak = out_qos.get('peak')
out_burst = out_qos.get('burst')
qos_values['outbound'] = {'average': out_av, 'peak': out_peak, 'burst': out_burst}
out_av = out_qos.get("average")
out_peak = out_qos.get("peak")
out_burst = out_qos.get("burst")
qos_values["outbound"] = {"average": out_av, "peak": out_peak, "burst": out_burst}
return qos_values
def set_qos(self, direction, average, peak, burst):
@ -328,7 +353,7 @@ class wvmNetwork(wvmConnect):
elif direction == "outbound":
xml = f"<outbound average='{average}' peak='{peak}' burst='{burst}'/>"
else:
raise Exception('Direction must be inbound or outbound')
raise Exception("Direction must be inbound or outbound")
tree = etree.fromstring(self._XMLDesc(0))
@ -363,7 +388,7 @@ class wvmNetwork(wvmConnect):
self.leases = self.net.DHCPLeases()
except Exception as e:
self.leases = []
raise f"Error getting {self} DHCP leases: {e}"
raise "Error getting {} DHCP leases: {}".format(self, e)
def get_dhcp_leases(self):
if self.leases is None:

View file

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

View file

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

View file

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

View file

@ -16,13 +16,7 @@ class wvmStorages(wvmConnect):
stg_vol = None
stg_size = stg.info()[1]
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
@ -103,12 +97,7 @@ class wvmStorage(wvmConnect):
return self.pool.name()
def get_status(self):
status = [
"Not running",
"Initializing pool, not available",
"Running normally",
"Running degraded"
]
status = ["Not running", "Initializing pool, not available", "Running normally", "Running degraded"]
try:
return status[self.pool.info()[0]]
except ValueError:
@ -217,12 +206,12 @@ class wvmStorage(wvmConnect):
"name": volname,
"size": self.get_volume_size(volname),
"allocation": self.get_volume_allocation(volname),
"type": self.get_volume_type(volname)
"type": self.get_volume_type(volname),
}
)
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
storage_type = self.get_type()
alloc = size
@ -258,7 +247,17 @@ class wvmStorage(wvmConnect):
self._createXML(xml, metadata)
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)
if not vol_fmt:
vol_fmt = self.get_volume_type(name)
@ -266,10 +265,10 @@ class wvmStorage(wvmConnect):
storage_type = self.get_type()
if storage_type == "dir":
if vol_fmt in ["qcow", "qcow2"]:
target_file += '.' + vol_fmt
target_file += "." + vol_fmt
else:
suffix = '.' + file_suffix
target_file += suffix if len(suffix) > 1 else ''
suffix = "." + file_suffix
target_file += suffix if len(suffix) > 1 else ""
xml = f"""
<volume>

View file

@ -1,8 +1,9 @@
import random
import string
import re
import lxml.etree as etree
import string
import libvirt
import lxml.etree as etree
def is_kvm_available(xml):
@ -18,10 +19,8 @@ def randomMAC():
# qemu MAC
oui = [0x52, 0x54, 0x00]
mac = oui + [random.randint(0x00, 0xff),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff)]
return ':'.join(map(lambda x: "%02x" % x, mac))
mac = oui + [random.randint(0x00, 0xFF), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]
return ":".join(map(lambda x: "%02x" % x, mac))
def randomUUID():
@ -29,18 +28,17 @@ def randomUUID():
u = [random.randint(0, 255) for ignore in range(0, 16)]
u[6] = (u[6] & 0x0F) | (4 << 4)
u[8] = (u[8] & 0x3F) | (2 << 6)
return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
"%02x" * 6]) % tuple(u)
return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2, "%02x" * 6]) % tuple(u)
def randomPasswd(length=12, alphabet=string.ascii_letters + string.digits):
"""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):
"""@param conn: libvirt connection to poll for max possible vcpus
@type type: optional guest type (kvm, etc.)"""
@type type: optional guest type (kvm, etc.)"""
if type is None:
type = conn.getType()
try:
@ -57,7 +55,7 @@ def xml_escape(str):
str = str.replace("&", "&amp;")
str = str.replace("'", "&apos;")
str = str.replace("\"", "&quot;")
str = str.replace('"', "&quot;")
str = str.replace("<", "&lt;")
str = str.replace(">", "&gt;")
return str
@ -109,7 +107,7 @@ def get_xpath(doc, path):
if ret is not None:
if isinstance(ret, list):
if len(ret) >= 1:
if hasattr(ret[0], 'text'):
if hasattr(ret[0], "text"):
result = ret[0].text
else:
result = ret[0]
@ -146,11 +144,11 @@ def validate_uuid(val):
raise ValueError(
"UUID must be a 32-digit hexadecimal number. It may take "
"the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or may "
"omit hyphens altogether.")
"omit hyphens altogether."
)
else: # UUID had no dashes, so add them in
val = (val[0:8] + "-" + val[8:12] + "-" + val[12:16] +
"-" + val[16:20] + "-" + val[20:32])
else: # UUID had no dashes, so add them in
val = val[0:8] + "-" + val[8:12] + "-" + val[12:16] + "-" + val[16:20] + "-" + val[20:32]
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)
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
@ -177,7 +175,8 @@ UEFI_ARCH_PATTERNS = {
r".*OVMF_CODE\.fd", # RHEL
r".*ovmf-x64/OVMF.*\.fd", # gerd's firmware repo
r".*ovmf-x86_64-.*", # SUSE
r".*ovmf.*", ".*OVMF.*", # generic attempt at a catchall
r".*ovmf.*",
".*OVMF.*", # generic attempt at a catchall
],
"aarch64": [
r".*AAVMF_CODE\.fd", # RHEL

View file

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

View file

@ -15,7 +15,7 @@ class ExceptionMiddleware:
if isinstance(exception, libvirtError):
messages.error(
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

View file

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

View file

@ -8,102 +8,102 @@ import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = ''
SECRET_KEY = ""
DEBUG = False
ALLOWED_HOSTS = ['*']
ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap4',
'django_icons',
'django_otp',
'django_otp.plugins.otp_totp',
'accounts',
'admin',
'appsettings',
'computes',
'console',
'datasource',
'networks',
'instances',
'interfaces',
'nwfilters',
'storages',
'secrets',
'logs',
'qr_code',
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"bootstrap4",
"django_icons",
"django_otp",
"django_otp.plugins.otp_totp",
"accounts",
"admin",
"appsettings",
"computes",
"console",
"datasource",
"networks",
"instances",
"interfaces",
"nwfilters",
"storages",
"secrets",
"logs",
"qr_code",
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware',
'login_required.middleware.LoginRequiredMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'appsettings.middleware.AppSettingsMiddleware',
'webvirtcloud.middleware.ExceptionMiddleware',
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django_otp.middleware.OTPMiddleware",
"login_required.middleware.LoginRequiredMiddleware",
"django.contrib.auth.middleware.RemoteUserMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"appsettings.middleware.AppSettingsMiddleware",
"webvirtcloud.middleware.ExceptionMiddleware",
]
ROOT_URLCONF = 'webvirtcloud.urls'
ROOT_URLCONF = "webvirtcloud.urls"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
os.path.join(BASE_DIR, "templates"),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'appsettings.context_processors.app_settings',
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"appsettings.context_processors.app_settings",
],
'libraries': {
'common_tags': 'webvirtcloud.common_tags',
"libraries": {
"common_tags": "webvirtcloud.common_tags",
},
},
},
]
WSGI_APPLICATION = 'webvirtcloud.wsgi.application'
WSGI_APPLICATION = "webvirtcloud.wsgi.application"
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
}
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
@ -111,30 +111,27 @@ USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/'
STATIC_URL = "/static/"
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
LOCALE_PATHS = [
'locale/',
"locale/",
]
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"mail_admins": {
"level": "ERROR",
"class": "django.utils.log.AdminEmailHandler"
}
"mail_admins": {"level": "ERROR", "class": "django.utils.log.AdminEmailHandler"}
},
"loggers": {
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": True
"propagate": True,
}
},
}
@ -147,7 +144,7 @@ LOGGING = {
WS_PORT = 6080
# 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
WS_PUBLIC_PORT = 6080
@ -156,22 +153,53 @@ WS_PUBLIC_PORT = 6080
WS_PUBLIC_HOST = None
# Websock public path
WS_PUBLIC_PATH = '/novncd/'
WS_PUBLIC_PATH = "/novncd/"
# Websock Certificate for SSL
WS_CERT = None
# List of console listen addresses
QEMU_CONSOLE_LISTEN_ADDRESSES = (
('127.0.0.1', 'Localhost'),
('0.0.0.0', 'All interfaces'),
("127.0.0.1", "Localhost"),
("0.0.0.0", "All interfaces"),
)
# 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',
'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']
QEMU_KEYMAPS = [
"ar",
"da",
"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
LIBVIRT_KEEPALIVE_INTERVAL = 5
@ -183,5 +211,4 @@ SHOW_PROFILE_EDIT_PASSWORD = True
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 console.views import console
from django.conf import settings
from django.urls import include, path
from instances.views import index
urlpatterns = [
path('', index, name='index'),
path('admin/', include(('admin.urls', 'admin'), namespace='admin')),
path('accounts/', include('accounts.urls')),
path('appsettings/', appsettings, name='appsettings'),
path('computes/', include('computes.urls')),
path('console/', console, name='console'),
path('datasource/', include('datasource.urls')),
path('instances/', include('instances.urls')),
path('i18n/', include('django.conf.urls.i18n')),
path('logs/', include('logs.urls')),
path("", index, name="index"),
path("admin/", include(("admin.urls", "admin"), namespace="admin")),
path("accounts/", include("accounts.urls")),
path("appsettings/", appsettings, name="appsettings"),
path("computes/", include("computes.urls")),
path("console/", console, name="console"),
path("datasource/", include("datasource.urls")),
path("instances/", include("instances.urls")),
path("i18n/", include("django.conf.urls.i18n")),
path("logs/", include("logs.urls")),
]
if settings.DEBUG:
@ -23,7 +22,7 @@ if settings.DEBUG:
import debug_toolbar
urlpatterns += [
path('__debug__/', include(debug_toolbar.urls)),
path("__debug__/", include(debug_toolbar.urls)),
]
except ImportError:
pass

View file

@ -11,6 +11,6 @@ import os
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()

View file

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