diff --git a/accounts/apps.py b/accounts/apps.py index 6a2e2bd..0192800 100644 --- a/accounts/apps.py +++ b/accounts/apps.py @@ -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: diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py index 1990eeb..6c41032 100644 --- a/accounts/migrations/0001_initial.py +++ b/accounts/migrations/0001_initial.py @@ -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): diff --git a/accounts/templatetags/tags_fingerprint.py b/accounts/templatetags/tags_fingerprint.py index 31f3952..83cfe14 100644 --- a/accounts/templatetags/tags_fingerprint.py +++ b/accounts/templatetags/tags_fingerprint.py @@ -1,7 +1,8 @@ -from django import template import base64 import hashlib +from django import template + register = template.Library() diff --git a/accounts/utils.py b/accounts/utils.py index d089ecd..da30c0a 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -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, diff --git a/accounts/views.py b/accounts/views.py index fa207bf..8ca3ba7 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -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) diff --git a/admin/forms.py b/admin/forms.py index 1a4a226..140e6a8 100644 --- a/admin/forms.py +++ b/admin/forms.py @@ -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 this form."""), - 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 this form.""" + ), + 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"] diff --git a/admin/views.py b/admin/views.py index b441d85..c920890 100644 --- a/admin/views.py +++ b/admin/views.py @@ -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")) diff --git a/appsettings/views.py b/appsettings/views.py index 5d9a19c..5446c9a 100644 --- a/appsettings/views.py +++ b/appsettings/views.py @@ -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()) diff --git a/computes/urls.py b/computes/urls.py index 08248de..6e43695 100644 --- a/computes/urls.py +++ b/computes/urls.py @@ -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 diff --git a/computes/validators.py b/computes/validators.py index e58dfea..64458fc 100644 --- a/computes/validators.py +++ b/computes/validators.py @@ -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._-]+') diff --git a/computes/views.py b/computes/views.py index 38514ff..7d9184b 100644 --- a/computes/views.py +++ b/computes/views.py @@ -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 diff --git a/conf/runit/secret_generator.py b/conf/runit/secret_generator.py index 2a5a8dc..e22ca7b 100644 --- a/conf/runit/secret_generator.py +++ b/conf/runit/secret_generator.py @@ -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)])) diff --git a/console/sshtunnels.py b/console/sshtunnels.py index 336febd..06f4c9d 100644 --- a/console/sshtunnels.py +++ b/console/sshtunnels.py @@ -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): """ diff --git a/console/views.py b/console/views.py index f5ac707..c5464aa 100644 --- a/console/views.py +++ b/console/views.py @@ -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) diff --git a/datasource/urls.py b/datasource/urls.py index d250fe7..cba7517 100644 --- a/datasource/urls.py +++ b/datasource/urls.py @@ -1,4 +1,5 @@ from django.urls import path + from . import views urlpatterns = [ diff --git a/datasource/views.py b/datasource/views.py index b389122..1a18ff5 100644 --- a/datasource/views.py +++ b/datasource/views.py @@ -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) diff --git a/instances/apps.py b/instances/apps.py index 3b5c07d..49983ac 100644 --- a/instances/apps.py +++ b/instances/apps.py @@ -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: diff --git a/instances/migrations/0001_initial.py b/instances/migrations/0001_initial.py index e27f7aa..6b64b27 100644 --- a/instances/migrations/0001_initial.py +++ b/instances/migrations/0001_initial.py @@ -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): diff --git a/instances/migrations/0006_addFlavors.py b/instances/migrations/0006_addFlavors.py index b1af99d..278060a 100644 --- a/instances/migrations/0006_addFlavors.py +++ b/instances/migrations/0006_addFlavors.py @@ -32,4 +32,4 @@ class Migration(migrations.Migration): operations = [ migrations.RunPython(add_flavors, del_flavors), - ] \ No newline at end of file + ] diff --git a/instances/templates/instances/snapshots_tab.html b/instances/templates/instances/snapshots_tab.html index f920f76..46f6049 100644 --- a/instances/templates/instances/snapshots_tab.html +++ b/instances/templates/instances/snapshots_tab.html @@ -19,7 +19,7 @@
{% if instance.status == 5 %} -

{% trans "This may take more than an hour, depending on how much content is on your droplet and how large the disk is." %}

+

{% trans "This may take more than an hour, depending on how much content is on your instance and how large the disk is." %}

{% csrf_token %}
diff --git a/instances/templatetags/tags_active.py b/instances/templatetags/tags_active.py index 5af5248..2745147 100644 --- a/instances/templatetags/tags_active.py +++ b/instances/templatetags/tags_active.py @@ -1,6 +1,7 @@ -from django import template import re +from django import template + register = template.Library() diff --git a/instances/tests.py b/instances/tests.py index 5c70322..20e1bfc 100644 --- a/instances/tests.py +++ b/instances/tests.py @@ -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 diff --git a/instances/views.py b/instances/views.py index f1a2221..c093f5f 100644 --- a/instances/views.py +++ b/instances/views.py @@ -19,7 +19,8 @@ from django.http import Http404, HttpResponse, JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError) +from instances.models import Instance +from libvirt import VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError from logs.views import addlogmsg from vrtManager import util from vrtManager.create import wvmCreate @@ -27,8 +28,6 @@ from vrtManager.instance import wvmInstances from vrtManager.storage import wvmStorage from vrtManager.util import randomPasswd -from instances.models import Instance - from . import utils from .forms import ConsoleForm, FlavorForm, NewVMForm from .models import Flavor @@ -37,42 +36,47 @@ from .models import Flavor def index(request): instances = None - computes = Compute.objects.all().order_by("name").prefetch_related('instance_set').prefetch_related( - 'instance_set__userinstance_set') + computes = ( + Compute.objects.all() + .order_by("name") + .prefetch_related("instance_set") + .prefetch_related("instance_set__userinstance_set") + ) for compute in computes: utils.refr(compute) if request.user.is_superuser: - instances = Instance.objects.all().prefetch_related('userinstance_set') + instances = Instance.objects.all().prefetch_related("userinstance_set") else: - instances = Instance.objects.filter(userinstance__user=request.user).prefetch_related('userinstance_set') + instances = Instance.objects.filter(userinstance__user=request.user).prefetch_related("userinstance_set") - return render(request, 'allinstances.html', {'computes': computes, 'instances': instances}) + return render(request, "allinstances.html", {"computes": computes, "instances": instances}) def instance(request, pk): instance: Instance = get_instance(request.user, pk) compute: Compute = instance.compute - computes = Compute.objects.all().order_by('name') + computes = Compute.objects.all().order_by("name") computes_count = computes.count() - users = User.objects.all().order_by('username') + users = User.objects.all().order_by("username") publickeys = UserSSHKey.objects.filter(user_id=request.user.id) keymaps = settings.QEMU_KEYMAPS console_types = AppSettings.objects.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list() console_form = ConsoleForm( initial={ - 'type': instance.console_type, - 'listen_on': instance.console_listen_address, - 'password': instance.console_passwd, - 'keymap': instance.console_keymap, - }) + "type": instance.console_type, + "listen_on": instance.console_listen_address, + "password": instance.console_passwd, + "keymap": instance.console_keymap, + } + ) console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES bottom_bar = app_settings.VIEW_INSTANCE_DETAIL_BOTTOM_BAR allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template try: - userinstance = UserInstance.objects.get(instance__compute_id=compute.id, - instance__name=instance.name, - user__id=request.user.id) + userinstance = UserInstance.objects.get( + instance__compute_id=compute.id, instance__name=instance.name, user__id=request.user.id + ) except UserInstance.DoesNotExist: userinstance = None @@ -109,7 +113,7 @@ def instance(request, pk): # addlogmsg(request.user.username, instance.name, msg) # userinstances = UserInstance.objects.filter(instance=instance).order_by('user__username') - userinstances = instance.userinstance_set.order_by('user__username') + userinstances = instance.userinstance_set.order_by("user__username") allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template # Host resources @@ -121,12 +125,12 @@ def instance(request, pk): storages_host = sorted(instance.proxy.get_storages(True)) net_models_host = instance.proxy.get_network_models() - return render(request, 'instance.html', locals()) + return render(request, "instance.html", locals()) def status(request, pk): instance = get_instance(request.user, pk) - return JsonResponse({'status': instance.proxy.get_status()}) + return JsonResponse({"status": instance.proxy.get_status()}) def stats(request, pk): @@ -142,56 +146,58 @@ def stats(request, pk): current_time = time.strftime("%H:%M:%S") for blk in blk_usage: - json_blk.append({'dev': blk['dev'], 'data': [int(blk['rd']) / 1048576, int(blk['wr']) / 1048576]}) + json_blk.append({"dev": blk["dev"], "data": [int(blk["rd"]) / 1048576, int(blk["wr"]) / 1048576]}) for net in net_usage: - json_net.append({'dev': net['dev'], 'data': [int(net['rx']) / 1048576, int(net['tx']) / 1048576]}) + json_net.append({"dev": net["dev"], "data": [int(net["rx"]) / 1048576, int(net["tx"]) / 1048576]}) - return JsonResponse({ - 'cpudata': int(cpu_usage['cpu']), - 'memdata': mem_usage, - 'blkdata': json_blk, - 'netdata': json_net, - 'timeline': current_time, - }) + return JsonResponse( + { + "cpudata": int(cpu_usage["cpu"]), + "memdata": mem_usage, + "blkdata": json_blk, + "netdata": json_net, + "timeline": current_time, + } + ) def guess_mac_address(request, vname): - data = {'vname': vname} + data = {"vname": vname} mac = utils.get_dhcp_mac_address(vname) if not mac: mac = utils.get_random_mac_address() - data['mac'] = mac + data["mac"] = mac return HttpResponse(json.dumps(data)) def random_mac_address(request): data = dict() - data['mac'] = utils.get_random_mac_address() + data["mac"] = utils.get_random_mac_address() return HttpResponse(json.dumps(data)) def guess_clone_name(request): - dhcp_file = '/srv/webvirtcloud/dhcpd.conf' + dhcp_file = "/srv/webvirtcloud/dhcpd.conf" prefix = app_settings.CLONE_INSTANCE_DEFAULT_PREFIX if os.path.isfile(dhcp_file): instance_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)] - with open(dhcp_file, 'r') as f: + with open(dhcp_file, "r") as f: for line in f: line = line.strip() if f"host {prefix}" in line: - fqdn = line.split(' ')[1] - hostname = fqdn.split('.')[0] + fqdn = line.split(" ")[1] + hostname = fqdn.split(".")[0] if hostname.startswith(prefix) and hostname not in instance_names: - return HttpResponse(json.dumps({'name': hostname})) + return HttpResponse(json.dumps({"name": hostname})) return HttpResponse(json.dumps({})) def check_instance(request, vname): instance = Instance.objects.filter(name=vname) - data = {'vname': vname, 'exists': False} + data = {"vname": vname, "exists": False} if instance: - data['exists'] = True + data["exists"] = True return JsonResponse(data) @@ -209,20 +215,20 @@ def sshkeys(request, pk): keys = UserSSHKey.objects.filter(user=ui.user) for k in keys: instance_keys.append(k.keypublic) - if request.GET.get('plain', ''): - response = '\n'.join(instance_keys) - response += '\n' + if request.GET.get("plain", ""): + response = "\n".join(instance_keys) + response += "\n" else: response = json.dumps(instance_keys) return HttpResponse(response) def get_instance(user, pk): - ''' + """ Check that instance is available for user, if not raise 404 - ''' + """ instance = get_object_or_404(Instance, pk=pk) - user_instances = user.userinstance_set.all().values_list('instance', flat=True) + user_instances = user.userinstance_set.all().values_list("instance", flat=True) if user.is_superuser or instance.id in user_instances: return instance @@ -238,7 +244,7 @@ def poweron(request, pk): instance.proxy.start() addlogmsg(request.user.username, instance.name, _("Power On")) - return redirect(request.META.get('HTTP_REFERER')) + return redirect(request.META.get("HTTP_REFERER")) def powercycle(request, pk): @@ -246,7 +252,7 @@ def powercycle(request, pk): instance.proxy.force_shutdown() instance.proxy.start() addlogmsg(request.user.username, instance.name, _("Power Cycle")) - return redirect(request.META.get('HTTP_REFERER')) + return redirect(request.META.get("HTTP_REFERER")) def poweroff(request, pk): @@ -254,7 +260,7 @@ def poweroff(request, pk): instance.proxy.shutdown() addlogmsg(request.user.username, instance.name, _("Power Off")) - return redirect(request.META.get('HTTP_REFERER')) + return redirect(request.META.get("HTTP_REFERER")) @superuser_only @@ -262,7 +268,7 @@ def suspend(request, pk): instance = get_instance(request.user, pk) instance.proxy.suspend() addlogmsg(request.user.username, instance.name, _("Suspend")) - return redirect(request.META.get('HTTP_REFERER')) + return redirect(request.META.get("HTTP_REFERER")) @superuser_only @@ -270,48 +276,48 @@ def resume(request, pk): instance = get_instance(request.user, pk) instance.proxy.resume() addlogmsg(request.user.username, instance.name, _("Resume")) - return redirect(request.META.get('HTTP_REFERER')) + return redirect(request.META.get("HTTP_REFERER")) def force_off(request, pk): instance = get_instance(request.user, pk) instance.proxy.force_shutdown() addlogmsg(request.user.username, instance.name, _("Force Off")) - return redirect(request.META.get('HTTP_REFERER')) + return redirect(request.META.get("HTTP_REFERER")) def destroy(request, pk): instance = get_instance(request.user, pk) try: userinstance = instance.userinstance_set.get(user=request.user) - except: + except Exception: userinstance = UserInstance(is_delete=request.user.is_superuser) - if request.method == 'POST' and userinstance.is_delete: + if request.method == "POST" and userinstance.is_delete: if instance.proxy.get_status() == 1: instance.proxy.force_shutdown() - if request.POST.get('delete_disk', ''): - snapshots = sorted(instance.proxy.get_snapshot(), reverse=True, key=lambda k: k['date']) + if request.POST.get("delete_disk", ""): + snapshots = sorted(instance.proxy.get_snapshot(), reverse=True, key=lambda k: k["date"]) for snapshot in snapshots: - instance.proxy.snapshot_delete(snapshot['name']) + instance.proxy.snapshot_delete(snapshot["name"]) instance.proxy.delete_all_disks() - if request.POST.get('delete_nvram', ''): + if request.POST.get("delete_nvram", ""): instance.proxy.delete(VIR_DOMAIN_UNDEFINE_NVRAM) else: instance.proxy.delete(VIR_DOMAIN_UNDEFINE_KEEP_NVRAM) instance.delete() addlogmsg(request.user, instance.name, _("Destroy")) - return redirect(reverse('instances:index')) + return redirect(reverse("instances:index")) return render( request, - 'instances/destroy_instance_form.html', + "instances/destroy_instance_form.html", { - 'instance': instance, - 'userinstance': userinstance, + "instance": instance, + "userinstance": userinstance, }, ) @@ -320,14 +326,14 @@ def destroy(request, pk): def migrate(request, pk): instance = get_instance(request.user, pk) - compute_id = request.POST.get('compute_id', '') - live = request.POST.get('live_migrate', False) - unsafe = request.POST.get('unsafe_migrate', False) - xml_del = request.POST.get('xml_delete', False) - offline = request.POST.get('offline_migrate', False) - autoconverge = request.POST.get('autoconverge', False) - compress = request.POST.get('compress', False) - postcopy = request.POST.get('postcopy', False) + compute_id = request.POST.get("compute_id", "") + live = request.POST.get("live_migrate", False) + unsafe = request.POST.get("unsafe_migrate", False) + xml_del = request.POST.get("xml_delete", False) + offline = request.POST.get("offline_migrate", False) + autoconverge = request.POST.get("autoconverge", False) + compress = request.POST.get("compress", False) + postcopy = request.POST.get("postcopy", False) new_compute = Compute.objects.get(id=compute_id) @@ -336,20 +342,20 @@ def migrate(request, pk): except libvirtError as err: messages.error(request, err) - msg = _("Migrate to %(hostname)%") % {'hostname': new_compute.hostname} + msg = _("Instance is migrated to %(hostname)s") % {"hostname": new_compute.hostname} addlogmsg(request.user, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER')) + return redirect(request.META.get("HTTP_REFERER")) def set_root_pass(request, pk): instance = get_instance(request.user, pk) - if request.method == 'POST': - passwd = request.POST.get('passwd', None) + if request.method == "POST": + passwd = request.POST.get("passwd", None) if passwd: - passwd_hash = crypt.crypt(passwd, '$6$kgPoiREy') - data = {'action': 'password', 'passwd': passwd_hash, 'vname': instance.name} + passwd_hash = crypt.crypt(passwd, "$6$kgPoiREy") + data = {"action": "password", "passwd": passwd_hash, "vname": instance.name} if instance.proxy.get_status() == 5: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -358,24 +364,24 @@ def set_root_pass(request, pk): d = s.recv(1024).strip() result = json.loads(d) s.close() - if result['return'] == 'success': + if result["return"] == "success": msg = _("Reset root password") addlogmsg(request.user.username, instance.name, msg) messages.success(request, msg) else: - messages.error(request, result['message']) + messages.error(request, result["message"]) else: msg = _("Please shutdown down your instance and then try again") messages.error(request, msg) - return redirect(reverse('instances:instance', args=[instance.id]) + '#access') + return redirect(reverse("instances:instance", args=[instance.id]) + "#access") def add_public_key(request, pk): instance = get_instance(request.user, pk) - if request.method == 'POST': - sshkeyid = request.POST.get('sshkeyid', '') + if request.method == "POST": + sshkeyid = request.POST.get("sshkeyid", "") publickey = UserSSHKey.objects.get(id=sshkeyid) - data = {'action': 'publickey', 'key': publickey.keypublic, 'vname': instance.name} + data = {"action": "publickey", "key": publickey.keypublic, "vname": instance.name} if instance.proxy.get_status() == 5: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -383,87 +389,90 @@ def add_public_key(request, pk): s.send(json.dumps(data).encode()) result = json.loads(s.recv(1024)) s.close() - if result['return'] == 'error': - msg = result['message'] + if result["return"] == "error": + msg = result["message"] else: - msg = _("Installed new SSH public key %(keyname)s") % {'keyname': publickey.keyname} + msg = _("Installed new SSH public key %(keyname)s") % {"keyname": publickey.keyname} addlogmsg(request.user.username, instance.name, msg) - if result['return'] == 'success': + if result["return"] == "success": messages.success(request, msg) else: messages.error(request, msg) else: msg = _("Please shutdown down your instance and then try again") messages.error(request, msg) - return redirect(reverse('instances:instance', args=[instance.id]) + '#access') + return redirect(reverse("instances:instance", args=[instance.id]) + "#access") def resizevm_cpu(request, pk): instance = get_instance(request.user, pk) try: userinstance = instance.userinstance_set.get(user=request.user) - except: + except Exception: userinstance = UserInstance(is_change=False) vcpu = instance.proxy.get_vcpu() - if request.method == 'POST': + if request.method == "POST": if request.user.is_superuser or request.user.is_staff or userinstance.is_change: - new_vcpu = request.POST.get('vcpu', '') - new_cur_vcpu = request.POST.get('cur_vcpu', '') + new_vcpu = request.POST.get("vcpu", "") + new_cur_vcpu = request.POST.get("cur_vcpu", "") quota_msg = utils.check_user_quota(request.user, 0, int(new_vcpu) - vcpu, 0, 0) if not request.user.is_superuser and quota_msg: msg = _("User %(quota_msg)s quota reached, cannot resize CPU of '%(instance_name)s'!") % { - 'quota_msg': quota_msg, - 'instance_name': instance.name + "quota_msg": quota_msg, + "instance_name": instance.name, } messages.error(request, msg) else: cur_vcpu = new_cur_vcpu vcpu = new_vcpu instance.proxy.resize_cpu(cur_vcpu, vcpu) - msg = _("Resize CPU") + msg = _("CPU is resized: %(old)s to %(new)s") % {"old": cur_vcpu, "new": vcpu} addlogmsg(request.user.username, instance.name, msg) messages.success(request, msg) - return redirect(reverse('instances:instance', args=[instance.id]) + '#resize') + return redirect(reverse("instances:instance", args=[instance.id]) + "#resize") def resize_memory(request, pk): instance = get_instance(request.user, pk) try: userinstance = instance.userinstance_set.get(user=request.user) - except: + except Exception: userinstance = UserInstance(is_change=False) memory = instance.proxy.get_memory() cur_memory = instance.proxy.get_cur_memory() - if request.method == 'POST': + if request.method == "POST": if request.user.is_superuser or request.user.is_staff or userinstance.is_change: - new_memory = request.POST.get('memory', '') - new_memory_custom = request.POST.get('memory_custom', '') + new_memory = request.POST.get("memory", "") + new_memory_custom = request.POST.get("memory_custom", "") if new_memory_custom: new_memory = new_memory_custom - new_cur_memory = request.POST.get('cur_memory', '') - new_cur_memory_custom = request.POST.get('cur_memory_custom', '') + new_cur_memory = request.POST.get("cur_memory", "") + new_cur_memory_custom = request.POST.get("cur_memory_custom", "") if new_cur_memory_custom: new_cur_memory = new_cur_memory_custom quota_msg = utils.check_user_quota(request.user, 0, 0, int(new_memory) - memory, 0) if not request.user.is_superuser and quota_msg: msg = _("User %(quota_msg)s quota reached, cannot resize memory of '%(instance_name)s'!") % { - 'quota_msg': quota_msg, - 'instance_name': instance.name + "quota_msg": quota_msg, + "instance_name": instance.name, } messages.error(request, msg) else: - cur_memory = new_cur_memory - memory = new_memory - instance.proxy.resize_mem(cur_memory, memory) - msg = _("Resize Memory") + instance.proxy.resize_mem(new_cur_memory, new_memory) + msg = _("Memory is resized: current/max: %(old_cur)s/%(old_max)s to %(new_cur)s/%(new_max)s") % { + "old_cur": cur_memory, + "old_max": memory, + "new_cur": new_cur_memory, + "new_max": new_memory, + } addlogmsg(request.user.username, instance.name, msg) messages.success(request, msg) - return redirect(reverse('instances:instance', args=[instance.id]) + '#resize') + return redirect(reverse("instances:instance", args=[instance.id]) + "#resize") def resize_disk(request, pk): @@ -471,35 +480,35 @@ def resize_disk(request, pk): try: userinstance = instance.userinstance_set.get(user=request.user) - except: + except Exception: userinstance = UserInstance(is_change=False) disks = instance.proxy.get_disk_devices() - if request.method == 'POST': + if request.method == "POST": if request.user.is_superuser or request.user.is_staff or userinstance.is_change: disks_new = list() for disk in disks: - input_disk_size = int(request.POST.get('disk_size_' + disk['dev'], '0')) * 1073741824 - if input_disk_size > disk['size'] + (64 << 20): - disk['size_new'] = input_disk_size + input_disk_size = int(request.POST.get("disk_size_" + disk["dev"], "0")) * 1073741824 + if input_disk_size > disk["size"] + (64 << 20): + disk["size_new"] = input_disk_size disks_new.append(disk) - disk_sum = sum([disk['size'] >> 30 for disk in disks_new]) - disk_new_sum = sum([disk['size_new'] >> 30 for disk in disks_new]) + disk_sum = sum([disk["size"] >> 30 for disk in disks_new]) + disk_new_sum = sum([disk["size_new"] >> 30 for disk in disks_new]) quota_msg = utils.check_user_quota(request.user, 0, 0, 0, disk_new_sum - disk_sum) if not request.user.is_superuser and quota_msg: msg = _("User %(quota_msg)s quota reached, cannot resize disks of '%(instance_name)s'!") % { - 'quota_msg': quota_msg, - 'instance_name': instance.name + "quota_msg": quota_msg, + "instance_name": instance.name, } messages.error(request, msg) else: instance.proxy.resize_disk(disks_new) - msg = _("Disk resize") + msg = _("Disk is resized: %(dev)s") % {"dev": disk["dev"]} addlogmsg(request.user.username, instance.name, msg) messages.success(request, msg) - return redirect(reverse('instances:instance', args=[instance.id]) + '#resize') + return redirect(reverse("instances:instance", args=[instance.id]) + "#resize") def add_new_vol(request, pk): @@ -515,13 +524,13 @@ def add_new_vol(request, pk): instance.compute.password, instance.compute.type, ) - storage = request.POST.get('storage', '') - name = request.POST.get('name', '') - format = request.POST.get('format', app_settings.INSTANCE_VOLUME_DEFAULT_FORMAT) - size = request.POST.get('size', 0) - meta_prealloc = True if request.POST.get('meta_prealloc', False) else False - bus = request.POST.get('bus', app_settings.INSTANCE_VOLUME_DEFAULT_BUS) - cache = request.POST.get('cache', app_settings.INSTANCE_VOLUME_DEFAULT_CACHE) + storage = request.POST.get("storage", "") + name = request.POST.get("name", "") + format = request.POST.get("format", app_settings.INSTANCE_VOLUME_DEFAULT_FORMAT) + size = request.POST.get("size", 0) + meta_prealloc = True if request.POST.get("meta_prealloc", False) else False + bus = request.POST.get("bus", app_settings.INSTANCE_VOLUME_DEFAULT_BUS) + cache = request.POST.get("cache", app_settings.INSTANCE_VOLUME_DEFAULT_CACHE) target_dev = utils.get_new_disk_dev(media, disks, bus) source = conn_create.create_volume( @@ -534,19 +543,19 @@ def add_new_vol(request, pk): int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID), ) instance.proxy.attach_disk(target_dev, source, target_bus=bus, driver_type=format, cache_mode=cache) - msg = _("Attach new disk %(name)s (%(format)s)") % {'name': name, 'format': format} + msg = _("Attach new disk: %(name)s (%(format)s)") % {"name": name, "format": format} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def add_existing_vol(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - storage = request.POST.get('selected_storage', '') - name = request.POST.get('vols', '') - bus = request.POST.get('bus', app_settings.INSTANCE_VOLUME_DEFAULT_BUS) - cache = request.POST.get('cache', app_settings.INSTANCE_VOLUME_DEFAULT_CACHE) + storage = request.POST.get("selected_storage", "") + name = request.POST.get("vols", "") + bus = request.POST.get("bus", app_settings.INSTANCE_VOLUME_DEFAULT_BUS) + cache = request.POST.get("cache", app_settings.INSTANCE_VOLUME_DEFAULT_CACHE) media = instance.proxy.get_media_devices() disks = instance.proxy.get_disk_devices() @@ -565,29 +574,29 @@ def add_existing_vol(request, pk): source = f"{path}/{name}" instance.proxy.attach_disk(target_dev, source, target_bus=bus, driver_type=driver_type, cache_mode=cache) - msg = _("Attach Existing disk: %(target_dev)s") % {'target_dev': target_dev} + msg = _("Attach Existing disk: %(target_dev)s") % {"target_dev": target_dev} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def edit_volume(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template - if 'edit_volume' in request.POST and allow_admin_or_not_template: - target_dev = request.POST.get('dev', '') + if "edit_volume" in request.POST and allow_admin_or_not_template: + target_dev = request.POST.get("dev", "") - new_path = request.POST.get('vol_path', '') - shareable = bool(request.POST.get('vol_shareable', False)) - readonly = bool(request.POST.get('vol_readonly', False)) - disk_type = request.POST.get('vol_type', '') - new_bus = request.POST.get('vol_bus', '') - bus = request.POST.get('vol_bus_old', '') - serial = request.POST.get('vol_serial', '') - format = request.POST.get('vol_format', '') - cache = request.POST.get('vol_cache', app_settings.INSTANCE_VOLUME_DEFAULT_CACHE) - io = request.POST.get('vol_io_mode', app_settings.INSTANCE_VOLUME_DEFAULT_IO) - discard = request.POST.get('vol_discard_mode', app_settings.INSTANCE_VOLUME_DEFAULT_DISCARD) - zeroes = request.POST.get('vol_detect_zeroes', app_settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES) + new_path = request.POST.get("vol_path", "") + shareable = bool(request.POST.get("vol_shareable", False)) + readonly = bool(request.POST.get("vol_readonly", False)) + disk_type = request.POST.get("vol_type", "") + new_bus = request.POST.get("vol_bus", "") + bus = request.POST.get("vol_bus_old", "") + serial = request.POST.get("vol_serial", "") + format = request.POST.get("vol_format", "") + cache = request.POST.get("vol_cache", app_settings.INSTANCE_VOLUME_DEFAULT_CACHE) + io = request.POST.get("vol_io_mode", app_settings.INSTANCE_VOLUME_DEFAULT_IO) + discard = request.POST.get("vol_discard_mode", app_settings.INSTANCE_VOLUME_DEFAULT_DISCARD) + zeroes = request.POST.get("vol_detect_zeroes", app_settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES) new_target_dev = utils.get_new_disk_dev(instance.media, instance.disks, new_bus) if new_bus != bus: @@ -621,20 +630,23 @@ def edit_volume(request, pk): ) if not instance.proxy.get_status() == 5: - messages.success(request, _("Volume changes are applied. " + "But it will be activated after shutdown")) + messages.success( + request, + _("Volume changes are applied. " + "But it will be activated after shutdown"), + ) else: messages.success(request, _("Volume is changed successfully.")) - msg = _("Edit disk: %(target_dev)s") % {'target_dev': target_dev} + msg = _("Edit disk: %(target_dev)s") % {"target_dev": target_dev} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def delete_vol(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - storage = request.POST.get('storage', '') + storage = request.POST.get("storage", "") conn_delete = wvmStorage( instance.compute.hostname, instance.compute.login, @@ -642,16 +654,16 @@ def delete_vol(request, pk): instance.compute.type, storage, ) - dev = request.POST.get('dev', '') - path = request.POST.get('path', '') - name = request.POST.get('name', '') + dev = request.POST.get("dev", "") + path = request.POST.get("path", "") + name = request.POST.get("name", "") - msg = _("Delete disk: %(dev)s") % {'dev': dev} + msg = _("Delete disk: %(dev)s") % {"dev": dev} instance.proxy.detach_disk(dev) conn_delete.del_volume(name) addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def detach_vol(request, pk): @@ -659,26 +671,26 @@ def detach_vol(request, pk): allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - dev = request.POST.get('dev', '') - path = request.POST.get('path', '') + dev = request.POST.get("dev", "") + path = request.POST.get("path", "") instance.proxy.detach_disk(dev) - msg = _("Detach disk: %(dev)s") % {'dev': dev} + msg = _("Detach disk: %(dev)s") % {"dev": dev} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def add_cdrom(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - bus = request.POST.get('bus', 'ide' if instance.machine == 'pc' else 'sata') + bus = request.POST.get("bus", "ide" if instance.machine == "pc" else "sata") target = utils.get_new_disk_dev(instance.media, instance.disks, bus) - instance.proxy.attach_disk(target, "", disk_device='cdrom', cache_mode='none', target_bus=bus, readonly=True) - msg = _("Add CD-ROM: %(target)s") % {'target': target} + instance.proxy.attach_disk(target, "", disk_device="cdrom", cache_mode="none", target_bus=bus, readonly=True) + msg = _("Add CD-ROM: %(target)s") % {"target": target} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def detach_cdrom(request, pk, dev): @@ -688,36 +700,36 @@ def detach_cdrom(request, pk, dev): if allow_admin_or_not_template: # dev = request.POST.get('detach_cdrom', '') instance.proxy.detach_disk(dev) - msg = _('Detach CD-ROM: %(dev)s') % {'dev': dev} + msg = _("Detach CD-ROM: %(dev)s") % {"dev": dev} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def unmount_iso(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - image = request.POST.get('path', '') - dev = request.POST.get('umount_iso', '') + image = request.POST.get("path", "") + dev = request.POST.get("umount_iso", "") instance.proxy.umount_iso(dev, image) - msg = _("Mount media: %(dev)s") % {'dev': dev} + msg = _("Mount media: %(dev)s") % {"dev": dev} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def mount_iso(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - image = request.POST.get('media', '') - dev = request.POST.get('mount_iso', '') + image = request.POST.get("media", "") + dev = request.POST.get("mount_iso", "") instance.proxy.mount_iso(dev, image) - msg = _("Unmount media: %(dev)s") % {'dev': dev} + msg = _("Unmount media: %(dev)s") % {"dev": dev} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#disks') + return redirect(request.META.get("HTTP_REFERER") + "#disks") def snapshot(request, pk): @@ -725,63 +737,60 @@ def snapshot(request, pk): allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - name = request.POST.get('name', '') + name = request.POST.get("name", "") instance.proxy.create_snapshot(name) - msg = _("New snapshot: %(name)s") % {'name': name} + msg = _("Create snapshot: %(snap)s") % {"snap": name} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#managesnapshot') + return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot") def delete_snapshot(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - snap_name = request.POST.get('name', '') + snap_name = request.POST.get("name", "") instance.proxy.snapshot_delete(snap_name) - msg = _("Delete snapshot: %(snap_name)s") % {'snap_name': snap_name} + msg = _("Delete snapshot: %(snap)s") % {"snap": snap_name} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#managesnapshot') + return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot") def revert_snapshot(request, pk): instance = get_instance(request.user, pk) allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template if allow_admin_or_not_template: - snap_name = request.POST.get('name', '') + snap_name = request.POST.get("name", "") instance.proxy.snapshot_revert(snap_name) msg = _("Successful revert snapshot: ") msg += snap_name messages.success(request, msg) - msg = _("Revert snapshot") + msg = _("Revert snapshot: %(snap)") % {"snap": snap_name} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#managesnapshot') + return redirect(request.META.get("HTTP_REFERER") + "#managesnapshot") @superuser_only def set_vcpu(request, pk): instance = get_instance(request.user, pk) - id = request.POST.get('id', '') - enabled = request.POST.get('set_vcpu', '') - if enabled == 'True': + id = request.POST.get("id", "") + enabled = request.POST.get("set_vcpu", "") + if enabled == "True": instance.proxy.set_vcpu(id, 1) else: instance.proxy.set_vcpu(id, 0) - msg = _("VCPU %(id)s is enabled=%(enabled)s") % {'id': id, 'enabled': enabled} - messages.success(request, msg) + msg = _("VCPU %(id)s is enabled=%(enabled)s") % {"id": id, "enabled": enabled} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#resize') + return redirect(request.META.get("HTTP_REFERER") + "#resize") @superuser_only def set_vcpu_hotplug(request, pk): instance = get_instance(request.user, pk) - status = request.POST.get('vcpu_hotplug', '') - # TODO: f strings are not translatable https://code.djangoproject.com/ticket/29174 - msg = _("VCPU Hot-plug is enabled=%(status)s") % {'status': status} + status = request.POST.get("vcpu_hotplug", "") + msg = _("VCPU Hot-plug is enabled=%(status)s") % {"status": status} instance.proxy.set_vcpu_hotplug(eval(status)) - messages.success(request, msg) addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#resize') + return redirect(request.META.get("HTTP_REFERER") + "#resize") @superuser_only @@ -790,7 +799,7 @@ def set_autostart(request, pk): instance.proxy.set_autostart(1) msg = _("Set autostart") addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#boot_opt') + return redirect(request.META.get("HTTP_REFERER") + "#boot_opt") @superuser_only @@ -799,7 +808,7 @@ def unset_autostart(request, pk): instance.proxy.set_autostart(0) msg = _("Unset autostart") addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#boot_opt') + return redirect(request.META.get("HTTP_REFERER") + "#boot_opt") @superuser_only @@ -808,7 +817,7 @@ def set_bootmenu(request, pk): instance.proxy.set_bootmenu(1) msg = _("Enable boot menu") addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#boot_opt') + return redirect(request.META.get("HTTP_REFERER") + "#boot_opt") @superuser_only @@ -817,62 +826,65 @@ def unset_bootmenu(request, pk): instance.proxy.set_bootmenu(0) msg = _("Disable boot menu") addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#boot_opt') + return redirect(request.META.get("HTTP_REFERER") + "#boot_opt") @superuser_only def set_bootorder(request, pk): instance = get_instance(request.user, pk) - bootorder = request.POST.get('bootorder', '') + bootorder = request.POST.get("bootorder", "") if bootorder: order_list = {} - for idx, val in enumerate(bootorder.split(',')): - dev_type, dev = val.split(':', 1) + for idx, val in enumerate(bootorder.split(",")): + dev_type, dev = val.split(":", 1) order_list[idx] = {"type": dev_type, "dev": dev} instance.proxy.set_bootorder(order_list) msg = _("Set boot order") if not instance.proxy.get_status() == 5: - messages.success(request, _("Boot menu changes applied. " + "But it will be activated after shutdown")) + messages.success( + request, + _("Boot menu changes applied. " + "But it will be activated after shutdown"), + ) else: messages.success(request, _("Boot order changed successfully.")) addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#boot_opt') + return redirect(request.META.get("HTTP_REFERER") + "#boot_opt") @superuser_only def change_xml(request, pk): instance = get_instance(request.user, pk) - exit_xml = request.POST.get('inst_xml', '') - if exit_xml: - instance.proxy._defineXML(exit_xml) - msg = _("Edit XML") + new_xml = request.POST.get("inst_xml", "") + if new_xml: + instance.proxy._defineXML(new_xml) + msg = _("Change instance XML") addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#xmledit') + return redirect(request.META.get("HTTP_REFERER") + "#xmledit") @superuser_only def set_guest_agent(request, pk): instance = get_instance(request.user, pk) - status = request.POST.get('guest_agent') - if status == 'True': + status = request.POST.get("guest_agent") + if status == "True": instance.proxy.add_guest_agent() - if status == 'False': + if status == "False": instance.proxy.remove_guest_agent() - msg = _("Set Guest Agent %(status)s") % {'status': status} + msg = _("Set Guest Agent: %(status)s") % {"status": status} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#options') + return redirect(request.META.get("HTTP_REFERER") + "#options") @superuser_only def set_video_model(request, pk): instance = get_instance(request.user, pk) - video_model = request.POST.get('video_model', 'vga') + video_model = request.POST.get("video_model", "vga") instance.proxy.set_video_model(video_model) - msg = _("Set Video Model") + msg = _("Set Video Model: %(model)") % {"model": video_model} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#options') + return redirect(request.META.get("HTTP_REFERER") + "#options") @superuser_only @@ -883,107 +895,117 @@ def change_network(request, pk): network_data = {} for post in request.POST: - if post.startswith('net-source-'): + if post.startswith("net-source-"): (source, source_type) = utils.get_network_tuple(request.POST.get(post)) network_data[post] = source - network_data[post + '-type'] = source_type - elif post.startswith('net-'): - network_data[post] = request.POST.get(post, '') + network_data[post + "-type"] = source_type + elif post.startswith("net-"): + network_data[post] = request.POST.get(post, "") instance.proxy.change_network(network_data) addlogmsg(request.user.username, instance.name, msg) msg = _("Network Device Config is changed. Please shutdown instance to activate.") - if instance.proxy.get_status() != 5: messages.success(request, msg) - return redirect(request.META.get('HTTP_REFERER') + '#network') + if instance.proxy.get_status() != 5: + messages.success(request, msg) + return redirect(request.META.get("HTTP_REFERER") + "#network") @superuser_only def add_network(request, pk): instance = get_instance(request.user, pk) - msg = _("Add network") - mac = request.POST.get('add-net-mac') - nwfilter = request.POST.get('add-net-nwfilter') - (source, source_type) = utils.get_network_tuple(request.POST.get('add-net-network')) + + mac = request.POST.get("add-net-mac") + nwfilter = request.POST.get("add-net-nwfilter") + (source, source_type) = utils.get_network_tuple(request.POST.get("add-net-network")) instance.proxy.add_network(mac, source, source_type, nwfilter=nwfilter) + msg = _("Add network: %(mac)s") % {"mac": mac} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#network') + return redirect(request.META.get("HTTP_REFERER") + "#network") @superuser_only def delete_network(request, pk): instance = get_instance(request.user, pk) - - msg = _("Delete network") - mac_address = request.POST.get('delete_network', '') + mac_address = request.POST.get("delete_network", "") instance.proxy.delete_network(mac_address) + msg = _("Delete Network: %(mac)s") % {"mac": mac_address} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#network') + return redirect(request.META.get("HTTP_REFERER") + "#network") @superuser_only def set_link_state(request, pk): instance = get_instance(request.user, pk) - mac_address = request.POST.get('mac', '') - state = request.POST.get('set_link_state') - state = 'down' if state == 'up' else 'up' + mac_address = request.POST.get("mac", "") + state = request.POST.get("set_link_state") + state = "down" if state == "up" else "up" instance.proxy.set_link_state(mac_address, state) - msg = _("Set Link State: %(state)s") % {'state': state} + msg = _("Set Link State: %(state)s") % {"state": state} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#network') + return redirect(request.META.get("HTTP_REFERER") + "#network") @superuser_only def set_qos(request, pk): instance = get_instance(request.user, pk) - 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 + 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 keys = request.POST.keys() - mac_key = [key for key in keys if 'mac' in key] - if mac_key: mac = request.POST.get(mac_key[0]) + mac_key = [key for key in keys if "mac" in key] + if mac_key: + mac = request.POST.get(mac_key[0]) instance.proxy.set_qos(mac, qos_dir, average, peak, burst) if instance.proxy.get_status() == 5: - messages.success(request, _("%(qos_dir)s QoS is set") % {'qos_dir': qos_dir.capitalize()}) + messages.success(request, _("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()}) else: messages.success( request, - _("%(qos_dir)s QoS is set. Network XML is changed. \ - Stop and start network to activate new config.") % {'qos_dir': qos_dir.capitalize()}) + _( + "%(qos_dir)s QoS is set. Network XML is changed. \ + Stop and start network to activate new config." + ) + % {"qos_dir": qos_dir.capitalize()}, + ) - return redirect(request.META.get('HTTP_REFERER') + '#network') + return redirect(request.META.get("HTTP_REFERER") + "#network") @superuser_only def unset_qos(request, pk): instance = get_instance(request.user, pk) - qos_dir = request.POST.get('qos_direction', '') - mac = request.POST.get('net-mac') + qos_dir = request.POST.get("qos_direction", "") + mac = request.POST.get("net-mac") instance.proxy.unset_qos(mac, qos_dir) if instance.proxy.get_status() == 5: - messages.success(request, _("%(qos_dir)s QoS is deleted") % {'qos_dir': qos_dir.capitalize()}) + messages.success(request, _("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()}) else: messages.success( request, - _("%(qos_dir)s QoS is deleted. Network XML is changed. \ - Stop and start network to activate new config.") % {'qos_dir': qos_dir.capitalize()}) - return redirect(request.META.get('HTTP_REFERER') + '#network') + _( + "%(qos_dir)s QoS is deleted. Network XML is changed. \ + Stop and start network to activate new config." + ) + % {"qos_dir": qos_dir.capitalize()}, + ) + return redirect(request.META.get("HTTP_REFERER") + "#network") @superuser_only def add_owner(request, pk): instance = get_instance(request.user, pk) - user_id = request.POST.get('user_id') + user_id = request.POST.get("user_id") check_inst = 0 - if app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER == 'False': + if app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER == "False": check_inst = UserInstance.objects.filter(instance=instance).count() if check_inst > 0: @@ -992,43 +1014,43 @@ def add_owner(request, pk): add_user_inst = UserInstance(instance=instance, user_id=user_id) add_user_inst.save() user = User.objects.get(id=user_id) - msg = _("Added owner %(user)s") % {'user': user} + msg = _("Add owner: %(user)s") % {"user": user} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#users') + return redirect(request.META.get("HTTP_REFERER") + "#users") @superuser_only def del_owner(request, pk): instance = get_instance(request.user, pk) - userinstance_id = int(request.POST.get('userinstance', '')) + userinstance_id = int(request.POST.get("userinstance", "")) userinstance = UserInstance.objects.get(pk=userinstance_id) userinstance.delete() - msg = _("Deleted owner %(userinstance_id)s") % {'userinstance_id': userinstance_id} + msg = _("Delete owner: %(userinstance_id)s ") % {"userinstance_id": userinstance_id} addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#users') + return redirect(request.META.get("HTTP_REFERER") + "#users") -@permission_required('instances.clone_instances', raise_exception=True) +@permission_required("instances.clone_instances", raise_exception=True) def clone(request, pk): instance = get_instance(request.user, pk) clone_data = dict() - clone_data['name'] = request.POST.get('name', '') + clone_data["name"] = request.POST.get("name", "") - disk_sum = sum([disk['size'] >> 30 for disk in instance.disks]) + disk_sum = sum([disk["size"] >> 30 for disk in instance.disks]) quota_msg = utils.check_user_quota(request.user, 1, instance.vcpu, instance.memory, disk_sum) - check_instance = Instance.objects.filter(name=clone_data['name']) + check_instance = Instance.objects.filter(name=clone_data["name"]) - clone_data['disk_owner_uid'] = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID) - clone_data['disk_owner_gid'] = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID) + clone_data["disk_owner_uid"] = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID) + clone_data["disk_owner_gid"] = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID) for post in request.POST: - clone_data[post] = request.POST.get(post, '').strip() + clone_data[post] = request.POST.get(post, "").strip() - if app_settings.CLONE_INSTANCE_AUTO_NAME == 'True' and not clone_data['name']: + if app_settings.CLONE_INSTANCE_AUTO_NAME == "True" and not clone_data["name"]: auto_vname = utils.get_clone_free_names()[0] - clone_data['name'] = auto_vname - clone_data['clone-net-mac-0'] = utils.get_dhcp_mac_address(auto_vname) + clone_data["name"] = auto_vname + clone_data["clone-net-mac-0"] = utils.get_dhcp_mac_address(auto_vname) for disk in instance.disks: disk_dev = f"disk-{disk['dev']}" disk_name = utils.get_clone_disk_name(disk, instance.name, auto_vname) @@ -1036,107 +1058,116 @@ def clone(request, pk): if not request.user.is_superuser and quota_msg: msg = _("User '%(quota_msg)s' quota reached, cannot create '%(clone_name)s'!") % { - 'quota_msg': quota_msg, - 'clone_name': clone_data['name'], + "quota_msg": quota_msg, + "clone_name": clone_data["name"], } messages.error(request, msg) elif check_instance: - msg = _("Instance '%(clone_name)s' already exists!") % {'clone_name': clone_data['name']} + msg = _("Instance '%(clone_name)s' already exists!") % {"clone_name": clone_data["name"]} messages.error(request, msg) - elif not re.match(r'^[a-zA-Z0-9-]+$', clone_data['name']): - msg = _("Instance name '%(clone_name)s' contains invalid characters!") % {'clone_name': clone_data['name']} + elif not re.match(r"^[a-zA-Z0-9-]+$", clone_data["name"]): + msg = _("Instance name '%(clone_name)s' contains invalid characters!") % {"clone_name": clone_data["name"]} messages.error(request, msg) - elif not re.match(r'^([0-9A-F]{2})(:?[0-9A-F]{2}){5}$', clone_data['clone-net-mac-0'], re.IGNORECASE): - msg = _("Instance MAC '%(clone_mac)s' invalid format!") % {'clone_mac': clone_data['clone-net-mac-0']} + elif not re.match(r"^([0-9A-F]{2})(:?[0-9A-F]{2}){5}$", clone_data["clone-net-mac-0"], re.IGNORECASE): + msg = _("Instance MAC '%(clone_mac)s' invalid format!") % {"clone_mac": clone_data["clone-net-mac-0"]} messages.error(request, msg) else: - new_instance = Instance(compute=instance.compute, name=clone_data['name']) + new_instance = Instance(compute=instance.compute, name=clone_data["name"]) try: new_uuid = instance.proxy.clone_instance(clone_data) new_instance.uuid = new_uuid new_instance.save() user_instance = UserInstance(instance_id=new_instance.id, user_id=request.user.id, is_delete=True) user_instance.save() - msg = _("Clone of '%(instance_name)s'") % {'instance_name': instance.name} + msg = _("Create a clone of '%(instance_name)s'") % {"instance_name": instance.name} + messages.success(request, msg) addlogmsg(request.user.username, new_instance.name, msg) - if app_settings.CLONE_INSTANCE_AUTO_MIGRATE == 'True': - new_compute = Compute.objects.order_by('?').first() + if app_settings.CLONE_INSTANCE_AUTO_MIGRATE == "True": + new_compute = Compute.objects.order_by("?").first() utils.migrate_instance(new_compute, new_instance, request.user, xml_del=True, offline=True) - return redirect(reverse('instances:instance', args=[new_instance.id])) + return redirect(reverse("instances:instance", args=[new_instance.id])) except Exception as e: messages.error(request, e) - return redirect(request.META.get('HTTP_REFERER') + '#clone') + return redirect(request.META.get("HTTP_REFERER") + "#clone") def update_console(request, pk): instance = get_instance(request.user, pk) try: userinstance = instance.userinstance_set.get(user=request.user) - except: + except Exception: userinstance = UserInstance(is_vnc=False) if request.user.is_superuser or request.user.is_staff or userinstance.is_vnc: form = ConsoleForm(request.POST or None) if form.is_valid(): - if 'generate_password' in form.changed_data or 'clear_password' in form.changed_data or 'password' in form.changed_data: - if form.cleaned_data['generate_password']: + if ( + "generate_password" in form.changed_data + or "clear_password" in form.changed_data + or "password" in form.changed_data + ): + if form.cleaned_data["generate_password"]: password = randomPasswd() - elif form.cleaned_data['clear_password']: - password = '' + elif form.cleaned_data["clear_password"]: + password = "" else: - password = form.cleaned_data['password'] + password = form.cleaned_data["password"] if not instance.proxy.set_console_passwd(password): - msg = _("Error setting console password. " + "You should check that your instance have an graphic device.") + msg = _( + "Error setting console password. " + + "You should check that your instance have an graphic device." + ) messages.error(request, msg) else: msg = _("Set VNC password") addlogmsg(request.user.username, instance.name, msg) - if 'keymap' in form.changed_data or 'clear_keymap' in form.changed_data: - if form.cleaned_data['clear_keymap']: - instance.proxy.set_console_keymap('') + if "keymap" in form.changed_data or "clear_keymap" in form.changed_data: + if form.cleaned_data["clear_keymap"]: + instance.proxy.set_console_keymap("") else: - instance.proxy.set_console_keymap(form.cleaned_data['keymap']) + instance.proxy.set_console_keymap(form.cleaned_data["keymap"]) + msg = _("Set VNC keymap") addlogmsg(request.user.username, instance.name, msg) - if 'type' in form.changed_data: - instance.proxy.set_console_type(form.cleaned_data['type']) + if "type" in form.changed_data: + instance.proxy.set_console_type(form.cleaned_data["type"]) msg = _("Set VNC type") addlogmsg(request.user.username, instance.name, msg) - if 'listen_on' in form.changed_data: - instance.proxy.set_console_listen_addr(form.cleaned_data['listen_on']) + if "listen_on" in form.changed_data: + instance.proxy.set_console_listen_addr(form.cleaned_data["listen_on"]) msg = _("Set VNC listen address") addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#vncsettings') + return redirect(request.META.get("HTTP_REFERER") + "#vncsettings") def change_options(request, pk): instance = get_instance(request.user, pk) try: userinstance = instance.userinstance_set.get(user=request.user) - except: + except Exception: userinstance = UserInstance(is_change=False) if request.user.is_superuser or request.user.is_staff or userinstance.is_change: - instance.is_template = request.POST.get('is_template', False) + instance.is_template = request.POST.get("is_template", False) instance.save() options = {} for post in request.POST: - if post in ['title', 'description']: - options[post] = request.POST.get(post, '') + if post in ["title", "description"]: + options[post] = request.POST.get(post, "") instance.proxy.set_options(options) msg = _("Edit options") addlogmsg(request.user.username, instance.name, msg) - return redirect(request.META.get('HTTP_REFERER') + '#options') + return redirect(request.META.get("HTTP_REFERER") + "#options") def getvvfile(request, pk): @@ -1150,23 +1181,29 @@ def getvvfile(request, pk): msg = _("Send console.vv file") addlogmsg(request.user.username, instance.name, msg) - response = HttpResponse(content='', content_type='application/x-virt-viewer', status=200, reason=None, charset='utf-8') - response.writelines('[virt-viewer]\n') - response.writelines('type=' + conn.graphics_type(instance.name) + '\n') - if conn.graphics_listen(instance.name) == '0.0.0.0': - response.writelines('host=' + conn.host + '\n') + response = HttpResponse( + content="", + content_type="application/x-virt-viewer", + status=200, + reason=None, + charset="utf-8", + ) + response.writelines("[virt-viewer]\n") + response.writelines("type=" + conn.graphics_type(instance.name) + "\n") + if conn.graphics_listen(instance.name) == "0.0.0.0": + response.writelines("host=" + conn.host + "\n") else: - response.writelines('host=' + conn.graphics_listen(instance.name) + '\n') - response.writelines('port=' + conn.graphics_port(instance.name) + '\n') - response.writelines('title=' + conn.domain_name(instance.name) + '\n') - response.writelines('password=' + conn.graphics_passwd(instance.name) + '\n') - response.writelines('enable-usbredir=1\n') - response.writelines('disable-effects=all\n') - response.writelines('secure-attention=ctrl+alt+ins\n') - response.writelines('release-cursor=ctrl+alt\n') - response.writelines('fullscreen=1\n') - response.writelines('delete-this-file=1\n') - response['Content-Disposition'] = 'attachment; filename="console.vv"' + response.writelines("host=" + conn.graphics_listen(instance.name) + "\n") + response.writelines("port=" + conn.graphics_port(instance.name) + "\n") + response.writelines("title=" + conn.domain_name(instance.name) + "\n") + response.writelines("password=" + conn.graphics_passwd(instance.name) + "\n") + response.writelines("enable-usbredir=1\n") + response.writelines("disable-effects=all\n") + response.writelines("secure-attention=ctrl+alt+ins\n") + response.writelines("release-cursor=ctrl+alt\n") + response.writelines("fullscreen=1\n") + response.writelines("delete-this-file=1\n") + response["Content-Disposition"] = 'attachment; filename="console.vv"' return response @@ -1195,12 +1232,12 @@ def create_instance_select_type(request, compute_id): default_machine = app_settings.INSTANCE_MACHINE_DEFAULT_TYPE default_arch = app_settings.INSTANCE_ARCH_DEFAULT_TYPE - if request.method == 'POST': - if 'create_xml' in request.POST: - xml = request.POST.get('dom_xml', '') + if request.method == "POST": + if "create_xml" in request.POST: + xml = request.POST.get("dom_xml", "") try: - name = util.get_xml_path(xml, '/domain/name') - except util.etree.Error as err: + name = util.get_xml_path(xml, "/domain/name") + except util.etree.Error: name = None if name in instances: error_msg = _("A virtual machine with this name already exists") @@ -1209,9 +1246,9 @@ def create_instance_select_type(request, compute_id): conn._defineXML(xml) utils.refr(compute) instance = compute.instance_set.get(name=name) - return redirect(reverse('instances:instance', args=[instance.id])) + return redirect(reverse("instances:instance", args=[instance.id])) - return render(request, 'create_instance_w1.html', locals()) + return render(request, "create_instance_w1.html", locals()) @superuser_only @@ -1231,7 +1268,7 @@ def create_instance(request, compute_id, arch, machine): firmwares = list() meta_prealloc = False compute = get_object_or_404(Compute, pk=compute_id) - flavors = Flavor.objects.filter().order_by('id') + flavors = Flavor.objects.filter().order_by("id") appsettings = AppSettings.objects.all() try: @@ -1267,11 +1304,13 @@ def create_instance(request, compute_id, arch, machine): hv_supports_uefi = conn.supports_uefi_xml(dom_caps["loader_enums"]) # Add BIOS label = conn.label_for_firmware_path(arch, None) - if label: firmwares.append(label) + if label: + firmwares.append(label) # Add UEFI loader_path = conn.find_uefi_path_for_arch(arch, dom_caps["loaders"]) label = conn.label_for_firmware_path(arch, loader_path) - if label: firmwares.append(label) + if label: + firmwares.append(label) firmwares = list(set(firmwares)) flavor_form = FlavorForm() @@ -1282,8 +1321,8 @@ def create_instance(request, compute_id, arch, machine): if not networks: raise libvirtError(_("You haven't defined any network pools")) - if request.method == 'POST': - if 'create' in request.POST: + if request.method == "POST": + if "create" in request.POST: firmware = dict() volume_list = list() is_disk_created = False @@ -1291,128 +1330,147 @@ def create_instance(request, compute_id, arch, machine): form = NewVMForm(request.POST) if form.is_valid(): data = form.cleaned_data - if data['meta_prealloc']: + if data["meta_prealloc"]: meta_prealloc = True if instances: - if data['name'] in instances: + if data["name"] in instances: raise libvirtError(_("A virtual machine with this name already exists")) - if Instance.objects.filter(name__exact=data['name']): + if Instance.objects.filter(name__exact=data["name"]): raise libvirtError(_("There is an instance with same name. Remove it and try again!")) - if data['hdd_size']: - if not data['mac']: + if data["hdd_size"]: + if not data["mac"]: raise libvirtError(_("No Virtual Machine MAC has been entered")) else: - path = conn.create_volume(data['storage'], data['name'], data['hdd_size'], default_disk_format, - meta_prealloc, default_disk_owner_uid, default_disk_owner_gid) + path = conn.create_volume( + data["storage"], + data["name"], + data["hdd_size"], + default_disk_format, + meta_prealloc, + default_disk_owner_uid, + default_disk_owner_gid, + ) volume = dict() - volume['device'] = 'disk' - volume['path'] = path - volume['type'] = conn.get_volume_type(path) - volume['cache_mode'] = data['cache_mode'] - volume['bus'] = default_bus - if volume['bus'] == 'scsi': - volume['scsi_model'] = default_scsi_disk_model - volume['discard_mode'] = default_discard - volume['detect_zeroes_mode'] = default_zeroes - volume['io_mode'] = default_io + volume["device"] = "disk" + volume["path"] = path + volume["type"] = conn.get_volume_type(path) + volume["cache_mode"] = data["cache_mode"] + volume["bus"] = default_bus + if volume["bus"] == "scsi": + volume["scsi_model"] = default_scsi_disk_model + volume["discard_mode"] = default_discard + volume["detect_zeroes_mode"] = default_zeroes + volume["io_mode"] = default_io volume_list.append(volume) is_disk_created = True - elif data['template']: - templ_path = conn.get_volume_path(data['template']) - dest_vol = conn.get_volume_path(data["name"] + ".img", data['storage']) + elif data["template"]: + templ_path = conn.get_volume_path(data["template"]) + dest_vol = conn.get_volume_path(data["name"] + ".img", data["storage"]) if dest_vol: - raise libvirtError(_("Image has already exist. Please check volumes or change instance name")) + raise libvirtError( + _("Image has already exist. Please check volumes or change instance name") + ) else: - clone_path = conn.clone_from_template(data['name'], templ_path, data['storage'], meta_prealloc, - default_disk_owner_uid, default_disk_owner_gid) + clone_path = conn.clone_from_template( + data["name"], + templ_path, + data["storage"], + meta_prealloc, + default_disk_owner_uid, + default_disk_owner_gid, + ) volume = dict() - volume['path'] = clone_path - volume['type'] = conn.get_volume_type(clone_path) - volume['device'] = 'disk' - volume['cache_mode'] = data['cache_mode'] - volume['bus'] = default_bus - if volume['bus'] == 'scsi': - volume['scsi_model'] = default_scsi_disk_model - volume['discard_mode'] = default_discard - volume['detect_zeroes_mode'] = default_zeroes - volume['io_mode'] = default_io + volume["path"] = clone_path + volume["type"] = conn.get_volume_type(clone_path) + volume["device"] = "disk" + volume["cache_mode"] = data["cache_mode"] + volume["bus"] = default_bus + if volume["bus"] == "scsi": + volume["scsi_model"] = default_scsi_disk_model + volume["discard_mode"] = default_discard + volume["detect_zeroes_mode"] = default_zeroes + volume["io_mode"] = default_io volume_list.append(volume) is_disk_created = True else: - if not data['images']: + if not data["images"]: raise libvirtError(_("First you need to create or select an image")) else: - for idx, vol in enumerate(data['images'].split(',')): + for idx, vol in enumerate(data["images"].split(",")): path = conn.get_volume_path(vol) volume = dict() - volume['path'] = path - volume['type'] = conn.get_volume_type(path) - volume['device'] = request.POST.get('device' + str(idx), '') - volume['bus'] = request.POST.get('bus' + str(idx), '') - if volume['bus'] == 'scsi': - volume['scsi_model'] = default_scsi_disk_model - volume['cache_mode'] = data['cache_mode'] - volume['discard_mode'] = default_discard - volume['detect_zeroes_mode'] = default_zeroes - volume['io_mode'] = default_io + volume["path"] = path + volume["type"] = conn.get_volume_type(path) + volume["device"] = request.POST.get("device" + str(idx), "") + volume["bus"] = request.POST.get("bus" + str(idx), "") + if volume["bus"] == "scsi": + volume["scsi_model"] = default_scsi_disk_model + volume["cache_mode"] = data["cache_mode"] + volume["discard_mode"] = default_discard + volume["detect_zeroes_mode"] = default_zeroes + volume["io_mode"] = default_io volume_list.append(volume) - if data['cache_mode'] not in conn.get_cache_modes(): + if data["cache_mode"] not in conn.get_cache_modes(): error_msg = _("Invalid cache mode") raise libvirtError - if 'UEFI' in data["firmware"]: + if "UEFI" in data["firmware"]: firmware["loader"] = data["firmware"].split(":")[1].strip() - firmware["secure"] = 'no' - firmware["readonly"] = 'yes' - firmware["type"] = 'pflash' - if 'secboot' in firmware["loader"] and machine != 'q35': + firmware["secure"] = "no" + firmware["readonly"] = "yes" + firmware["type"] = "pflash" + if "secboot" in firmware["loader"] and machine != "q35": messages.warning( - request, "Changing machine type from '%s' to 'q35' " - "which is required for UEFI secure boot." % machine) - machine = 'q35' - firmware["secure"] = 'yes' + request, + "Changing machine type from '%s' to 'q35' " + "which is required for UEFI secure boot." % machine, + ) + machine = "q35" + firmware["secure"] = "yes" uuid = util.randomUUID() try: - conn.create_instance(name=data['name'], - memory=data['memory'], - vcpu=data['vcpu'], - vcpu_mode=data['vcpu_mode'], - uuid=uuid, - arch=arch, - machine=machine, - firmware=firmware, - volumes=volume_list, - networks=data['networks'], - virtio=data['virtio'], - listen_addr=data["listener_addr"], - nwfilter=data["nwfilter"], - graphics=data["graphics"], - video=data["video"], - console_pass=data["console_pass"], - mac=data['mac'], - qemu_ga=data['qemu_ga']) - create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid) + conn.create_instance( + name=data["name"], + memory=data["memory"], + vcpu=data["vcpu"], + vcpu_mode=data["vcpu_mode"], + uuid=uuid, + arch=arch, + machine=machine, + firmware=firmware, + volumes=volume_list, + networks=data["networks"], + virtio=data["virtio"], + listen_addr=data["listener_addr"], + nwfilter=data["nwfilter"], + graphics=data["graphics"], + video=data["video"], + console_pass=data["console_pass"], + mac=data["mac"], + qemu_ga=data["qemu_ga"], + ) + create_instance = Instance(compute_id=compute_id, name=data["name"], uuid=uuid) create_instance.save() msg = _("Instance is created") messages.success(request, msg) addlogmsg(request.user.username, create_instance.name, msg) - return redirect(reverse('instances:instance', args=[create_instance.id])) + return redirect(reverse("instances:instance", args=[create_instance.id])) except libvirtError as lib_err: - if data['hdd_size'] or len(volume_list) > 0: + if data["hdd_size"] or len(volume_list) > 0: if is_disk_created: for vol in volume_list: - conn.delete_volume(vol['path']) + conn.delete_volume(vol["path"]) messages.error(request, lib_err) conn.close() except libvirtError as lib_err: messages.error(request, lib_err) - return render(request, 'create_instance_w2.html', locals()) + return render(request, "create_instance_w2.html", locals()) @superuser_only @@ -1420,16 +1478,13 @@ def flavor_create(request): form = FlavorForm(request.POST or None) if form.is_valid(): form.save() - messages.success(request, _('Flavor Created')) - return redirect(request.META.get('HTTP_REFERER')) + messages.success(request, _("Flavor Created")) + return redirect(request.META.get("HTTP_REFERER")) return render( request, - 'common/form.html', - { - 'form': form, - 'title': _('Create Flavor') - }, + "common/form.html", + {"form": form, "title": _("Create Flavor")}, ) @@ -1439,29 +1494,26 @@ def flavor_update(request, pk): form = FlavorForm(request.POST or None, instance=flavor) if form.is_valid(): form.save() - messages.success(request, _('Flavor Updated')) - return redirect(request.META.get('HTTP_REFERER')) + messages.success(request, _("Flavor Updated")) + return redirect(request.META.get("HTTP_REFERER")) return render( request, - 'common/form.html', - { - 'form': form, - 'title': _('Update Flavor') - }, + "common/form.html", + {"form": form, "title": _("Update Flavor")}, ) @superuser_only def flavor_delete(request, pk): flavor = get_object_or_404(Flavor, pk=pk) - if request.method == 'POST': + if request.method == "POST": flavor.delete() - messages.success(request, _('Flavor Deleted')) - return redirect(request.META.get('HTTP_REFERER')) + messages.success(request, _("Flavor Deleted")) + return redirect(request.META.get("HTTP_REFERER")) return render( request, - 'common/confirm_delete.html', - {'object': flavor}, + "common/confirm_delete.html", + {"object": flavor}, ) diff --git a/interfaces/forms.py b/interfaces/forms.py index 4490d0b..c19ffda 100644 --- a/interfaces/forms.py +++ b/interfaces/forms.py @@ -1,4 +1,5 @@ import re + from django import forms from django.utils.translation import gettext_lazy as _ diff --git a/interfaces/views.py b/interfaces/views.py index 7a12a38..a6f8c0b 100644 --- a/interfaces/views.py +++ b/interfaces/views.py @@ -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()) diff --git a/logs/models.py b/logs/models.py index d45c056..ad9946b 100644 --- a/logs/models.py +++ b/logs/models.py @@ -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 diff --git a/logs/urls.py b/logs/urls.py index 41618ae..2e8ca5a 100644 --- a/logs/urls.py +++ b/logs/urls.py @@ -1,6 +1,7 @@ from django.urls import path + from . import views urlpatterns = [ - path('vm_logs//', views.vm_logs, name='vm_logs'), + path("vm_logs//", views.vm_logs, name="vm_logs"), ] diff --git a/logs/views.py b/logs/views.py index 7e98221..0f94940 100644 --- a/logs/views.py +++ b/logs/views.py @@ -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)) diff --git a/networks/forms.py b/networks/forms.py index 6b9189f..36ceed9 100644 --- a/networks/forms.py +++ b/networks/forms.py @@ -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 diff --git a/networks/views.py b/networks/views.py index aade157..f40a395 100644 --- a/networks/views.py +++ b/networks/views.py @@ -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()) diff --git a/nwfilters/apps.py b/nwfilters/apps.py index 11475c5..496ed18 100644 --- a/nwfilters/apps.py +++ b/nwfilters/apps.py @@ -5,4 +5,4 @@ from django.apps import AppConfig class NwfiltersConfig(AppConfig): - name = 'nwfilters' + name = "nwfilters" diff --git a/nwfilters/views.py b/nwfilters/views.py index 3ac9407..7cb690d 100644 --- a/nwfilters/views.py +++ b/nwfilters/views.py @@ -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()) diff --git a/secrets/views.py b/secrets/views.py index 3788d87..3bcee54 100644 --- a/secrets/views.py +++ b/secrets/views.py @@ -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()) diff --git a/storages/forms.py b/storages/forms.py index f2fd89b..64dcd3c 100644 --- a/storages/forms.py +++ b/storages/forms.py @@ -1,4 +1,5 @@ import re + from django import forms from django.utils.translation import gettext_lazy as _ diff --git a/storages/views.py b/storages/views.py index b3ee0b1..1934237 100644 --- a/storages/views.py +++ b/storages/views.py @@ -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)) diff --git a/vrtManager/IPy.py b/vrtManager/IPy.py index b157f3d..163010b 100644 --- a/vrtManager/IPy.py +++ b/vrtManager/IPy.py @@ -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]]) diff --git a/vrtManager/connection.py b/vrtManager/connection.py index 4ac9f4f..0272353 100644 --- a/vrtManager/connection.py +++ b/vrtManager/connection.py @@ -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'' + return f"" 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"]: diff --git a/vrtManager/create.py b/vrtManager/create.py index 641715c..9cdaca4 100644 --- a/vrtManager/create.py +++ b/vrtManager/create.py @@ -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} {vcpu}""" - if dom_caps["os_support"] == 'yes': + if dom_caps["os_support"] == "yes": xml += f""" {caps["os_type"]}""" xml += """ """ if firmware: - if firmware["secure"] == 'yes': - xml += """%s""" % (firmware["readonly"], - firmware["type"], - firmware["secure"], - firmware["loader"]) - if firmware["secure"] == 'no': - xml += """%s""" % (firmware["readonly"], - firmware["type"], - firmware["loader"]) + if firmware["secure"] == "yes": + xml += """%s""" % ( + firmware["readonly"], + firmware["type"], + firmware["secure"], + firmware["loader"], + ) + if firmware["secure"] == "no": + xml += """%s""" % ( + firmware["readonly"], + firmware["type"], + firmware["loader"], + ) xml += """""" if caps["features"]: xml += """""" - if 'acpi' in caps["features"]: + if "acpi" in caps["features"]: xml += """""" - if 'apic' in caps["features"]: + if "apic" in caps["features"]: xml += """""" - if 'pae' in caps["features"]: + if "pae" in caps["features"]: xml += """""" - if firmware.get("secure", 'no') == 'yes': + if firmware.get("secure", "no") == "yes": xml += """""" xml += """""" @@ -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 += """ - """ % (volume['type'], disk_opts) + """ % ( + volume["type"], + disk_opts, + ) xml += """ - """ % (ceph_user, secret_uuid, volume['path']) + """ % ( + 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.get('name'), host.get('port')) + """ % ( + host.get("name"), + host.get("port"), + ) else: xml += """ - """ % host.get('name') + """ % host.get( + "name" + ) xml += """""" else: - xml += """""" % volume['device'] - xml += """ """ % (volume['type'], disk_opts) - xml += f""" """ % volume['path'] + xml += """""" % volume["device"] + xml += """ """ % (volume["type"], disk_opts) + xml += """ """ % volume["path"] - if volume.get('bus') == 'virtio': - xml += """""" % (vd_disk_letters.pop(0), volume.get('bus')) - elif volume.get('bus') == 'ide': - xml += """""" % (hd_disk_letters.pop(0), volume.get('bus')) - elif volume.get('bus') == 'fdc': - xml += """""" % (fd_disk_letters.pop(0), volume.get('bus')) - elif volume.get('bus') == 'sata' or volume.get('bus') == 'scsi': - xml += """""" % (sd_disk_letters.pop(0), volume.get('bus')) + if volume.get("bus") == "virtio": + xml += """""" % (vd_disk_letters.pop(0), volume.get("bus")) + elif volume.get("bus") == "ide": + xml += """""" % (hd_disk_letters.pop(0), volume.get("bus")) + elif volume.get("bus") == "fdc": + xml += """""" % (fd_disk_letters.pop(0), volume.get("bus")) + elif volume.get("bus") == "sata" or volume.get("bus") == "scsi": + xml += """""" % (sd_disk_letters.pop(0), volume.get("bus")) else: xml += """""" % sd_disk_letters.pop(0) xml += """""" - if volume.get('bus') == 'scsi': + if volume.get("bus") == "scsi": xml += f"""""" if add_cd: @@ -292,17 +328,17 @@ class wvmCreate(wvmConnect): """ - if 'ide' in dom_caps['disk_bus']: - xml += """""" % (hd_disk_letters.pop(0), 'ide') - elif 'sata' in dom_caps['disk_bus']: - xml += """""" % (sd_disk_letters.pop(0), 'sata') - elif 'scsi' in dom_caps['disk_bus']: - xml += """""" % (sd_disk_letters.pop(0), 'scsi') + if "ide" in dom_caps["disk_bus"]: + xml += """""" % (hd_disk_letters.pop(0), "ide") + elif "sata" in dom_caps["disk_bus"]: + xml += """""" % (sd_disk_letters.pop(0), "sata") + elif "scsi" in dom_caps["disk_bus"]: + xml += """""" % (sd_disk_letters.pop(0), "scsi") else: - xml += """""" % (vd_disk_letters.pop(0), 'virtio') + xml += """""" % (vd_disk_letters.pop(0), "virtio") xml += """""" - for net in networks.split(','): + for net in networks.split(","): xml += """""" if mac: xml += f"""""" @@ -319,10 +355,10 @@ class wvmCreate(wvmConnect): if not console_pass == "": console_pass = "passwd='" + console_pass + "'" - if 'usb' in dom_caps['disk_bus']: - xml += """""".format('virtio' if virtio else 'usb') - xml += """""".format('virtio' if virtio else 'usb') - xml += """""".format('virtio' if virtio else 'usb') + if "usb" in dom_caps["disk_bus"]: + xml += """""".format("virtio" if virtio else "usb") + xml += """""".format("virtio" if virtio else "usb") + xml += """""".format("virtio" if virtio else "usb") else: xml += """""" xml += """""" diff --git a/vrtManager/hostdetails.py b/vrtManager/hostdetails.py index f2defa3..2996904 100644 --- a/vrtManager/hostdetails.py +++ b/vrtManager/hostdetails.py @@ -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): """ diff --git a/vrtManager/instance.py b/vrtManager/instance.py index e78b314..a3b0648 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -1,5 +1,6 @@ -import time import os.path +import time + try: from libvirt import ( libvirtError, @@ -7,9 +8,6 @@ try: VIR_DOMAIN_RUNNING, VIR_DOMAIN_AFFECT_LIVE, VIR_DOMAIN_AFFECT_CONFIG, - VIR_DOMAIN_UNDEFINE_NVRAM, - VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, - VIR_DOMAIN_START_PAUSED ) from libvirt import ( VIR_MIGRATE_LIVE, @@ -19,16 +17,18 @@ try: VIR_MIGRATE_OFFLINE, VIR_MIGRATE_COMPRESSED, VIR_MIGRATE_AUTO_CONVERGE, - VIR_MIGRATE_POSTCOPY + VIR_MIGRATE_POSTCOPY, ) from libvirt import VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT except: from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE -from xml.etree import ElementTree -from lxml import etree -from datetime import datetime from collections import OrderedDict +from datetime import datetime +from xml.etree import ElementTree + +from lxml import etree + from vrtManager import util from vrtManager.connection import wvmConnect from vrtManager.storage import wvmStorage, wvmStorages @@ -112,7 +112,7 @@ class wvmInstances(wvmConnect): dom_emulator = conn.get_dom_emulator() if dom_emulator != self.get_emulator(dom_arch): - raise libvirtError('Destination host emulator is different. Cannot be migrated') + raise libvirtError("Destination host emulator is different. Cannot be migrated") dom.migrate(self.wvm, flags, None, None, 0) @@ -192,10 +192,10 @@ class wvmInstance(wvmConnect): def get_status(self): """ - VIR_DOMAIN_NOSTATE = 0 - VIR_DOMAIN_RUNNING = 1 - VIR_DOMAIN_PAUSED = 3 - VIR_DOMAIN_SHUTOFF = 5 + VIR_DOMAIN_NOSTATE = 0 + VIR_DOMAIN_RUNNING = 1 + VIR_DOMAIN_PAUSED = 3 + VIR_DOMAIN_SHUTOFF = 5 """ return self.instance.info()[0] @@ -260,13 +260,13 @@ class wvmInstance(wvmConnect): def get_title(self): title = util.get_xml_path(self._XMLDesc(0), "/domain/title") - return title if title else '' + return title if title else "" def get_filterrefs(self): def filterrefs(ctx): result = [] - for net in ctx.xpath('/domain/devices/interface'): - filterref = net.xpath('filterref/@filter') + for net in ctx.xpath("/domain/devices/interface"): + filterref = net.xpath("filterref/@filter") if filterref: result.append(filterref[0]) return result @@ -275,7 +275,7 @@ class wvmInstance(wvmConnect): def get_description(self): description = util.get_xml_path(self._XMLDesc(0), "/domain/description") - return description if description else '' + return description if description else "" def get_max_memory(self): return self.wvm.getInfo()[1] * 1048576 @@ -306,7 +306,7 @@ class wvmInstance(wvmConnect): for addr in addrs["addrs"]: if addr["type"] == 0: ipv4.append(addr["addr"]) - elif (addr["type"] == 1 and not str(addr["addr"]).startswith("fe80")): + elif addr["type"] == 1 and not str(addr["addr"]).startswith("fe80"): ipv6.append(addr["addr"] + "/" + str(addr["prefix"])) return ipv4, ipv6 @@ -320,7 +320,7 @@ class wvmInstance(wvmConnect): ipv6.append(info["ipaddr"]) return ipv4, ipv6 - for ips in ([qemuga] + leases + [arp]): + for ips in [qemuga] + leases + [arp]: if "expirytime" in ips: ipv4, ipv6 = extract_lease(ips) else: @@ -333,7 +333,7 @@ class wvmInstance(wvmConnect): # ("Calling interfaceAddresses source=%s", source) try: return self.instance.interfaceAddresses(source) - except libvirtError as e: + except libvirtError: # log.debug("interfaceAddresses failed: %s", str(e)) pass return {} @@ -354,44 +354,46 @@ class wvmInstance(wvmConnect): def networks(ctx): result = [] inbound = outbound = [] - for net in ctx.xpath('/domain/devices/interface'): - interface_type = net.xpath('@type')[0] - mac_inst = net.xpath('mac/@address')[0] - nic_inst = net.xpath('source/@network|source/@bridge|source/@dev')[0] - target_inst = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0] - link_state = 'up' if not net.xpath('link') else net.xpath('link/@state')[0] - filterref_inst = '' if not net.xpath('filterref/@filter') else net.xpath('filterref/@filter')[0] - model_type = net.xpath('model/@type')[0] - if net.xpath('bandwidth/inbound'): - in_attr = net.xpath('bandwidth/inbound')[0] - in_av = in_attr.get('average') - in_peak = in_attr.get('peak') - in_burst = in_attr.get('burst') - inbound = {'average': in_av, 'peak': in_peak, 'burst': in_burst} - if net.xpath('bandwidth/outbound'): - out_attr = net.xpath('bandwidth/outbound')[0] - out_av = out_attr.get('average') - out_peak = out_attr.get('peak') - out_burst = out_attr.get('burst') - outbound = {'average': out_av, 'peak': out_peak, 'burst': out_burst} + for net in ctx.xpath("/domain/devices/interface"): + interface_type = net.xpath("@type")[0] + mac_inst = net.xpath("mac/@address")[0] + nic_inst = net.xpath("source/@network|source/@bridge|source/@dev")[0] + target_inst = "" if not net.xpath("target/@dev") else net.xpath("target/@dev")[0] + link_state = "up" if not net.xpath("link") else net.xpath("link/@state")[0] + filterref_inst = "" if not net.xpath("filterref/@filter") else net.xpath("filterref/@filter")[0] + model_type = net.xpath("model/@type")[0] + if net.xpath("bandwidth/inbound"): + in_attr = net.xpath("bandwidth/inbound")[0] + in_av = in_attr.get("average") + in_peak = in_attr.get("peak") + in_burst = in_attr.get("burst") + inbound = {"average": in_av, "peak": in_peak, "burst": in_burst} + if net.xpath("bandwidth/outbound"): + out_attr = net.xpath("bandwidth/outbound")[0] + out_av = out_attr.get("average") + out_peak = out_attr.get("peak") + out_burst = out_attr.get("burst") + outbound = {"average": out_av, "peak": out_peak, "burst": out_burst} try: ipv4, ipv6 = self.get_interface_addresses(mac_inst) except libvirtError: ipv4, ipv6 = None, None - result.append({ - 'type': interface_type, - 'mac': mac_inst, - 'nic': nic_inst, - 'target': target_inst, - 'state': link_state, - 'model': model_type, - 'ipv4': ipv4, - 'ipv6': ipv6, - 'filterref': filterref_inst, - 'inbound': inbound, - 'outbound': outbound, - }) + result.append( + { + "type": interface_type, + "mac": mac_inst, + "nic": nic_inst, + "target": target_inst, + "state": link_state, + "model": model_type, + "ipv4": ipv4, + "ipv6": ipv6, + "filterref": filterref_inst, + "inbound": inbound, + "outbound": outbound, + } + ) return result return util.get_xml_path(self._XMLDesc(0), func=networks) @@ -400,48 +402,48 @@ class wvmInstance(wvmConnect): def disks(doc): result = [] - for disk in doc.xpath('/domain/devices/disk'): + for disk in doc.xpath("/domain/devices/disk"): dev = volume = storage = src_file = bus = None disk_format = used_size = disk_size = None - disk_cache = disk_io = disk_discard = disk_zeroes = 'default' + disk_cache = disk_io = disk_discard = disk_zeroes = "default" readonly = shareable = serial = None - device = disk.xpath('@device')[0] - if device == 'disk': + device = disk.xpath("@device")[0] + if device == "disk": try: - dev = disk.xpath('target/@dev')[0] - bus = disk.xpath('target/@bus')[0] + dev = disk.xpath("target/@dev")[0] + bus = disk.xpath("target/@bus")[0] try: - src_file = disk.xpath('source/@file|source/@dev|source/@name')[0] - except Exception as e: - v = disk.xpath('source/@volume')[0] - s_name = disk.xpath('source/@pool')[0] + src_file = disk.xpath("source/@file|source/@dev|source/@name")[0] + except Exception: + v = disk.xpath("source/@volume")[0] + s_name = disk.xpath("source/@pool")[0] s = self.wvm.storagePoolLookupByName(s_name) src_file = s.storageVolLookupByName(v).path() try: - disk_format = disk.xpath('driver/@type')[0] + disk_format = disk.xpath("driver/@type")[0] except: pass try: - disk_cache = disk.xpath('driver/@cache')[0] + disk_cache = disk.xpath("driver/@cache")[0] except: pass try: - disk_io = disk.xpath('driver/@io')[0] + disk_io = disk.xpath("driver/@io")[0] except: pass try: - disk_discard = disk.xpath('driver/@discard')[0] + disk_discard = disk.xpath("driver/@discard")[0] except: pass try: - disk_zeroes = disk.xpath('driver/@detect_zeroes')[0] + disk_zeroes = disk.xpath("driver/@detect_zeroes")[0] except: pass - readonly = True if disk.xpath('readonly') else False - shareable = True if disk.xpath('shareable') else False - serial = disk.xpath('serial')[0].text if disk.xpath('serial') else None + readonly = True if disk.xpath("readonly") else False + shareable = True if disk.xpath("shareable") else False + serial = disk.xpath("serial")[0].text if disk.xpath("serial") else None try: vol = self.get_volume_by_path(src_file) @@ -454,25 +456,27 @@ class wvmInstance(wvmConnect): except libvirtError: volume = src_file except Exception as e: - print(f'Exception: {e}') + print(f"Exception: {e}") finally: - result.append({ - 'dev': dev, - 'bus': bus, - 'image': volume, - 'storage': storage, - 'path': src_file, - 'format': disk_format, - 'size': disk_size, - 'used': used_size, - 'cache': disk_cache, - 'io': disk_io, - 'discard': disk_discard, - 'detect_zeroes': disk_zeroes, - 'readonly': readonly, - 'shareable': shareable, - 'serial': serial - }) + result.append( + { + "dev": dev, + "bus": bus, + "image": volume, + "storage": storage, + "path": src_file, + "format": disk_format, + "size": disk_size, + "used": used_size, + "cache": disk_cache, + "io": disk_io, + "discard": disk_discard, + "detect_zeroes": disk_zeroes, + "readonly": readonly, + "shareable": shareable, + "serial": serial, + } + ) return result return util.get_xml_path(self._XMLDesc(0), func=disks) @@ -482,14 +486,14 @@ class wvmInstance(wvmConnect): result = [] dev = volume = storage = bus = None src_file = None - for media in doc.xpath('/domain/devices/disk'): - device = media.xpath('@device')[0] - if device == 'cdrom': + for media in doc.xpath("/domain/devices/disk"): + device = media.xpath("@device")[0] + if device == "cdrom": try: - dev = media.xpath('target/@dev')[0] - bus = media.xpath('target/@bus')[0] + dev = media.xpath("target/@dev")[0] + bus = media.xpath("target/@bus")[0] try: - src_file = media.xpath('source/@file')[0] + src_file = media.xpath("source/@file")[0] vol = self.get_volume_by_path(src_file) volume = vol.name() stg = vol.storagePoolLookupByVolume() @@ -500,18 +504,18 @@ class wvmInstance(wvmConnect): except: pass finally: - result.append({'dev': dev, 'image': volume, 'storage': storage, 'path': src_file, 'bus': bus}) + result.append({"dev": dev, "image": volume, "storage": storage, "path": src_file, "bus": bus}) return result return util.get_xml_path(self._XMLDesc(0), func=disks) def get_bootmenu(self): menu = util.get_xml_path(self._XMLDesc(0), "/domain/os/bootmenu/@enable") - return True if menu == 'yes' else False + return True if menu == "yes" else False def set_bootmenu(self, flag): tree = ElementTree.fromstring(self._XMLDesc(0)) - os = tree.find('os') + os = tree.find("os") menu = os.find("bootmenu") if menu is None: @@ -520,13 +524,13 @@ class wvmInstance(wvmConnect): menu = os.find("bootmenu") if flag == 0: # Disable - menu.attrib['enable'] = 'no' + menu.attrib["enable"] = "no" elif flag == 1: # Enable - menu.attrib['enable'] = 'yes' + menu.attrib["enable"] = "yes" elif flag == -1: # Remove os.remove(menu) else: - raise Exception('Unknown boot menu option, please choose one of 0:disable, 1:enable, -1:remove') + raise Exception("Unknown boot menu option, please choose one of 0:disable, 1:enable, -1:remove") xmldom = ElementTree.tostring(tree).decode() self._defineXML(xmldom) @@ -535,42 +539,42 @@ class wvmInstance(wvmConnect): boot_order = {} type = target = None tree = ElementTree.fromstring(self._XMLDesc(0)) - os = tree.find('os') - boot = os.findall('boot') + os = tree.find("os") + boot = os.findall("boot") for idx, b in enumerate(boot): - dev = b.get('dev') - if dev == 'hd': + dev = b.get("dev") + if dev == "hd": target = "disk" type = "file" - elif dev == 'fd': + elif dev == "fd": target = "floppy" type = "file" - elif dev == 'cdrom': + elif dev == "cdrom": target = "cdrom" type = "file" - elif dev == 'network': + elif dev == "network": target = "network" type = "network" boot_order[idx] = {"type": type, "dev": dev, "target": target} - devices = tree.find('devices') + devices = tree.find("devices") for dev in devices: dev_target = None - boot_dev = dev.find('boot') + boot_dev = dev.find("boot") if boot_dev is not None: - idx = boot_dev.get('order') - dev_type = dev.get('type') - dev_device = dev.get('device') + idx = boot_dev.get("order") + dev_type = dev.get("type") + dev_device = dev.get("device") - if dev_type == 'file': - dev_target = dev.find('target').get('dev') + if dev_type == "file": + dev_target = dev.find("target").get("dev") - elif dev_type == 'network': - dev_mac = dev.find('mac').get('address') + elif dev_type == "network": + dev_mac = dev.find("mac").get("address") dev_device = "network" dev_target = "nic-{}".format(dev_mac[9:]) - elif dev_type == 'usb': + elif dev_type == "usb": pass boot_order[int(idx) - 1] = {"type": dev_type, "dev": dev_device, "target": dev_target} @@ -583,14 +587,14 @@ class wvmInstance(wvmConnect): def remove_bootorder(): tree = ElementTree.fromstring(self._XMLDesc(0)) - os = tree.find('os') - boot = os.findall('boot') + os = tree.find("os") + boot = os.findall("boot") # Remove old style boot order for b in boot: os.remove(b) # Remove rest of them - for dev in tree.find('devices'): - boot_dev = dev.find('boot') + for dev in tree.find("devices"): + boot_dev = dev.find("boot") if boot_dev is not None: dev.remove(boot_dev) return tree @@ -599,36 +603,36 @@ class wvmInstance(wvmConnect): for idx, dev in devorder.items(): order = ElementTree.fromstring("".format(idx + 1)) - if dev['type'] == 'disk': + if dev["type"] == "disk": devices = tree.findall("./devices/disk[@device='disk']") for d in devices: - device = d.find("./target[@dev='{}']".format(dev['dev'])) + device = d.find("./target[@dev='{}']".format(dev["dev"])) if device is not None: d.append(order) - elif dev['type'] == 'cdrom': + elif dev["type"] == "cdrom": devices = tree.findall("./devices/disk[@device='cdrom']") for d in devices: - device = d.find("./target[@dev='{}']".format(dev['dev'])) + device = d.find("./target[@dev='{}']".format(dev["dev"])) if device is not None: d.append(order) - elif dev['type'] == 'network': + elif dev["type"] == "network": devices = tree.findall("./devices/interface[@type='network']") for d in devices: - device = d.find("mac[@address='{}']".format(dev['dev'])) + device = d.find("mac[@address='{}']".format(dev["dev"])) if device is not None: d.append(order) else: - raise Exception('Invalid Device Type for boot order') + raise Exception("Invalid Device Type for boot order") self._defineXML(ElementTree.tostring(tree).decode()) def mount_iso(self, dev, image): def attach_iso(dev, disk, vol): - if disk.get('device') == 'cdrom': + if disk.get("device") == "cdrom": for elm in disk: - if elm.tag == 'target': - if elm.get('dev') == dev: - src_media = ElementTree.Element('source') - src_media.set('file', vol.path()) + if elm.tag == "target": + if elm.get("dev") == dev: + src_media = ElementTree.Element("source") + src_media.set("file", vol.path()) disk.insert(2, src_media) return True @@ -641,7 +645,7 @@ class wvmInstance(wvmConnect): if image == img: vol = stg.storageVolLookupByName(image) tree = ElementTree.fromstring(self._XMLDesc(0)) - for disk in tree.findall('devices/disk'): + for disk in tree.findall("devices/disk"): if attach_iso(dev, disk, vol): break if self.get_status() == 1: @@ -654,14 +658,14 @@ class wvmInstance(wvmConnect): def umount_iso(self, dev, image): tree = ElementTree.fromstring(self._XMLDesc(0)) - for disk in tree.findall('devices/disk'): - if disk.get('device') == 'cdrom': + for disk in tree.findall("devices/disk"): + if disk.get("device") == "cdrom": for elm in disk: - if elm.tag == 'source': - if elm.get('file') == image: + if elm.tag == "source": + if elm.get("file") == image: src_media = elm - if elm.tag == 'target': - if elm.get('dev') == dev: + if elm.tag == "target": + if elm.get("dev") == dev: disk.remove(src_media) if self.get_status() == 1: xml_disk = ElementTree.tostring(disk).decode() @@ -671,44 +675,46 @@ class wvmInstance(wvmConnect): xmldom = ElementTree.tostring(tree).decode() self._defineXML(xmldom) - def attach_disk(self, - target_dev, - source, - target_bus='ide', - disk_type='file', - disk_device='disk', - driver_name='qemu', - driver_type='raw', - readonly=False, - shareable=False, - serial=None, - cache_mode=None, - io_mode=None, - discard_mode=None, - detect_zeroes_mode=None): + def attach_disk( + self, + target_dev, + source, + target_bus="ide", + disk_type="file", + disk_device="disk", + driver_name="qemu", + driver_type="raw", + readonly=False, + shareable=False, + serial=None, + cache_mode=None, + io_mode=None, + discard_mode=None, + detect_zeroes_mode=None, + ): - additionals = '' - if cache_mode is not None and cache_mode != 'default' and disk_device != 'cdrom': + additionals = "" + if cache_mode is not None and cache_mode != "default" and disk_device != "cdrom": additionals += f"cache='{cache_mode}' " - if io_mode is not None and io_mode != 'default': + if io_mode is not None and io_mode != "default": additionals += f"io='{io_mode}' " - if discard_mode is not None and discard_mode != 'default': + if discard_mode is not None and discard_mode != "default": additionals += f"discard='{discard_mode}' " - if detect_zeroes_mode is not None and detect_zeroes_mode != 'default': + if detect_zeroes_mode is not None and detect_zeroes_mode != "default": additionals += f"detect_zeroes='{detect_zeroes_mode}' " xml_disk = f"" - if disk_device == 'cdrom': + if disk_device == "cdrom": xml_disk += f"" - elif disk_device == 'disk': + elif disk_device == "disk": xml_disk += f"" xml_disk += f""" """ - if readonly or disk_device == 'cdrom': + if readonly or disk_device == "cdrom": xml_disk += """""" if shareable: xml_disk += """""" - if serial is not None and serial != 'None' and serial != '': + if serial is not None and serial != "None" and serial != "": xml_disk += f"""{serial}""" xml_disk += """""" if self.get_status() == 1: @@ -722,7 +728,7 @@ class wvmInstance(wvmConnect): disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[0].getparent() xml_disk = etree.tostring(disk_el).decode() - devices = tree.find('devices') + devices = tree.find("devices") devices.remove(disk_el) if self.get_status() == 1: @@ -731,29 +737,41 @@ class wvmInstance(wvmConnect): if self.get_status() == 5: self.instance.detachDeviceFlags(xml_disk, VIR_DOMAIN_AFFECT_CONFIG) - def edit_disk(self, target_dev, source, readonly, shareable, target_bus, serial, format, cache_mode, io_mode, discard_mode, - detect_zeroes_mode): + def edit_disk( + self, + target_dev, + source, + readonly, + shareable, + target_bus, + serial, + format, + cache_mode, + io_mode, + discard_mode, + detect_zeroes_mode, + ): tree = etree.fromstring(self._XMLDesc(0)) disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[0].getparent() - old_disk_type = disk_el.get('type') - old_disk_device = disk_el.get('device') - old_driver_name = disk_el.xpath('driver/@name')[0] - old_target_bus = disk_el.xpath('target/@bus')[0] + old_disk_type = disk_el.get("type") + old_disk_device = disk_el.get("device") + old_driver_name = disk_el.xpath("driver/@name")[0] + old_target_bus = disk_el.xpath("target/@bus")[0] - additionals = '' - if cache_mode is not None and cache_mode != 'default': + additionals = "" + if cache_mode is not None and cache_mode != "default": additionals += f"cache='{cache_mode}' " - if io_mode is not None and io_mode != 'default': + if io_mode is not None and io_mode != "default": additionals += f"io='{io_mode}' " - if discard_mode is not None and discard_mode != 'default': + if discard_mode is not None and discard_mode != "default": additionals += f"discard='{discard_mode}' " - if detect_zeroes_mode is not None and detect_zeroes_mode != 'default': + if detect_zeroes_mode is not None and detect_zeroes_mode != "default": additionals += f"detect_zeroes='{detect_zeroes_mode}' " xml_disk = f"" - if old_disk_device == 'cdrom': + if old_disk_device == "cdrom": xml_disk += f"" - elif old_disk_device == 'disk': + elif old_disk_device == "disk": xml_disk += f"" xml_disk += f""" @@ -762,7 +780,7 @@ class wvmInstance(wvmConnect): xml_disk += """""" if shareable: xml_disk += """""" - if serial is not None and serial != 'None' and serial != '': + if serial is not None and serial != "None" and serial != "": xml_disk += f"""{serial}""" xml_disk += """""" @@ -776,9 +794,9 @@ class wvmInstance(wvmConnect): time.sleep(1) cpu_use_now = self.instance.info()[4] diff_usage = cpu_use_now - cpu_use_ago - cpu_usage['cpu'] = 100 * diff_usage / (1 * nbcore * 10**9) + cpu_usage["cpu"] = 100 * diff_usage / (1 * nbcore * 10 ** 9) else: - cpu_usage['cpu'] = 0 + cpu_usage["cpu"] = 0 return cpu_usage def set_vcpu(self, cpu_id, enabled): @@ -814,38 +832,39 @@ class wvmInstance(wvmConnect): mem_usage = {} if self.get_status() == 1: mem_stats = self.instance.memoryStats() - rss = mem_stats['rss'] if 'rss' in mem_stats else 0 - total = mem_stats['actual'] if 'actual' in mem_stats else 0 + rss = mem_stats["rss"] if "rss" in mem_stats else 0 + total = mem_stats["actual"] if "actual" in mem_stats else 0 available = total - rss - if available < 0: available = 0 + if available < 0: + available = 0 - mem_usage['used'] = rss - mem_usage['total'] = total + mem_usage["used"] = rss + mem_usage["total"] = total else: - mem_usage['used'] = 0 - mem_usage['total'] = 0 + mem_usage["used"] = 0 + mem_usage["total"] = 0 return mem_usage def disk_usage(self): devices = [] dev_usage = [] tree = ElementTree.fromstring(self._XMLDesc(0)) - for disk in tree.findall('devices/disk'): - if disk.get('device') == 'disk': + for disk in tree.findall("devices/disk"): + if disk.get("device") == "disk": dev_file = None dev_bus = None network_disk = True for elm in disk: - if elm.tag == 'source': - if elm.get('protocol'): - dev_file = elm.get('protocol') + if elm.tag == "source": + if elm.get("protocol"): + dev_file = elm.get("protocol") network_disk = True - if elm.get('file'): - dev_file = elm.get('file') - if elm.get('dev'): - dev_file = elm.get('dev') - if elm.tag == 'target': - dev_bus = elm.get('dev') + if elm.get("file"): + dev_file = elm.get("file") + if elm.get("dev"): + dev_file = elm.get("dev") + if elm.tag == "target": + dev_bus = elm.get("dev") if (dev_file and dev_bus) is not None: if network_disk: dev_file = dev_bus @@ -862,7 +881,7 @@ class wvmInstance(wvmConnect): else: rd_diff_usage = 0 wr_diff_usage = 0 - dev_usage.append({'dev': dev[1], 'rd': rd_diff_usage, 'wr': wr_diff_usage}) + dev_usage.append({"dev": dev[1], "rd": rd_diff_usage, "wr": wr_diff_usage}) return dev_usage def net_usage(self): @@ -880,24 +899,24 @@ class wvmInstance(wvmConnect): tx_use_now = self.instance.interfaceStats(dev)[4] rx_diff_usage = (rx_use_now - rx_use_ago) * 8 tx_diff_usage = (tx_use_now - tx_use_ago) * 8 - dev_usage.append({'dev': i, 'rx': rx_diff_usage, 'tx': tx_diff_usage}) + dev_usage.append({"dev": i, "rx": rx_diff_usage, "tx": tx_diff_usage}) else: for i, dev in enumerate(self.get_net_devices()): - dev_usage.append({'dev': i, 'rx': 0, 'tx': 0}) + dev_usage.append({"dev": i, "rx": 0, "tx": 0}) return dev_usage def get_telnet_port(self): telnet_port = None service_port = None tree = ElementTree.fromstring(self._XMLDesc(0)) - for console in tree.findall('devices/console'): - if console.get('type') == 'tcp': + for console in tree.findall("devices/console"): + if console.get("type") == "tcp": for elm in console: - if elm.tag == 'source': - if elm.get('service'): - service_port = elm.get('service') - if elm.tag == 'protocol': - if elm.get('type') == 'telnet': + if elm.tag == "source": + if elm.get("service"): + service_port = elm.get("service") + if elm.tag == "protocol": + if elm.get("type") == "telnet": if service_port is not None: telnet_port = service_port return telnet_port @@ -948,7 +967,7 @@ class wvmInstance(wvmConnect): current_type = self.get_console_type() if current_type == console_type: return True - if console_type == '': + if console_type == "": return False xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE) root = ElementTree.fromstring(xml) @@ -957,7 +976,7 @@ class wvmInstance(wvmConnect): except SyntaxError: # Little fix for old version ElementTree graphic = root.find("devices/graphics") - graphic.set('type', console_type) + graphic.set("type", console_type) newxml = ElementTree.tostring(root).decode() self._defineXML(newxml) @@ -969,7 +988,9 @@ class wvmInstance(wvmConnect): def get_console_websocket_port(self): console_type = self.get_console_type() - websocket_port = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics[@type='%s']/@websocket" % console_type) + websocket_port = util.get_xml_path( + self._XMLDesc(0), "/domain/devices/graphics[@type='%s']/@websocket" % console_type + ) return websocket_port def get_console_passwd(self): @@ -987,10 +1008,10 @@ class wvmInstance(wvmConnect): if graphic is None: return False if passwd: - graphic.set('passwd', passwd) + graphic.set("passwd", passwd) else: try: - graphic.attrib.pop('passwd') + graphic.attrib.pop("passwd") except: pass newxml = ElementTree.tostring(root).decode() @@ -1005,18 +1026,18 @@ class wvmInstance(wvmConnect): except SyntaxError: # Little fix for old version ElementTree graphic = root.find("devices/graphics") - if keymap != 'auto': - graphic.set('keymap', keymap) + if keymap != "auto": + graphic.set("keymap", keymap) else: try: - graphic.attrib.pop('keymap') + graphic.attrib.pop("keymap") except: pass newxml = ElementTree.tostring(root).decode() self._defineXML(newxml) def get_console_keymap(self): - return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@keymap") or '' + return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@keymap") or "" def get_video_model(self): """ :return only primary video card""" @@ -1024,8 +1045,8 @@ class wvmInstance(wvmConnect): tree = etree.fromstring(xml) video_models = tree.xpath("/domain/devices/video/model") for model in video_models: - if model.get('primary') == 'yes' or len(video_models) == 1: - return model.get('type') + if model.get("primary") == "yes" or len(video_models) == 1: + return model.get("type") def set_video_model(self, model): """ Changes only primary video card""" @@ -1034,7 +1055,7 @@ class wvmInstance(wvmConnect): video_models = tree.xpath("/domain/devices/video/model") video_xml = "".format(model) for model in video_models: - if model.get('primary') == 'yes' or len(video_models) == 1: + if model.get("primary") == "yes" or len(video_models) == 1: parent = model.getparent() parent.remove(model) parent.append(etree.fromstring(video_xml)) @@ -1051,9 +1072,9 @@ class wvmInstance(wvmConnect): xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE) tree = etree.fromstring(xml) - vcpu_elem = tree.find('vcpu') + vcpu_elem = tree.find("vcpu") vcpu_elem.text = vcpu - vcpu_elem.set('current', cur_vcpu) + vcpu_elem.set("current", cur_vcpu) new_xml = etree.tostring(tree).decode() self._defineXML(new_xml) @@ -1076,9 +1097,9 @@ class wvmInstance(wvmConnect): xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE) tree = etree.fromstring(xml) - mem_elem = tree.find('memory') + mem_elem = tree.find("memory") mem_elem.text = str(memory) - cur_mem_elem = tree.find('currentMemory') + cur_mem_elem = tree.find("currentMemory") cur_mem_elem.text = str(cur_memory) new_xml = etree.tostring(tree).decode() @@ -1092,9 +1113,9 @@ class wvmInstance(wvmConnect): tree = etree.fromstring(xml) for disk in disks: - source_dev = disk['path'] + source_dev = disk["path"] vol = self.get_volume_by_path(source_dev) - vol.resize(disk['size_new']) + vol.resize(disk["size_new"]) new_xml = etree.tostring(tree).decode() self._defineXML(new_xml) @@ -1110,14 +1131,14 @@ class wvmInstance(wvmConnect): except: pass for img in stg.listVolumes(): - if img.lower().endswith('.iso'): + if img.lower().endswith(".iso"): iso.append(img) return iso def delete_all_disks(self): disks = self.get_disk_devices() for disk in disks: - vol = self.get_volume_by_path(disk.get('path')) + vol = self.get_volume_by_path(disk.get("path")) vol.delete(0) def _snapshotCreateXML(self, xml, flag): @@ -1127,7 +1148,10 @@ class wvmInstance(wvmConnect): xml = """ %s shutoff - %d""" % (name, time.time()) + %d""" % ( + name, + time.time(), + ) xml += self._XMLDesc(VIR_DOMAIN_XML_SECURE) xml += """0 """ @@ -1139,7 +1163,7 @@ class wvmInstance(wvmConnect): for snapshot in snapshot_list: snap = self.instance.snapshotLookupByName(snapshot, 0) snap_time_create = util.get_xml_path(snap.getXMLDesc(0), "/domainsnapshot/creationTime") - snapshots.append({'date': datetime.fromtimestamp(int(snap_time_create)), 'name': snapshot}) + snapshots.append({"date": datetime.fromtimestamp(int(snap_time_create)), "name": snapshot}) return snapshots def snapshot_delete(self, snapshot): @@ -1164,29 +1188,29 @@ class wvmInstance(wvmConnect): return mac # if mac does not contain ":", try to split into tuples and join with ":" n = 2 - mac_tuples = [mac[i:i + n] for i in range(0, len(mac), n)] - return ':'.join(mac_tuples) + mac_tuples = [mac[i : i + n] for i in range(0, len(mac), n)] + return ":".join(mac_tuples) def clone_instance(self, clone_data): clone_dev_path = [] xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE) tree = etree.fromstring(xml) - name = tree.find('name') - name.text = clone_data['name'] - uuid = tree.find('uuid') + name = tree.find("name") + name.text = clone_data["name"] + uuid = tree.find("uuid") tree.remove(uuid) options = { - 'title': clone_data.get('clone-title', ''), - 'description': clone_data.get('clone-description', ''), + "title": clone_data.get("clone-title", ""), + "description": clone_data.get("clone-description", ""), } self._set_options(tree, options) src_nvram_path = self.get_nvram() if src_nvram_path: # Change XML for nvram - nvram = tree.find('os/nvram') + nvram = tree.find("os/nvram") nvram.getparent().remove(nvram) # NVRAM CLONE: create pool if nvram is not in a pool. then clone it @@ -1197,40 +1221,40 @@ class wvmInstance(wvmConnect): self.get_volume_by_path(src_nvram_path) except libvirtError: stg_conn = self.get_wvmStorages() - stg_conn.create_storage('dir', nvram_pool_name, None, nvram_dir) + stg_conn.create_storage("dir", nvram_pool_name, None, nvram_dir) new_nvram_name = f"{clone_data['name']}_VARS" nvram_stg = self.get_wvmStorage(nvram_pool_name) - nvram_stg.clone_volume(src_nvram_name, new_nvram_name, file_suffix='fd') + nvram_stg.clone_volume(src_nvram_name, new_nvram_name, file_suffix="fd") - for num, net in enumerate(tree.findall('devices/interface')): - elm = net.find('mac') - mac_address = self.fix_mac(clone_data['clone-net-mac-' + str(num)]) - elm.set('address', mac_address) + for num, net in enumerate(tree.findall("devices/interface")): + elm = net.find("mac") + mac_address = self.fix_mac(clone_data["clone-net-mac-" + str(num)]) + elm.set("address", mac_address) - for disk in tree.findall('devices/disk'): - if disk.get('device') == 'disk': - elm = disk.find('target') - device_name = elm.get('dev') + for disk in tree.findall("devices/disk"): + if disk.get("device") == "disk": + elm = disk.find("target") + device_name = elm.get("dev") if device_name: - target_file = clone_data['disk-' + device_name] + target_file = clone_data["disk-" + device_name] try: - meta_prealloc = clone_data['meta-' + device_name] + meta_prealloc = clone_data["meta-" + device_name] except: meta_prealloc = False - elm.set('dev', device_name) + elm.set("dev", device_name) - elm = disk.find('source') - source_file = elm.get('file') + elm = disk.find("source") + source_file = elm.get("file") if source_file: clone_dev_path.append(source_file) clone_path = os.path.join(os.path.dirname(source_file), target_file) - elm.set('file', clone_path) + elm.set("file", clone_path) vol = self.get_volume_by_path(source_file) vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type") - if vol_format == 'qcow2' and meta_prealloc: + if vol_format == "qcow2" and meta_prealloc: meta_prealloc = True vol_clone_xml = f""" @@ -1256,11 +1280,11 @@ class wvmInstance(wvmConnect): stg = vol.storagePoolLookupByVolume() stg.createXMLFrom(vol_clone_xml, vol, meta_prealloc) - source_protocol = elm.get('protocol') - if source_protocol == 'rbd': - source_name = elm.get('name') + source_protocol = elm.get("protocol") + if source_protocol == "rbd": + source_name = elm.get("name") clone_name = "%s/%s" % (os.path.dirname(source_name), target_file) - elm.set('name', clone_name) + elm.set("name", clone_name) vol = self.get_volume_by_path(source_name) vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type") @@ -1277,10 +1301,10 @@ class wvmInstance(wvmConnect): stg = vol.storagePoolLookupByVolume() stg.createXMLFrom(vol_clone_xml, vol, meta_prealloc) - source_dev = elm.get('dev') + source_dev = elm.get("dev") if source_dev: clone_path = os.path.join(os.path.dirname(source_dev), target_file) - elm.set('dev', clone_path) + elm.set("dev", clone_path) vol = self.get_volume_by_path(source_dev) stg = vol.storagePoolLookupByVolume() @@ -1293,10 +1317,10 @@ class wvmInstance(wvmConnect): self._defineXML(ElementTree.tostring(tree).decode()) - return self.get_instance(clone_data['name']).UUIDString() + return self.get_instance(clone_data["name"]).UUIDString() - def get_bridge_name(self, source, source_type='net'): - if source_type == 'iface': + def get_bridge_name(self, source, source_type="net"): + if source_type == "iface": iface = self.get_iface(source) bridge_name = iface.name() else: @@ -1307,28 +1331,28 @@ class wvmInstance(wvmConnect): bridge_name = None return bridge_name - def add_network(self, mac_address, source, source_type='net', model='virtio', nwfilter=None): - forward_mode = '' - if source_type != 'iface': + def add_network(self, mac_address, source, source_type="net", model="virtio", nwfilter=None): + forward_mode = "" + if source_type != "iface": forward_mode = self.get_network_forward(source) - if forward_mode in ['nat', 'isolated', 'routed']: - interface_type = 'network' - elif forward_mode == '': - interface_type = 'direct' + if forward_mode in ["nat", "isolated", "routed"]: + interface_type = "network" + elif forward_mode == "": + interface_type = "direct" else: if self.get_bridge_name(source, source_type) is None: - interface_type = 'network' + interface_type = "network" else: - interface_type = 'bridge' + interface_type = "bridge" xml_iface = f""" """ - if interface_type == 'network': + if interface_type == "network": xml_iface += f"""""" - elif interface_type == 'direct': - if source_type == 'net': + elif interface_type == "direct": + if source_type == "net": xml_iface += f"""""" else: xml_iface += f"""""" @@ -1348,9 +1372,9 @@ class wvmInstance(wvmConnect): def delete_network(self, mac_address): tree = ElementTree.fromstring(self._XMLDesc(0)) - for interface in tree.findall('devices/interface'): - source = interface.find('mac') - if source.get('address', '') == mac_address: + for interface in tree.findall("devices/interface"): + source = interface.find("mac") + if source.get("address", "") == mac_address: new_xml = ElementTree.tostring(interface).decode() if self.get_status() == 1: @@ -1362,55 +1386,58 @@ class wvmInstance(wvmConnect): def change_network(self, network_data): xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE) tree = ElementTree.fromstring(xml) - for num, interface in enumerate(tree.findall('devices/interface')): - net_mac = network_data.get('net-mac-' + str(num)) - if net_mac is None: continue - net_source = network_data.get('net-source-' + str(num)) - net_source_type = network_data.get('net-source-' + str(num) + '-type') - net_filter = network_data.get('net-nwfilter-' + str(num)) - net_model = network_data.get('net-model-' + str(num)) + for num, interface in enumerate(tree.findall("devices/interface")): + net_mac = network_data.get("net-mac-" + str(num)) + if net_mac is None: + continue + net_source = network_data.get("net-source-" + str(num)) + net_source_type = network_data.get("net-source-" + str(num) + "-type") + net_filter = network_data.get("net-nwfilter-" + str(num)) + net_model = network_data.get("net-model-" + str(num)) - source = interface.find('source') - if interface.get('type') == 'bridge': + source = interface.find("source") + if interface.get("type") == "bridge": bridge_name = self.get_bridge_name(net_source, net_source_type) - source.set('bridge', bridge_name) - elif interface.get('type') in ['network', 'direct']: - if net_source_type == 'net': - source.set('network', net_source) - elif net_source_type == 'iface': - source.set('dev', net_source) + source.set("bridge", bridge_name) + elif interface.get("type") in ["network", "direct"]: + if net_source_type == "net": + source.set("network", net_source) + elif net_source_type == "iface": + source.set("dev", net_source) else: - raise libvirtError(f"Unknown network type: {net_source_type}") + raise libvirtError("Unknown network type: {}".format(net_source_type)) else: - raise libvirtError(f"Unknown network type: {interface.get('type')}") + raise libvirtError("Unknown network type: {}".format(interface.get("type"))) - source = interface.find('model') - if net_model != 'default': - source.attrib['type'] = net_model + source = interface.find("model") + if net_model != "default": + source.attrib["type"] = net_model else: interface.remove(source) - source = interface.find('mac') - source.set('address', net_mac) - source = interface.find('filterref') + source = interface.find("mac") + source.set("address", net_mac) + source = interface.find("filterref") if net_filter: - if source is not None: source.set('filter', net_filter) + if source is not None: + source.set("filter", net_filter) else: element = ElementTree.Element("filterref") - element.attrib['filter'] = net_filter + element.attrib["filter"] = net_filter interface.append(element) else: - if source is not None: interface.remove(source) + if source is not None: + interface.remove(source) new_xml = ElementTree.tostring(tree).decode() self._defineXML(new_xml) def set_link_state(self, mac_address, state): tree = etree.fromstring(self._XMLDesc(0)) - for interface in tree.findall('devices/interface'): - source = interface.find('mac') - if source.get('address') == mac_address: - link = interface.find('link') + for interface in tree.findall("devices/interface"): + source = interface.find("mac") + if source.get("address") == mac_address: + link = interface.find("link") if link is not None: interface.remove(link) link_el = etree.Element("link") @@ -1424,9 +1451,9 @@ class wvmInstance(wvmConnect): self.instance.updateDeviceFlags(new_xml, VIR_DOMAIN_AFFECT_CONFIG) def _set_options(self, tree, options): - for o in ['title', 'description']: + for o in ["title", "description"]: option = tree.find(o) - option_value = options.get(o, '').strip() + option_value = options.get(o, "").strip() if not option_value: if option is not None: tree.remove(option) @@ -1456,29 +1483,33 @@ class wvmInstance(wvmConnect): for q in qos: bound_list = list() - mac = q.xpath('mac/@address') - band = q.find('bandwidth') + mac = q.xpath("mac/@address") + band = q.find("bandwidth") if band is not None: - in_qos = band.find('inbound') + in_qos = band.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') - in_floor = in_qos.get('floor') - bound_list.append({ - 'direction': 'inbound', - 'average': in_av, - 'peak': in_peak, - 'floor': in_floor, - 'burst': in_burst - }) + in_av = in_qos.get("average") + in_peak = in_qos.get("peak") + in_burst = in_qos.get("burst") + in_floor = in_qos.get("floor") + bound_list.append( + { + "direction": "inbound", + "average": in_av, + "peak": in_peak, + "floor": in_floor, + "burst": in_burst, + } + ) - out_qos = band.find('outbound') + out_qos = band.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') - bound_list.append({'direction': '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") + bound_list.append( + {"direction": "outbound", "average": out_av, "peak": out_peak, "burst": out_burst} + ) qos_values[mac[0]] = bound_list return qos_values @@ -1488,7 +1519,7 @@ class wvmInstance(wvmConnect): elif direction == "outbound": xml = f"" else: - raise Exception('Direction must be inbound or outbound') + raise Exception("Direction must be inbound or outbound") tree = etree.fromstring(self._XMLDesc(0)) @@ -1497,7 +1528,7 @@ class wvmInstance(wvmConnect): if cur_mac.get("address") == mac: interface = cur_mac.getparent() - band = interface.find('bandwidth') + band = interface.find("bandwidth") if band is None: xml = "" + xml + "" interface.append(etree.fromstring(xml)) @@ -1517,7 +1548,7 @@ class wvmInstance(wvmConnect): for direct in tree.xpath("/domain/devices/interface/bandwidth/{}".format(direction)): band_el = direct.getparent() interface_el = band_el.getparent() # parent bandwidth,its parent is interface - parent_mac = interface_el.xpath('mac/@address') + parent_mac = interface_el.xpath("mac/@address") if parent_mac[0] == mac: band_el.remove(direct) @@ -1551,7 +1582,7 @@ class wvmInstance(wvmConnect): """ Return agent channel object if it is defined. """ - for channel in doc.xpath('/domain/devices/channel'): + for channel in doc.xpath("/domain/devices/channel"): ch_type = channel.get("type") target = channel.find("target") target_name = target.get("name") @@ -1570,7 +1601,7 @@ class wvmInstance(wvmConnect): dev = self.get_guest_agent() if dev is not None: states = dev.xpath("target/@state") - state = states[0] if len(states) > 0 else '' + state = states[0] if len(states) > 0 else "" if state == "connected": return True return False diff --git a/vrtManager/interface.py b/vrtManager/interface.py index 149c600..b6e7c56 100644 --- a/vrtManager/interface.py +++ b/vrtManager/interface.py @@ -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""" """ - if ipv4_type == 'dhcp': + if ipv4_type == "dhcp": xml += """ """ - if ipv4_type == 'static': - address, prefix = ipv4_addr.split('/') + if ipv4_type == "static": + address, prefix = ipv4_addr.split("/") xml += f""" """ - if ipv6_type == 'dhcp': + if ipv6_type == "dhcp": xml += """ """ - if ipv6_type == 'static': - address, prefix = ipv6_addr.split('/') + if ipv6_type == "static": + address, prefix = ipv6_addr.split("/") xml += f""" """ - if itype == 'bridge': + if itype == "bridge": xml += f""" """ @@ -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 diff --git a/vrtManager/network.py b/vrtManager/network.py index dec2362..9a5a149 100644 --- a/vrtManager/network.py +++ b/vrtManager/network.py @@ -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""" {name}""" - if forward in ['nat', 'route', 'bridge']: + if forward in ["nat", "route", "bridge"]: xml += f"""""" - if forward == 'macvtap': + if forward == "macvtap": xml += f""" """ else: xml += """""" if openvswitch is True: xml += """""" - if forward not in ['bridge', 'macvtap']: + if forward not in ["bridge", "macvtap"]: if ipv4: xml += f"""""" if dhcp4: xml += f""" """ 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"""""" xml += """""" @@ -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 = ''.format(h.get('mac'), h.get('name'), ip) - if family == 'ipv6': - new_xml = ''.format(h.get('id'), h.get('name'), ip) + if h.get("ip") == ip: + if family == "ipv4": + new_xml = ''.format(h.get("mac"), h.get("name"), ip) + if family == "ipv6": + new_xml = ''.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 = ''.format(mac_duid, 'name="' + name + '"' if name else '', IP(address)) + if family == "ipv4": + new_xml = ''.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 = ''.format(mac_duid, 'name="' + name + '"' if name else '', IP(address)) + if family == "ipv6": + new_xml = ''.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"" 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: diff --git a/vrtManager/nwfilters.py b/vrtManager/nwfilters.py index f0a89a5..627e571 100644 --- a/vrtManager/nwfilters.py +++ b/vrtManager/nwfilters.py @@ -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) diff --git a/vrtManager/rwlock.py b/vrtManager/rwlock.py index 2ee82f9..a32903f 100644 --- a/vrtManager/rwlock.py +++ b/vrtManager/rwlock.py @@ -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: diff --git a/vrtManager/secrets.py b/vrtManager/secrets.py index de7b3f4..c877282 100644 --- a/vrtManager/secrets.py +++ b/vrtManager/secrets.py @@ -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""" """ - if secret_type == 'ceph': + if secret_type == "ceph": xml += f"""{data}""" - if secret_type == 'volume': + if secret_type == "volume": xml += f"""{data}""" - if secret_type == 'iscsi': - xml += f"""{data}""" + if secret_type == "iscsi": + xml += f"""{data}""" xml += """ """ self.wvm.secretDefineXML(xml) diff --git a/vrtManager/storage.py b/vrtManager/storage.py index 7726b95..85eafb0 100644 --- a/vrtManager/storage.py +++ b/vrtManager/storage.py @@ -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""" diff --git a/vrtManager/util.py b/vrtManager/util.py index 7c9a08e..abe2309 100644 --- a/vrtManager/util.py +++ b/vrtManager/util.py @@ -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("&", "&") str = str.replace("'", "'") - str = str.replace("\"", """) + str = str.replace('"', """) str = str.replace("<", "<") str = str.replace(">", ">") 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 diff --git a/webvirtcloud/common_tags.py b/webvirtcloud/common_tags.py index 0b43d01..7197800 100644 --- a/webvirtcloud/common_tags.py +++ b/webvirtcloud/common_tags.py @@ -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 diff --git a/webvirtcloud/middleware.py b/webvirtcloud/middleware.py index 6759ff1..fe2d039 100644 --- a/webvirtcloud/middleware.py +++ b/webvirtcloud/middleware.py @@ -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 diff --git a/webvirtcloud/settings-dev.py b/webvirtcloud/settings-dev.py index 25b9733..990ed60 100644 --- a/webvirtcloud/settings-dev.py +++ b/webvirtcloud/settings-dev.py @@ -20,9 +20,7 @@ MIDDLEWARE += [ ] # DebugToolBar -INTERNAL_IPS = ( - "127.0.0.1", -) +INTERNAL_IPS = ("127.0.0.1",) DEBUG_TOOLBAR_CONFIG = { "INTERCEPT_REDIRECTS": False, } diff --git a/webvirtcloud/settings.py.template b/webvirtcloud/settings.py.template index 6dd0b2a..37ca195 100644 --- a/webvirtcloud/settings.py.template +++ b/webvirtcloud/settings.py.template @@ -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"] diff --git a/webvirtcloud/urls.py b/webvirtcloud/urls.py index 24854ca..42785ac 100644 --- a/webvirtcloud/urls.py +++ b/webvirtcloud/urls.py @@ -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 diff --git a/webvirtcloud/wsgi.py b/webvirtcloud/wsgi.py index 53925ed..d444f71 100644 --- a/webvirtcloud/wsgi.py +++ b/webvirtcloud/wsgi.py @@ -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() diff --git a/webvirtcloud/wsgi_custom.py b/webvirtcloud/wsgi_custom.py index f423187..acf22aa 100644 --- a/webvirtcloud/wsgi_custom.py +++ b/webvirtcloud/wsgi_custom.py @@ -16,7 +16,7 @@ exec( compile( open("/srv/webvirtcloud/venv/bin/activate", "rb").read(), "/srv/webvirtcloud/venv/bin/activate", - "exec" + "exec", ) )