mirror of
https://github.com/retspen/webvirtcloud
synced 2024-10-31 19:44:16 +00:00
lint with black python. convert f style strings to old one. some small fixes
This commit is contained in:
parent
c20c353a40
commit
508e3609be
54 changed files with 2123 additions and 1824 deletions
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from django import template
|
||||
import base64
|
||||
import hashlib
|
||||
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django import forms
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.text import format_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -13,7 +13,7 @@ from .models import Permission
|
|||
class GroupForm(forms.ModelForm):
|
||||
permissions = forms.ModelMultipleChoiceField(
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
queryset=Permission.objects.filter(content_type__model='permissionset'),
|
||||
queryset=Permission.objects.filter(content_type__model="permissionset"),
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
@ -25,12 +25,12 @@ class GroupForm(forms.ModelForm):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GroupForm, self).__init__(*args, **kwargs)
|
||||
instance = getattr(self, 'instance', None)
|
||||
instance = getattr(self, "instance", None)
|
||||
if instance and instance.id:
|
||||
self.fields['users'].initial = self.instance.user_set.all()
|
||||
self.fields["users"].initial = self.instance.user_set.all()
|
||||
|
||||
def save_m2m(self):
|
||||
self.instance.user_set.set(self.cleaned_data['users'])
|
||||
self.instance.user_set.set(self.cleaned_data["users"])
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
instance = super(GroupForm, self).save()
|
||||
|
@ -39,36 +39,36 @@ class GroupForm(forms.ModelForm):
|
|||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = '__all__'
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class UserForm(forms.ModelForm):
|
||||
user_permissions = forms.ModelMultipleChoiceField(
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
queryset=Permission.objects.filter(content_type__model='permissionset'),
|
||||
label=_('Permissions'),
|
||||
queryset=Permission.objects.filter(content_type__model="permissionset"),
|
||||
label=_("Permissions"),
|
||||
required=False,
|
||||
)
|
||||
|
||||
groups = forms.ModelMultipleChoiceField(
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
queryset=Group.objects.all(),
|
||||
label=_('Groups'),
|
||||
label=_("Groups"),
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
'username',
|
||||
'groups',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'user_permissions',
|
||||
'is_staff',
|
||||
'is_active',
|
||||
'is_superuser',
|
||||
"username",
|
||||
"groups",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"user_permissions",
|
||||
"is_staff",
|
||||
"is_active",
|
||||
"is_superuser",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -76,12 +76,20 @@ class UserForm(forms.ModelForm):
|
|||
if self.instance.id:
|
||||
password = ReadOnlyPasswordHashField(
|
||||
label=_("Password"),
|
||||
help_text=format_lazy(_("""Raw passwords are not stored, so there is no way to see
|
||||
this user's password, but you can change the password using <a href='{}'>this form</a>."""),
|
||||
reverse_lazy('admin:user_update_password',
|
||||
args=[self.instance.id,]))
|
||||
help_text=format_lazy(
|
||||
_(
|
||||
"""Raw passwords are not stored, so there is no way to see this user's password,
|
||||
but you can change the password using <a href='{}'>this form</a>."""
|
||||
),
|
||||
reverse_lazy(
|
||||
"admin:user_update_password",
|
||||
args=[
|
||||
self.instance.id,
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
self.fields['Password'] = password
|
||||
self.fields["Password"] = password
|
||||
|
||||
|
||||
class UserCreateForm(UserForm):
|
||||
|
@ -90,20 +98,20 @@ class UserCreateForm(UserForm):
|
|||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
'username',
|
||||
'password',
|
||||
'groups',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'user_permissions',
|
||||
'is_staff',
|
||||
'is_active',
|
||||
'is_superuser',
|
||||
"username",
|
||||
"password",
|
||||
"groups",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"user_permissions",
|
||||
"is_staff",
|
||||
"is_active",
|
||||
"is_superuser",
|
||||
]
|
||||
|
||||
|
||||
class UserAttributesForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = UserAttributes
|
||||
exclude = ['user', 'can_clone_instances']
|
||||
exclude = ["user", "can_clone_instances"]
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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._-]+')
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)]))
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -32,4 +32,4 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.RunPython(add_flavors, del_flavors),
|
||||
]
|
||||
]
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="takesnapshot">
|
||||
{% if instance.status == 5 %}
|
||||
<p>{% trans "This may take more than an hour, depending on how much content is on your droplet and how large the disk is." %}</p>
|
||||
<p>{% trans "This may take more than an hour, depending on how much content is on your instance and how large the disk is." %}</p>
|
||||
<form action="{% url 'instances:snapshot' instance.id %}" class="form-inline" method="post" role="form" aria-label="Create snapshot form">
|
||||
{% csrf_token %}
|
||||
<div class="form-group row">
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django import template
|
||||
import re
|
||||
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
|
|
|
@ -8,12 +8,11 @@ from django.contrib.auth.models import Permission
|
|||
from django.http.response import Http404
|
||||
from django.shortcuts import reverse
|
||||
from django.test import TestCase
|
||||
from instances.views import instance
|
||||
from libvirt import VIR_DOMAIN_UNDEFINE_NVRAM
|
||||
from vrtManager.create import wvmCreate
|
||||
from vrtManager.util import randomUUID
|
||||
|
||||
from instances.views import instance
|
||||
|
||||
from .models import Flavor, Instance
|
||||
from .utils import refr
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,5 @@
|
|||
import re
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('vm_logs/<vname>/', views.vm_logs, name='vm_logs'),
|
||||
path("vm_logs/<vname>/", views.vm_logs, name="vm_logs"),
|
||||
]
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -5,4 +5,4 @@ from django.apps import AppConfig
|
|||
|
||||
|
||||
class NwfiltersConfig(AppConfig):
|
||||
name = 'nwfilters'
|
||||
name = "nwfilters"
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import re
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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]])
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import libvirt
|
||||
import threading
|
||||
import socket
|
||||
import re
|
||||
from vrtManager import util
|
||||
from vrtManager.rwlock import ReadWriteLock
|
||||
import socket
|
||||
import threading
|
||||
|
||||
import libvirt
|
||||
from django.conf import settings
|
||||
from libvirt import libvirtError
|
||||
from vrtManager import util
|
||||
from vrtManager.rwlock import ReadWriteLock
|
||||
|
||||
CONN_SOCKET = 4
|
||||
CONN_TLS = 3
|
||||
|
@ -18,6 +19,7 @@ TCP_PORT = 16509
|
|||
|
||||
class wvmEventLoop(threading.Thread):
|
||||
""" Event Loop Class"""
|
||||
|
||||
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
|
||||
# register the default event implementation
|
||||
# of libvirt, as we do not have an existing
|
||||
|
@ -25,7 +27,7 @@ class wvmEventLoop(threading.Thread):
|
|||
libvirt.virEventRegisterDefaultImpl()
|
||||
|
||||
if name is None:
|
||||
name = 'libvirt event loop'
|
||||
name = "libvirt event loop"
|
||||
|
||||
super(wvmEventLoop, self).__init__(group, target, name, args, kwargs)
|
||||
|
||||
|
@ -46,6 +48,7 @@ class wvmConnection(object):
|
|||
class representing a single connection stored in the Connection Manager
|
||||
# to-do: may also need some locking to ensure to not connect simultaniously in 2 threads
|
||||
"""
|
||||
|
||||
def __init__(self, host, login, passwd, conn):
|
||||
"""
|
||||
Sets all class attributes and tries to open the connection
|
||||
|
@ -86,10 +89,12 @@ class wvmConnection(object):
|
|||
# * set keep alive interval
|
||||
# * set connection close/fail handler
|
||||
try:
|
||||
self.connection.setKeepAlive(connection_manager.keepalive_interval, connection_manager.keepalive_count)
|
||||
self.connection.setKeepAlive(
|
||||
connection_manager.keepalive_interval, connection_manager.keepalive_count
|
||||
)
|
||||
try:
|
||||
self.connection.registerCloseCallback(self.__connection_close_callback, None)
|
||||
except:
|
||||
except Exception:
|
||||
# Temporary fix for libvirt > libvirt-0.10.2-41
|
||||
pass
|
||||
except libvirtError as e:
|
||||
|
@ -134,49 +139,49 @@ class wvmConnection(object):
|
|||
def __connect_tcp(self):
|
||||
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
|
||||
auth = [flags, self.__libvirt_auth_credentials_callback, None]
|
||||
uri = f'qemu+tcp://{self.host}/system'
|
||||
uri = f"qemu+tcp://{self.host}/system"
|
||||
|
||||
try:
|
||||
self.connection = libvirt.openAuth(uri, auth, 0)
|
||||
self.last_error = None
|
||||
|
||||
except libvirtError as e:
|
||||
self.last_error = f'Connection Failed: {str(e)}'
|
||||
self.last_error = f"Connection Failed: {str(e)}"
|
||||
self.connection = None
|
||||
|
||||
def __connect_ssh(self):
|
||||
uri = 'qemu+ssh://%s@%s/system' % (self.login, self.host)
|
||||
uri = "qemu+ssh://%s@%s/system" % (self.login, self.host)
|
||||
|
||||
try:
|
||||
self.connection = libvirt.open(uri)
|
||||
self.last_error = None
|
||||
|
||||
except libvirtError as e:
|
||||
self.last_error = f'Connection Failed: {str(e)} --- ' + repr(libvirt.virGetLastError())
|
||||
self.last_error = f"Connection Failed: {str(e)} --- " + repr(libvirt.virGetLastError())
|
||||
self.connection = None
|
||||
|
||||
def __connect_tls(self):
|
||||
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
|
||||
auth = [flags, self.__libvirt_auth_credentials_callback, None]
|
||||
uri = 'qemu+tls://%s@%s/system' % (self.login, self.host)
|
||||
uri = "qemu+tls://%s@%s/system" % (self.login, self.host)
|
||||
|
||||
try:
|
||||
self.connection = libvirt.openAuth(uri, auth, 0)
|
||||
self.last_error = None
|
||||
|
||||
except libvirtError as e:
|
||||
self.last_error = f'Connection Failed: {str(e)}'
|
||||
self.last_error = f"Connection Failed: {str(e)}"
|
||||
self.connection = None
|
||||
|
||||
def __connect_socket(self):
|
||||
uri = 'qemu:///system'
|
||||
uri = "qemu:///system"
|
||||
|
||||
try:
|
||||
self.connection = libvirt.open(uri)
|
||||
self.last_error = None
|
||||
|
||||
except libvirtError as e:
|
||||
self.last_error = f'Connection Failed: {str(e)}'
|
||||
self.last_error = f"Connection Failed: {str(e)}"
|
||||
self.connection = None
|
||||
|
||||
def close(self):
|
||||
|
@ -202,23 +207,23 @@ class wvmConnection(object):
|
|||
# unregister callback (as it is no longer valid if this instance gets deleted)
|
||||
try:
|
||||
self.connection.unregisterCloseCallback()
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
if self.type == CONN_TCP:
|
||||
type_str = 'tcp'
|
||||
type_str = "tcp"
|
||||
elif self.type == CONN_SSH:
|
||||
type_str = 'ssh'
|
||||
type_str = "ssh"
|
||||
elif self.type == CONN_TLS:
|
||||
type_str = 'tls'
|
||||
type_str = "tls"
|
||||
else:
|
||||
type_str = 'invalid_type'
|
||||
type_str = "invalid_type"
|
||||
|
||||
return f'qemu+{type_str}://{self.login}@{self.host}/system'
|
||||
return f"qemu+{type_str}://{self.login}@{self.host}/system"
|
||||
|
||||
def __repr__(self):
|
||||
return f'<wvmConnection {str(self)}>'
|
||||
return f"<wvmConnection {str(self)}>"
|
||||
|
||||
|
||||
class wvmConnectionManager(object):
|
||||
|
@ -307,7 +312,7 @@ class wvmConnectionManager(object):
|
|||
socket_host = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
socket_host.settimeout(1)
|
||||
if conn_type == CONN_SSH:
|
||||
if ':' in hostname:
|
||||
if ":" in hostname:
|
||||
libvirt_host, PORT = hostname.split(":")
|
||||
PORT = int(PORT)
|
||||
else:
|
||||
|
@ -320,7 +325,7 @@ class wvmConnectionManager(object):
|
|||
socket_host.connect((hostname, TLS_PORT))
|
||||
if conn_type == CONN_SOCKET:
|
||||
socket_host = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
socket_host.connect('/var/run/libvirt/libvirt-sock')
|
||||
socket_host.connect("/var/run/libvirt/libvirt-sock")
|
||||
socket_host.close()
|
||||
return True
|
||||
except Exception as err:
|
||||
|
@ -328,8 +333,8 @@ class wvmConnectionManager(object):
|
|||
|
||||
|
||||
connection_manager = wvmConnectionManager(
|
||||
settings.LIBVIRT_KEEPALIVE_INTERVAL if hasattr(settings, 'LIBVIRT_KEEPALIVE_INTERVAL') else 5,
|
||||
settings.LIBVIRT_KEEPALIVE_COUNT if hasattr(settings, 'LIBVIRT_KEEPALIVE_COUNT') else 5,
|
||||
settings.LIBVIRT_KEEPALIVE_INTERVAL if hasattr(settings, "LIBVIRT_KEEPALIVE_INTERVAL") else 5,
|
||||
settings.LIBVIRT_KEEPALIVE_COUNT if hasattr(settings, "LIBVIRT_KEEPALIVE_COUNT") else 5,
|
||||
)
|
||||
|
||||
|
||||
|
@ -353,15 +358,16 @@ class wvmConnect(object):
|
|||
def get_dom_cap_xml(self, arch, machine):
|
||||
""" Return domain capabilities xml"""
|
||||
emulatorbin = self.get_emulator(arch)
|
||||
virttype = 'kvm' if 'kvm' in self.get_hypervisors_domain_types()[arch] else 'qemu'
|
||||
virttype = "kvm" if "kvm" in self.get_hypervisors_domain_types()[arch] else "qemu"
|
||||
|
||||
machine_types = self.get_machine_types(arch)
|
||||
if not machine or machine not in machine_types:
|
||||
machine = 'pc' if 'pc' in machine_types else machine_types[0]
|
||||
machine = "pc" if "pc" in machine_types else machine_types[0]
|
||||
return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype)
|
||||
|
||||
def get_capabilities(self, arch):
|
||||
""" Host Capabilities for specified architecture """
|
||||
|
||||
def guests(ctx):
|
||||
result = dict()
|
||||
for arch_el in ctx.xpath("/capabilities/guest/arch[@name='{}']".format(arch)):
|
||||
|
@ -371,11 +377,9 @@ class wvmConnect(object):
|
|||
|
||||
result["machines"] = []
|
||||
for m in arch_el.xpath("machine"):
|
||||
result["machines"].append({
|
||||
"machine": m.text,
|
||||
"max_cpu": m.get("maxCpus"),
|
||||
"canonical": m.get("canonical")
|
||||
})
|
||||
result["machines"].append(
|
||||
{"machine": m.text, "max_cpu": m.get("maxCpus"), "canonical": m.get("canonical")}
|
||||
)
|
||||
|
||||
guest_el = arch_el.getparent()
|
||||
for f in guest_el.xpath("features"):
|
||||
|
@ -400,7 +404,7 @@ class wvmConnect(object):
|
|||
result["os_support"] = util.get_xml_path(xml, "/domainCapabilities/os/@supported")
|
||||
|
||||
result["loader_support"] = util.get_xml_path(xml, "/domainCapabilities/os/loader/@supported")
|
||||
if result["loader_support"] == 'yes':
|
||||
if result["loader_support"] == "yes":
|
||||
result["loaders"] = self.get_os_loaders(arch, machine)
|
||||
result["loader_enums"] = self.get_os_loader_enums(arch, machine)
|
||||
|
||||
|
@ -410,27 +414,29 @@ class wvmConnect(object):
|
|||
result["cpu_custom_models"] = self.get_cpu_custom_types(arch, machine)
|
||||
|
||||
result["disk_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/disk/@supported")
|
||||
if result["disk_support"] == 'yes':
|
||||
if result["disk_support"] == "yes":
|
||||
result["disk_devices"] = self.get_disk_device_types(arch, machine)
|
||||
result["disk_bus"] = self.get_disk_bus_types(arch, machine)
|
||||
|
||||
result["graphics_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/graphics/@supported")
|
||||
if result["graphics_support"] == 'yes':
|
||||
if result["graphics_support"] == "yes":
|
||||
result["graphics_types"] = self.get_graphics_types(arch, machine)
|
||||
|
||||
result["video_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/video/@supported")
|
||||
if result["video_support"] == 'yes':
|
||||
if result["video_support"] == "yes":
|
||||
result["video_types"] = self.get_video_models(arch, machine)
|
||||
|
||||
result["hostdev_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/hostdev/@supported")
|
||||
if result["hostdev_support"] == 'yes':
|
||||
if result["hostdev_support"] == "yes":
|
||||
result["hostdev_types"] = self.get_hostdev_modes(arch, machine)
|
||||
result["hostdev_startup_policies"] = self.get_hostdev_startup_policies(arch, machine)
|
||||
result["hostdev_subsys_types"] = self.get_hostdev_subsys_types(arch, machine)
|
||||
|
||||
result["features_gic_support"] = util.get_xml_path(xml, "/domainCapabilities/features/gic/@supported")
|
||||
result["features_genid_support"] = util.get_xml_path(xml, "/domainCapabilities/features/genid/@supported")
|
||||
result["features_vmcoreinfo_support"] = util.get_xml_path(xml, "/domainCapabilities/features/vmcoreinfo/@supported")
|
||||
result["features_vmcoreinfo_support"] = util.get_xml_path(
|
||||
xml, "/domainCapabilities/features/vmcoreinfo/@supported"
|
||||
)
|
||||
result["features_sev_support"] = util.get_xml_path(xml, "/domainCapabilities/features/sev/@supported")
|
||||
|
||||
return result
|
||||
|
@ -510,12 +516,12 @@ class wvmConnect(object):
|
|||
:return: Get cache available modes
|
||||
"""
|
||||
return {
|
||||
'default': 'Default',
|
||||
'none': 'Disabled',
|
||||
'writethrough': 'Write through',
|
||||
'writeback': 'Write back',
|
||||
'directsync': 'Direct sync', # since libvirt 0.9.5
|
||||
'unsafe': 'Unsafe', # since libvirt 0.9.7
|
||||
"default": "Default",
|
||||
"none": "Disabled",
|
||||
"writethrough": "Write through",
|
||||
"writeback": "Write back",
|
||||
"directsync": "Direct sync", # since libvirt 0.9.5
|
||||
"unsafe": "Unsafe", # since libvirt 0.9.7
|
||||
}
|
||||
|
||||
def get_io_modes(self):
|
||||
|
@ -523,9 +529,9 @@ class wvmConnect(object):
|
|||
:return: available io modes
|
||||
"""
|
||||
return {
|
||||
'default': 'Default',
|
||||
'native': 'Native',
|
||||
'threads': 'Threads',
|
||||
"default": "Default",
|
||||
"native": "Native",
|
||||
"threads": "Threads",
|
||||
}
|
||||
|
||||
def get_discard_modes(self):
|
||||
|
@ -533,9 +539,9 @@ class wvmConnect(object):
|
|||
:return: available discard modes
|
||||
"""
|
||||
return {
|
||||
'default': 'Default',
|
||||
'ignore': 'Ignore',
|
||||
'unmap': 'Unmap',
|
||||
"default": "Default",
|
||||
"ignore": "Ignore",
|
||||
"unmap": "Unmap",
|
||||
}
|
||||
|
||||
def get_detect_zeroes_modes(self):
|
||||
|
@ -543,21 +549,22 @@ class wvmConnect(object):
|
|||
:return: available detect zeroes modes
|
||||
"""
|
||||
return {
|
||||
'default': 'Default',
|
||||
'on': 'On',
|
||||
'off': 'Off',
|
||||
'unmap': 'Unmap',
|
||||
"default": "Default",
|
||||
"on": "On",
|
||||
"off": "Off",
|
||||
"unmap": "Unmap",
|
||||
}
|
||||
|
||||
def get_hypervisors_domain_types(self):
|
||||
"""
|
||||
:return: hypervisor domain types
|
||||
"""
|
||||
|
||||
def hypervisors(ctx):
|
||||
result = {}
|
||||
for arch in ctx.xpath('/capabilities/guest/arch'):
|
||||
domain_types = arch.xpath('domain/@type')
|
||||
arch_name = arch.xpath('@name')[0]
|
||||
for arch in ctx.xpath("/capabilities/guest/arch"):
|
||||
domain_types = arch.xpath("domain/@type")
|
||||
arch_name = arch.xpath("@name")[0]
|
||||
result[arch_name] = domain_types
|
||||
return result
|
||||
|
||||
|
@ -567,9 +574,10 @@ class wvmConnect(object):
|
|||
"""
|
||||
:return: hypervisor and its machine types
|
||||
"""
|
||||
|
||||
def machines(ctx):
|
||||
result = dict()
|
||||
for arche in ctx.xpath('/capabilities/guest/arch'):
|
||||
for arche in ctx.xpath("/capabilities/guest/arch"):
|
||||
arch = arche.get("name")
|
||||
|
||||
result[arch] = self.get_machine_types(arch)
|
||||
|
@ -587,6 +595,7 @@ class wvmConnect(object):
|
|||
"""
|
||||
:return: canonical(if exist) name of machine types
|
||||
"""
|
||||
|
||||
def machines(ctx):
|
||||
result = list()
|
||||
canonical_name = ctx.xpath("/capabilities/guest/arch[@name='{}']/machine[@canonical]".format(arch))
|
||||
|
@ -602,22 +611,24 @@ class wvmConnect(object):
|
|||
"""
|
||||
:return: host emulators list
|
||||
"""
|
||||
|
||||
def emulators(ctx):
|
||||
result = {}
|
||||
for arch in ctx.xpath('/capabilities/guest/arch'):
|
||||
emulator = arch.xpath('emulator')
|
||||
arch_name = arch.xpath('@name')[0]
|
||||
for arch in ctx.xpath("/capabilities/guest/arch"):
|
||||
emulator = arch.xpath("emulator")
|
||||
arch_name = arch.xpath("@name")[0]
|
||||
result[arch_name] = emulator
|
||||
return result
|
||||
|
||||
return util.get_xml_path(self.get_cap_xml(), func=emulators)
|
||||
|
||||
def get_os_loaders(self, arch='x86_64', machine='pc'):
|
||||
def get_os_loaders(self, arch="x86_64", machine="pc"):
|
||||
"""
|
||||
:param arch: architecture
|
||||
:param machine:
|
||||
:return: available os loaders list
|
||||
"""
|
||||
|
||||
def get_os_loaders(ctx):
|
||||
return [v.text for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/value")]
|
||||
|
||||
|
@ -629,6 +640,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available os loaders list
|
||||
"""
|
||||
|
||||
def get_os_loader_enums(ctx):
|
||||
result = dict()
|
||||
enums = [v for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/enum/@name")]
|
||||
|
@ -645,6 +657,7 @@ class wvmConnect(object):
|
|||
:param arch:
|
||||
:return: available disk bus types list
|
||||
"""
|
||||
|
||||
def get_bus_list(ctx):
|
||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='bus']/value")]
|
||||
|
||||
|
@ -657,6 +670,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available disk device type list
|
||||
"""
|
||||
|
||||
def get_device_list(ctx):
|
||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='diskDevice']/value")]
|
||||
|
||||
|
@ -669,6 +683,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available graphics types
|
||||
"""
|
||||
|
||||
def get_graphics_list(ctx):
|
||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/graphics/enum[@name='type']/value")]
|
||||
|
||||
|
@ -680,6 +695,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available cpu modes
|
||||
"""
|
||||
|
||||
def get_cpu_modes(ctx):
|
||||
return [v for v in ctx.xpath("/domainCapabilities/cpu/mode[@supported='yes']/@name")]
|
||||
|
||||
|
@ -691,6 +707,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available graphics types
|
||||
"""
|
||||
|
||||
def get_custom_list(ctx):
|
||||
usable_yes = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='yes']"
|
||||
usable_unknown = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='unknown']"
|
||||
|
@ -706,6 +723,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return. available nodedev modes
|
||||
"""
|
||||
|
||||
def get_hostdev_list(ctx):
|
||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='mode']/value")]
|
||||
|
||||
|
@ -717,6 +735,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available hostdev modes
|
||||
"""
|
||||
|
||||
def get_hostdev_list(ctx):
|
||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='startupPolicy']/value")]
|
||||
|
||||
|
@ -728,6 +747,7 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available nodedev sub system types
|
||||
"""
|
||||
|
||||
def get_hostdev_list(ctx):
|
||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='subsysType']/value")]
|
||||
|
||||
|
@ -737,19 +757,19 @@ class wvmConnect(object):
|
|||
"""
|
||||
:return: network card models
|
||||
"""
|
||||
return ['default', 'e1000', 'virtio']
|
||||
return ["default", "e1000", "virtio"]
|
||||
|
||||
def get_image_formats(self):
|
||||
"""
|
||||
:return: available image formats
|
||||
"""
|
||||
return ['raw', 'qcow', 'qcow2']
|
||||
return ["raw", "qcow", "qcow2"]
|
||||
|
||||
def get_file_extensions(self):
|
||||
"""
|
||||
:return: available image filename extensions
|
||||
"""
|
||||
return ['img', 'qcow', 'qcow2']
|
||||
return ["img", "qcow", "qcow2"]
|
||||
|
||||
def get_video_models(self, arch, machine):
|
||||
"""
|
||||
|
@ -757,9 +777,10 @@ class wvmConnect(object):
|
|||
:param machine:
|
||||
:return: available graphics video types
|
||||
"""
|
||||
|
||||
def get_video_list(ctx):
|
||||
result = []
|
||||
for video_enum in ctx.xpath('/domainCapabilities/devices/video/enum'):
|
||||
for video_enum in ctx.xpath("/domainCapabilities/devices/video/enum"):
|
||||
if video_enum.xpath("@name")[0] == "modelType":
|
||||
for values in video_enum:
|
||||
result.append(values.text)
|
||||
|
@ -787,8 +808,8 @@ class wvmConnect(object):
|
|||
|
||||
def get_network_forward(self, net_name):
|
||||
def get_forward(doc):
|
||||
forward_mode = util.get_xpath(doc, '/network/forward/@mode')
|
||||
return forward_mode or 'isolated'
|
||||
forward_mode = util.get_xpath(doc, "/network/forward/@mode")
|
||||
return forward_mode or "isolated"
|
||||
|
||||
net = self.get_network(net_name)
|
||||
xml = net.XMLDesc(0)
|
||||
|
@ -825,14 +846,14 @@ class wvmConnect(object):
|
|||
netdevice = []
|
||||
|
||||
def get_info(doc):
|
||||
dev_type = util.get_xpath(doc, '/device/capability/@type')
|
||||
interface = util.get_xpath(doc, '/device/capability/interface')
|
||||
dev_type = util.get_xpath(doc, "/device/capability/@type")
|
||||
interface = util.get_xpath(doc, "/device/capability/interface")
|
||||
return dev_type, interface
|
||||
|
||||
for dev in self.wvm.listAllDevices(0):
|
||||
xml = dev.XMLDesc(0)
|
||||
(dev_type, interface) = util.get_xml_path(xml, func=get_info)
|
||||
if dev_type == 'net':
|
||||
if dev_type == "net":
|
||||
netdevice.append(interface)
|
||||
return netdevice
|
||||
|
||||
|
@ -850,9 +871,9 @@ class wvmConnect(object):
|
|||
else:
|
||||
vcpu = util.get_xpath(doc, "/domain/vcpu")
|
||||
title = util.get_xpath(doc, "/domain/title")
|
||||
title = title if title else ''
|
||||
title = title if title else ""
|
||||
description = util.get_xpath(doc, "/domain/description")
|
||||
description = description if description else ''
|
||||
description = description if description else ""
|
||||
return mem, vcpu, title, description
|
||||
|
||||
for name in self.get_instances():
|
||||
|
@ -860,12 +881,12 @@ class wvmConnect(object):
|
|||
xml = dom.XMLDesc(0)
|
||||
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
|
||||
vname[dom.name()] = {
|
||||
'status': dom.info()[0],
|
||||
'uuid': dom.UUIDString(),
|
||||
'vcpu': vcpu,
|
||||
'memory': mem,
|
||||
'title': title,
|
||||
'description': description,
|
||||
"status": dom.info()[0],
|
||||
"uuid": dom.UUIDString(),
|
||||
"vcpu": vcpu,
|
||||
"memory": mem,
|
||||
"title": title,
|
||||
"description": description,
|
||||
}
|
||||
return vname
|
||||
|
||||
|
@ -882,20 +903,20 @@ class wvmConnect(object):
|
|||
else:
|
||||
vcpu = util.get_xpath(ctx, "/domain/vcpu")
|
||||
title = util.get_xpath(ctx, "/domain/title")
|
||||
title = title if title else ''
|
||||
title = title if title else ""
|
||||
description = util.get_xpath(ctx, "/domain/description")
|
||||
description = description if description else ''
|
||||
description = description if description else ""
|
||||
return mem, vcpu, title, description
|
||||
|
||||
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
|
||||
return {
|
||||
'name': dom.name(),
|
||||
'status': dom.info()[0],
|
||||
'uuid': dom.UUIDString(),
|
||||
'vcpu': vcpu,
|
||||
'memory': mem,
|
||||
'title': title,
|
||||
'description': description,
|
||||
"name": dom.name(),
|
||||
"status": dom.info()[0],
|
||||
"uuid": dom.UUIDString(),
|
||||
"vcpu": vcpu,
|
||||
"memory": mem,
|
||||
"title": title,
|
||||
"description": description,
|
||||
}
|
||||
|
||||
def close(self):
|
||||
|
@ -931,7 +952,7 @@ class wvmConnect(object):
|
|||
for arch, patterns in util.UEFI_ARCH_PATTERNS.items():
|
||||
for pattern in patterns:
|
||||
if re.match(pattern, path):
|
||||
return ("UEFI %(arch)s: %(path)s" % {"arch": arch, "path": path})
|
||||
return "UEFI %(arch)s: %(path)s" % {"arch": arch, "path": path}
|
||||
|
||||
return "Custom: %(path)s" % {"path": path}
|
||||
|
||||
|
@ -945,15 +966,17 @@ class wvmConnect(object):
|
|||
"""
|
||||
Return True if libvirt advertises support for proper UEFI setup
|
||||
"""
|
||||
return ("readonly" in loader_enums and "yes" in loader_enums.get("readonly"))
|
||||
return "readonly" in loader_enums and "yes" in loader_enums.get("readonly")
|
||||
|
||||
def is_supports_virtio(self, arch, machine):
|
||||
if not self.is_qemu():
|
||||
return False
|
||||
|
||||
# These _only_ support virtio so don't check the OS
|
||||
if arch in ["aarch64", "armv7l", "ppc64", "ppc64le", "s390x", "riscv64", "riscv32"] and \
|
||||
machine in ["virt", "pseries"]:
|
||||
if arch in ["aarch64", "armv7l", "ppc64", "ppc64le", "s390x", "riscv64", "riscv32"] and machine in [
|
||||
"virt",
|
||||
"pseries",
|
||||
]:
|
||||
return True
|
||||
|
||||
if arch in ["x86_64", "i686"]:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import string
|
||||
|
||||
from vrtManager import util
|
||||
from vrtManager.connection import wvmConnect
|
||||
|
||||
|
@ -12,15 +13,15 @@ def get_rbd_storage_data(stg):
|
|||
for host in doc.xpath("/pool/source/host"):
|
||||
name = host.prop("name")
|
||||
if name:
|
||||
hosts.append({'name': name, 'port': host.prop("port")})
|
||||
hosts.append({"name": name, "port": host.prop("port")})
|
||||
return hosts
|
||||
|
||||
ceph_hosts = util.get_xml_path(xml, func=get_ceph_hosts)
|
||||
secret_uuid = util.get_xml_path(xml, "/pool/source/auth/secret/@uuid")
|
||||
return ceph_user, secret_uuid, ceph_hosts
|
||||
|
||||
|
||||
class wvmCreate(wvmConnect):
|
||||
|
||||
def get_storages_images(self):
|
||||
"""
|
||||
Function return all images on all storages
|
||||
|
@ -31,10 +32,10 @@ class wvmCreate(wvmConnect):
|
|||
stg = self.get_storage(storage)
|
||||
try:
|
||||
stg.refresh(0)
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
for img in stg.listVolumes():
|
||||
if img.lower().endswith('.iso'):
|
||||
if img.lower().endswith(".iso"):
|
||||
pass
|
||||
else:
|
||||
images.append(img)
|
||||
|
@ -52,11 +53,11 @@ class wvmCreate(wvmConnect):
|
|||
size = int(size) * 1073741824
|
||||
stg = self.get_storage(storage)
|
||||
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||
if storage_type == 'dir':
|
||||
if image_format in ('qcow', 'qcow2'):
|
||||
name += '.' + image_format
|
||||
if storage_type == "dir":
|
||||
if image_format in ("qcow", "qcow2"):
|
||||
name += "." + image_format
|
||||
else:
|
||||
name += '.img'
|
||||
name += ".img"
|
||||
alloc = 0
|
||||
else:
|
||||
alloc = size
|
||||
|
@ -91,12 +92,12 @@ class wvmCreate(wvmConnect):
|
|||
def get_volume_type(self, path):
|
||||
vol = self.get_volume_by_path(path)
|
||||
vol_type = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||
if vol_type == 'unknown' or vol_type == 'iso':
|
||||
return 'raw'
|
||||
if vol_type == "unknown" or vol_type == "iso":
|
||||
return "raw"
|
||||
if vol_type:
|
||||
return vol_type
|
||||
else:
|
||||
return 'raw'
|
||||
return "raw"
|
||||
|
||||
def get_volume_path(self, volume, pool=None):
|
||||
if not pool:
|
||||
|
@ -125,8 +126,8 @@ class wvmCreate(wvmConnect):
|
|||
|
||||
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||
format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||
if storage_type == 'dir':
|
||||
clone += '.img'
|
||||
if storage_type == "dir":
|
||||
clone += ".img"
|
||||
else:
|
||||
metadata = False
|
||||
xml = f"""
|
||||
|
@ -159,9 +160,27 @@ class wvmCreate(wvmConnect):
|
|||
vol = self.get_volume_by_path(path)
|
||||
vol.delete()
|
||||
|
||||
def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, volumes,
|
||||
networks, nwfilter, graphics, virtio, listen_addr,
|
||||
video="vga", console_pass="random", mac=None, qemu_ga=True):
|
||||
def create_instance(
|
||||
self,
|
||||
name,
|
||||
memory,
|
||||
vcpu,
|
||||
vcpu_mode,
|
||||
uuid,
|
||||
arch,
|
||||
machine,
|
||||
firmware,
|
||||
volumes,
|
||||
networks,
|
||||
nwfilter,
|
||||
graphics,
|
||||
virtio,
|
||||
listen_addr,
|
||||
video="vga",
|
||||
console_pass="random",
|
||||
mac=None,
|
||||
qemu_ga=True,
|
||||
):
|
||||
"""
|
||||
Create VM function
|
||||
"""
|
||||
|
@ -178,33 +197,37 @@ class wvmCreate(wvmConnect):
|
|||
<memory unit='KiB'>{memory}</memory>
|
||||
<vcpu>{vcpu}</vcpu>"""
|
||||
|
||||
if dom_caps["os_support"] == 'yes':
|
||||
if dom_caps["os_support"] == "yes":
|
||||
xml += f"""<os>
|
||||
<type arch='{arch}' machine='{machine}'>{caps["os_type"]}</type>"""
|
||||
xml += """ <boot dev='hd'/>
|
||||
<boot dev='cdrom'/>
|
||||
<bootmenu enable='yes'/>"""
|
||||
if firmware:
|
||||
if firmware["secure"] == 'yes':
|
||||
xml += """<loader readonly='%s' type='%s' secure='%s'>%s</loader>""" % (firmware["readonly"],
|
||||
firmware["type"],
|
||||
firmware["secure"],
|
||||
firmware["loader"])
|
||||
if firmware["secure"] == 'no':
|
||||
xml += """<loader readonly='%s' type='%s'>%s</loader>""" % (firmware["readonly"],
|
||||
firmware["type"],
|
||||
firmware["loader"])
|
||||
if firmware["secure"] == "yes":
|
||||
xml += """<loader readonly='%s' type='%s' secure='%s'>%s</loader>""" % (
|
||||
firmware["readonly"],
|
||||
firmware["type"],
|
||||
firmware["secure"],
|
||||
firmware["loader"],
|
||||
)
|
||||
if firmware["secure"] == "no":
|
||||
xml += """<loader readonly='%s' type='%s'>%s</loader>""" % (
|
||||
firmware["readonly"],
|
||||
firmware["type"],
|
||||
firmware["loader"],
|
||||
)
|
||||
xml += """</os>"""
|
||||
|
||||
if caps["features"]:
|
||||
xml += """<features>"""
|
||||
if 'acpi' in caps["features"]:
|
||||
if "acpi" in caps["features"]:
|
||||
xml += """<acpi/>"""
|
||||
if 'apic' in caps["features"]:
|
||||
if "apic" in caps["features"]:
|
||||
xml += """<apic/>"""
|
||||
if 'pae' in caps["features"]:
|
||||
if "pae" in caps["features"]:
|
||||
xml += """<pae/>"""
|
||||
if firmware.get("secure", 'no') == 'yes':
|
||||
if firmware.get("secure", "no") == "yes":
|
||||
xml += """<smm state="on"/>"""
|
||||
xml += """</features>"""
|
||||
|
||||
|
@ -235,56 +258,69 @@ class wvmCreate(wvmConnect):
|
|||
|
||||
for volume in volumes:
|
||||
|
||||
disk_opts = ''
|
||||
if volume['cache_mode'] is not None and volume['cache_mode'] != 'default':
|
||||
disk_opts = ""
|
||||
if volume["cache_mode"] is not None and volume["cache_mode"] != "default":
|
||||
disk_opts += f"cache='{volume['cache_mode']}' "
|
||||
if volume['io_mode'] is not None and volume['io_mode'] != 'default':
|
||||
if volume["io_mode"] is not None and volume["io_mode"] != "default":
|
||||
disk_opts += f"io='{volume['io_mode']}' "
|
||||
if volume['discard_mode'] is not None and volume['discard_mode'] != 'default':
|
||||
if volume["discard_mode"] is not None and volume["discard_mode"] != "default":
|
||||
disk_opts += f"discard='{volume['discard_mode']}' "
|
||||
if volume['detect_zeroes_mode'] is not None and volume['detect_zeroes_mode'] != 'default':
|
||||
if volume["detect_zeroes_mode"] is not None and volume["detect_zeroes_mode"] != "default":
|
||||
disk_opts += f"detect_zeroes='{volume['detect_zeroes_mode']}' "
|
||||
|
||||
stg = self.get_storage_by_vol_path(volume['path'])
|
||||
stg = self.get_storage_by_vol_path(volume["path"])
|
||||
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||
|
||||
if volume['device'] == 'cdrom': add_cd = False
|
||||
if volume["device"] == "cdrom":
|
||||
add_cd = False
|
||||
|
||||
if stg_type == 'rbd':
|
||||
if stg_type == "rbd":
|
||||
ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg)
|
||||
xml += """<disk type='network' device='disk'>
|
||||
<driver name='qemu' type='%s' %s />""" % (volume['type'], disk_opts)
|
||||
<driver name='qemu' type='%s' %s />""" % (
|
||||
volume["type"],
|
||||
disk_opts,
|
||||
)
|
||||
xml += """ <auth username='%s'>
|
||||
<secret type='ceph' uuid='%s'/>
|
||||
</auth>
|
||||
<source protocol='rbd' name='%s'>""" % (ceph_user, secret_uuid, volume['path'])
|
||||
<source protocol='rbd' name='%s'>""" % (
|
||||
ceph_user,
|
||||
secret_uuid,
|
||||
volume["path"],
|
||||
)
|
||||
if isinstance(ceph_hosts, list):
|
||||
for host in ceph_hosts:
|
||||
if host.get('port'):
|
||||
if host.get("port"):
|
||||
xml += """
|
||||
<host name='%s' port='%s'/>""" % (host.get('name'), host.get('port'))
|
||||
<host name='%s' port='%s'/>""" % (
|
||||
host.get("name"),
|
||||
host.get("port"),
|
||||
)
|
||||
else:
|
||||
xml += """
|
||||
<host name='%s'/>""" % host.get('name')
|
||||
<host name='%s'/>""" % host.get(
|
||||
"name"
|
||||
)
|
||||
xml += """</source>"""
|
||||
else:
|
||||
xml += """<disk type='file' device='%s'>""" % volume['device']
|
||||
xml += """ <driver name='qemu' type='%s' %s/>""" % (volume['type'], disk_opts)
|
||||
xml += f""" <source file='%s'/>""" % volume['path']
|
||||
xml += """<disk type='file' device='%s'>""" % volume["device"]
|
||||
xml += """ <driver name='qemu' type='%s' %s/>""" % (volume["type"], disk_opts)
|
||||
xml += """ <source file='%s'/>""" % volume["path"]
|
||||
|
||||
if volume.get('bus') == 'virtio':
|
||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume.get('bus'))
|
||||
elif volume.get('bus') == 'ide':
|
||||
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), volume.get('bus'))
|
||||
elif volume.get('bus') == 'fdc':
|
||||
xml += """<target dev='fd%s' bus='%s'/>""" % (fd_disk_letters.pop(0), volume.get('bus'))
|
||||
elif volume.get('bus') == 'sata' or volume.get('bus') == 'scsi':
|
||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume.get('bus'))
|
||||
if volume.get("bus") == "virtio":
|
||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume.get("bus"))
|
||||
elif volume.get("bus") == "ide":
|
||||
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), volume.get("bus"))
|
||||
elif volume.get("bus") == "fdc":
|
||||
xml += """<target dev='fd%s' bus='%s'/>""" % (fd_disk_letters.pop(0), volume.get("bus"))
|
||||
elif volume.get("bus") == "sata" or volume.get("bus") == "scsi":
|
||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume.get("bus"))
|
||||
else:
|
||||
xml += """<target dev='sd%s'/>""" % sd_disk_letters.pop(0)
|
||||
xml += """</disk>"""
|
||||
|
||||
if volume.get('bus') == 'scsi':
|
||||
if volume.get("bus") == "scsi":
|
||||
xml += f"""<controller type='scsi' model='{volume.get('scsi_model')}'/>"""
|
||||
|
||||
if add_cd:
|
||||
|
@ -292,17 +328,17 @@ class wvmCreate(wvmConnect):
|
|||
<driver name='qemu' type='raw'/>
|
||||
<source file = '' />
|
||||
<readonly/>"""
|
||||
if 'ide' in dom_caps['disk_bus']:
|
||||
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), 'ide')
|
||||
elif 'sata' in dom_caps['disk_bus']:
|
||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'sata')
|
||||
elif 'scsi' in dom_caps['disk_bus']:
|
||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'scsi')
|
||||
if "ide" in dom_caps["disk_bus"]:
|
||||
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), "ide")
|
||||
elif "sata" in dom_caps["disk_bus"]:
|
||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), "sata")
|
||||
elif "scsi" in dom_caps["disk_bus"]:
|
||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), "scsi")
|
||||
else:
|
||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), 'virtio')
|
||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), "virtio")
|
||||
xml += """</disk>"""
|
||||
|
||||
for net in networks.split(','):
|
||||
for net in networks.split(","):
|
||||
xml += """<interface type='network'>"""
|
||||
if mac:
|
||||
xml += f"""<mac address='{mac}'/>"""
|
||||
|
@ -319,10 +355,10 @@ class wvmCreate(wvmConnect):
|
|||
if not console_pass == "":
|
||||
console_pass = "passwd='" + console_pass + "'"
|
||||
|
||||
if 'usb' in dom_caps['disk_bus']:
|
||||
xml += """<input type='mouse' bus='{}'/>""".format('virtio' if virtio else 'usb')
|
||||
xml += """<input type='keyboard' bus='{}'/>""".format('virtio' if virtio else 'usb')
|
||||
xml += """<input type='tablet' bus='{}'/>""".format('virtio' if virtio else 'usb')
|
||||
if "usb" in dom_caps["disk_bus"]:
|
||||
xml += """<input type='mouse' bus='{}'/>""".format("virtio" if virtio else "usb")
|
||||
xml += """<input type='keyboard' bus='{}'/>""".format("virtio" if virtio else "usb")
|
||||
xml += """<input type='tablet' bus='{}'/>""".format("virtio" if virtio else "usb")
|
||||
else:
|
||||
xml += """<input type='mouse'/>"""
|
||||
xml += """<input type='keyboard'/>"""
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import time
|
||||
|
||||
from vrtManager.connection import wvmConnect
|
||||
from vrtManager.util import get_xml_path
|
||||
|
||||
|
||||
def cpu_version(doc):
|
||||
for info in doc.xpath('/sysinfo/processor/entry'):
|
||||
elem = info.xpath('@name')[0]
|
||||
if elem == 'version':
|
||||
for info in doc.xpath("/sysinfo/processor/entry"):
|
||||
elem = info.xpath("@name")[0]
|
||||
if elem == "version":
|
||||
return info.text
|
||||
return 'Unknown'
|
||||
return "Unknown"
|
||||
|
||||
|
||||
class wvmHostDetails(wvmConnect):
|
||||
|
@ -19,14 +20,12 @@ class wvmHostDetails(wvmConnect):
|
|||
all_mem = self.wvm.getInfo()[1] * 1048576
|
||||
freemem = self.wvm.getMemoryStats(-1, 0)
|
||||
if isinstance(freemem, dict):
|
||||
free = (freemem['buffers'] +
|
||||
freemem['free'] +
|
||||
freemem['cached']) * 1024
|
||||
free = (freemem["buffers"] + freemem["free"] + freemem["cached"]) * 1024
|
||||
percent = abs(100 - ((free * 100) // all_mem))
|
||||
usage = (all_mem - free)
|
||||
mem_usage = {'total': all_mem, 'usage': usage, 'percent': percent}
|
||||
usage = all_mem - free
|
||||
mem_usage = {"total": all_mem, "usage": usage, "percent": percent}
|
||||
else:
|
||||
mem_usage = {'total': None, 'usage': None, 'percent': None}
|
||||
mem_usage = {"total": None, "usage": None, "percent": None}
|
||||
return mem_usage
|
||||
|
||||
def get_cpu_usage(self):
|
||||
|
@ -38,7 +37,7 @@ class wvmHostDetails(wvmConnect):
|
|||
cpu = self.wvm.getCPUStats(-1, 0)
|
||||
if isinstance(cpu, dict):
|
||||
for num in range(2):
|
||||
idle = self.wvm.getCPUStats(-1, 0)['idle']
|
||||
idle = self.wvm.getCPUStats(-1, 0)["idle"]
|
||||
total = sum(self.wvm.getCPUStats(-1, 0).values())
|
||||
diff_idle = idle - prev_idle
|
||||
diff_total = total - prev_total
|
||||
|
@ -51,8 +50,8 @@ class wvmHostDetails(wvmConnect):
|
|||
if diff_usage < 0:
|
||||
diff_usage = 0
|
||||
else:
|
||||
return {'usage': None}
|
||||
return {'usage': diff_usage}
|
||||
return {"usage": None}
|
||||
return {"usage": diff_usage}
|
||||
|
||||
def get_node_info(self):
|
||||
"""
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
|||
from xml.etree import ElementTree
|
||||
from libvirt import VIR_INTERFACE_XML_INACTIVE
|
||||
from vrtManager.connection import wvmConnect
|
||||
from vrtManager import util
|
||||
|
||||
from libvirt import VIR_INTERFACE_XML_INACTIVE
|
||||
from vrtManager import util
|
||||
from vrtManager.connection import wvmConnect
|
||||
|
||||
|
||||
class wvmInterfaces(wvmConnect):
|
||||
|
@ -12,36 +12,37 @@ class wvmInterfaces(wvmConnect):
|
|||
mac = iface.MACString()
|
||||
itype = util.get_xml_path(xml, "/interface/@type")
|
||||
state = iface.isActive()
|
||||
return {'name': name, 'type': itype, 'state': state, 'mac': mac}
|
||||
return {"name": name, "type": itype, "state": state, "mac": mac}
|
||||
|
||||
def define_iface(self, xml, flag=0):
|
||||
self.wvm.interfaceDefineXML(xml, flag)
|
||||
|
||||
def create_iface(self, name, itype, mode, netdev, ipv4_type, ipv4_addr, ipv4_gw,
|
||||
ipv6_type, ipv6_addr, ipv6_gw, stp, delay):
|
||||
def create_iface(
|
||||
self, name, itype, mode, netdev, ipv4_type, ipv4_addr, ipv4_gw, ipv6_type, ipv6_addr, ipv6_gw, stp, delay
|
||||
):
|
||||
xml = f"""<interface type='{itype}' name='{name}'>
|
||||
<start mode='{mode}'/>"""
|
||||
if ipv4_type == 'dhcp':
|
||||
if ipv4_type == "dhcp":
|
||||
xml += """<protocol family='ipv4'>
|
||||
<dhcp/>
|
||||
</protocol>"""
|
||||
if ipv4_type == 'static':
|
||||
address, prefix = ipv4_addr.split('/')
|
||||
if ipv4_type == "static":
|
||||
address, prefix = ipv4_addr.split("/")
|
||||
xml += f"""<protocol family='ipv4'>
|
||||
<ip address='{address}' prefix='{prefix}'/>
|
||||
<route gateway='{ipv4_gw}'/>
|
||||
</protocol>"""
|
||||
if ipv6_type == 'dhcp':
|
||||
if ipv6_type == "dhcp":
|
||||
xml += """<protocol family='ipv6'>
|
||||
<dhcp/>
|
||||
</protocol>"""
|
||||
if ipv6_type == 'static':
|
||||
address, prefix = ipv6_addr.split('/')
|
||||
if ipv6_type == "static":
|
||||
address, prefix = ipv6_addr.split("/")
|
||||
xml += f"""<protocol family='ipv6'>
|
||||
<ip address='{address}' prefix='{prefix}'/>
|
||||
<route gateway='{ipv6_gw}'/>
|
||||
</protocol>"""
|
||||
if itype == 'bridge':
|
||||
if itype == "bridge":
|
||||
xml += f"""<bridge stp='{stp}' delay='{delay}'>
|
||||
<interface name='{netdev}' type='ethernet'/>
|
||||
</bridge>"""
|
||||
|
@ -85,9 +86,9 @@ class wvmInterface(wvmConnect):
|
|||
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
|
||||
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv4']/ip/@address")
|
||||
if ipaddr:
|
||||
return 'static'
|
||||
return "static"
|
||||
else:
|
||||
return 'dhcp'
|
||||
return "dhcp"
|
||||
except:
|
||||
return None
|
||||
|
||||
|
@ -98,16 +99,16 @@ class wvmInterface(wvmConnect):
|
|||
if not int_ipv4_ip or not int_ipv4_mask:
|
||||
return None
|
||||
else:
|
||||
return int_ipv4_ip + '/' + int_ipv4_mask
|
||||
return int_ipv4_ip + "/" + int_ipv4_mask
|
||||
|
||||
def get_ipv6_type(self):
|
||||
try:
|
||||
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
|
||||
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv6']/ip/@address")
|
||||
if ipaddr:
|
||||
return 'static'
|
||||
return "static"
|
||||
else:
|
||||
return 'dhcp'
|
||||
return "dhcp"
|
||||
except:
|
||||
return None
|
||||
|
||||
|
@ -118,15 +119,15 @@ class wvmInterface(wvmConnect):
|
|||
if not int_ipv6_ip or not int_ipv6_mask:
|
||||
return None
|
||||
else:
|
||||
return int_ipv6_ip + '/' + int_ipv6_mask
|
||||
return int_ipv6_ip + "/" + int_ipv6_mask
|
||||
|
||||
def get_bridge(self):
|
||||
bridge = None
|
||||
if self.get_type() == 'bridge':
|
||||
if self.get_type() == "bridge":
|
||||
bridge = util.get_xml_path(self._XMLDesc(), "/interface/bridge/interface/@name")
|
||||
for iface in self.get_bridge_slave_ifaces():
|
||||
if iface.get('state') == 'up' and iface.get('speed') is not 'unknown':
|
||||
bridge = iface.get('name')
|
||||
if iface.get("state") == "up" and iface.get("speed") != "unknown":
|
||||
bridge = iface.get("name")
|
||||
return bridge
|
||||
return bridge
|
||||
else:
|
||||
|
@ -134,20 +135,20 @@ class wvmInterface(wvmConnect):
|
|||
|
||||
def get_bridge_slave_ifaces(self):
|
||||
ifaces = list()
|
||||
if self.get_type() == 'bridge':
|
||||
if self.get_type() == "bridge":
|
||||
tree = ElementTree.fromstring(self._XMLDesc())
|
||||
for iface in tree.findall("./bridge/"):
|
||||
address = state = speed = None
|
||||
name = iface.get('name')
|
||||
if_type = iface.get('type')
|
||||
link = iface.find('link')
|
||||
name = iface.get("name")
|
||||
if_type = iface.get("type")
|
||||
link = iface.find("link")
|
||||
if link is not None:
|
||||
state = link.get('state')
|
||||
speed = link.get('speed')
|
||||
mac = iface.find('mac')
|
||||
state = link.get("state")
|
||||
speed = link.get("speed")
|
||||
mac = iface.find("mac")
|
||||
if mac is not None:
|
||||
address = mac.get('address')
|
||||
ifaces.append({'name': name, 'type': if_type, 'state': state, 'speed': speed, 'mac': address})
|
||||
address = mac.get("address")
|
||||
ifaces.append({"name": name, "type": if_type, "state": state, "speed": speed, "mac": address})
|
||||
return ifaces
|
||||
else:
|
||||
return None
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
from libvirt import (
|
||||
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||
VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||
VIR_NETWORK_UPDATE_AFFECT_LIVE,
|
||||
VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
|
||||
VIR_NETWORK_UPDATE_COMMAND_DELETE,
|
||||
VIR_NETWORK_UPDATE_COMMAND_MODIFY, libvirtError)
|
||||
from lxml import etree
|
||||
from libvirt import libvirtError
|
||||
from libvirt import VIR_NETWORK_SECTION_IP_DHCP_HOST
|
||||
from libvirt import VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_UPDATE_COMMAND_MODIFY
|
||||
from libvirt import VIR_NETWORK_UPDATE_AFFECT_LIVE, VIR_NETWORK_UPDATE_AFFECT_CONFIG
|
||||
from vrtManager import util
|
||||
from vrtManager.IPy import IP
|
||||
from vrtManager.connection import wvmConnect
|
||||
from vrtManager.IPy import IP
|
||||
|
||||
|
||||
def network_size(subnet, dhcp=None):
|
||||
"""
|
||||
|
@ -17,7 +21,7 @@ def network_size(subnet, dhcp=None):
|
|||
if addr.version() == 4:
|
||||
dhcp_pool = [addr[2].strCompressed(), addr[addr.len() - 2].strCompressed()]
|
||||
if addr.version() == 6:
|
||||
mask = mask.lstrip('/') if '/' in mask else mask
|
||||
mask = mask.lstrip("/") if "/" in mask else mask
|
||||
dhcp_pool = [IP(addr[0].strCompressed() + hex(256)), IP(addr[0].strCompressed() + hex(512 - 1))]
|
||||
if dhcp:
|
||||
return gateway, mask, dhcp_pool
|
||||
|
@ -26,7 +30,6 @@ def network_size(subnet, dhcp=None):
|
|||
|
||||
|
||||
class wvmNetworks(wvmConnect):
|
||||
|
||||
def get_networks_info(self):
|
||||
get_networks = self.get_networks()
|
||||
networks = []
|
||||
|
@ -39,44 +42,55 @@ class wvmNetworks(wvmConnect):
|
|||
net_bridge = util.get_xml_path(net.XMLDesc(0), "/network/forward/interface/@dev")
|
||||
|
||||
net_forward = util.get_xml_path(net.XMLDesc(0), "/network/forward/@mode")
|
||||
networks.append({'name': network, 'status': net_status,
|
||||
'device': net_bridge, 'forward': net_forward})
|
||||
networks.append({"name": network, "status": net_status, "device": net_bridge, "forward": net_forward})
|
||||
return networks
|
||||
|
||||
def define_network(self, xml):
|
||||
self.wvm.networkDefineXML(xml)
|
||||
|
||||
def create_network(self, name, forward,
|
||||
ipv4, gateway, mask, dhcp4,
|
||||
ipv6, gateway6, prefix6, dhcp6,
|
||||
bridge, openvswitch, fixed=False):
|
||||
def create_network(
|
||||
self,
|
||||
name,
|
||||
forward,
|
||||
ipv4,
|
||||
gateway,
|
||||
mask,
|
||||
dhcp4,
|
||||
ipv6,
|
||||
gateway6,
|
||||
prefix6,
|
||||
dhcp6,
|
||||
bridge,
|
||||
openvswitch,
|
||||
fixed=False,
|
||||
):
|
||||
xml = f"""
|
||||
<network>
|
||||
<name>{name}</name>"""
|
||||
if forward in ['nat', 'route', 'bridge']:
|
||||
if forward in ["nat", "route", "bridge"]:
|
||||
xml += f"""<forward mode='{forward}'/>"""
|
||||
if forward == 'macvtap':
|
||||
if forward == "macvtap":
|
||||
xml += f"""<forward mode='bridge'>
|
||||
<interface dev='{bridge}'/>
|
||||
</forward>"""
|
||||
else:
|
||||
xml += """<bridge """
|
||||
if forward in ['nat', 'route', 'none']:
|
||||
if forward in ["nat", "route", "none"]:
|
||||
xml += """stp='on' delay='0'"""
|
||||
if forward == 'bridge':
|
||||
if forward == "bridge":
|
||||
xml += f"""name='{bridge}'"""
|
||||
xml += """/>"""
|
||||
if openvswitch is True:
|
||||
xml += """<virtualport type='openvswitch'/>"""
|
||||
if forward not in ['bridge', 'macvtap']:
|
||||
if forward not in ["bridge", "macvtap"]:
|
||||
if ipv4:
|
||||
xml += f"""<ip address='{gateway}' netmask='{mask}'>"""
|
||||
if dhcp4:
|
||||
xml += f"""<dhcp>
|
||||
<range start='{dhcp4[0]}' end='{dhcp4[1]}' />"""
|
||||
if fixed:
|
||||
fist_oct = int(dhcp4[0].strip().split('.')[3])
|
||||
last_oct = int(dhcp4[1].strip().split('.')[3])
|
||||
fist_oct = int(dhcp4[0].strip().split(".")[3])
|
||||
last_oct = int(dhcp4[1].strip().split(".")[3])
|
||||
for ip in range(fist_oct, last_oct + 1):
|
||||
xml += f"""<host mac='{util.randomMAC()}' ip='{gateway[:-2]}.{ip}' />"""
|
||||
xml += """</dhcp>"""
|
||||
|
@ -144,23 +158,23 @@ class wvmNetwork(wvmConnect):
|
|||
if util.get_xml_path(xml, "/network/ip") is None:
|
||||
return ip_networks
|
||||
tree = etree.fromstring(xml)
|
||||
ips = tree.findall('.ip')
|
||||
ips = tree.findall(".ip")
|
||||
for ip in ips:
|
||||
address_str = ip.get('address')
|
||||
netmask_str = ip.get('netmask')
|
||||
prefix = ip.get('prefix')
|
||||
family = ip.get('family', 'ipv4')
|
||||
base = 32 if family == 'ipv4' else 128
|
||||
address_str = ip.get("address")
|
||||
netmask_str = ip.get("netmask")
|
||||
prefix = ip.get("prefix")
|
||||
family = ip.get("family", "ipv4")
|
||||
base = 32 if family == "ipv4" else 128
|
||||
if prefix:
|
||||
prefix = int(prefix)
|
||||
binstr = ((prefix * "1") + ((base - prefix) * "0"))
|
||||
binstr = (prefix * "1") + ((base - prefix) * "0")
|
||||
netmask_str = str(IP(int(binstr, base=2)))
|
||||
|
||||
if netmask_str:
|
||||
netmask = IP(netmask_str)
|
||||
gateway = IP(address_str)
|
||||
network = IP(gateway.int() & netmask.int())
|
||||
netmask_str = netmask_str if family == 'ipv4' else str(prefix)
|
||||
netmask_str = netmask_str if family == "ipv4" else str(prefix)
|
||||
ret = IP(str(network) + "/" + netmask_str)
|
||||
else:
|
||||
ret = IP(str(address_str))
|
||||
|
@ -178,12 +192,12 @@ class wvmNetwork(wvmConnect):
|
|||
forward_dev = util.get_xml_path(xml, "/network/forward/@dev")
|
||||
return [fw, forward_dev]
|
||||
|
||||
def get_dhcp_range(self, family='ipv4'):
|
||||
def get_dhcp_range(self, family="ipv4"):
|
||||
xml = self._XMLDesc(0)
|
||||
if family == 'ipv4':
|
||||
if family == "ipv4":
|
||||
dhcpstart = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@start")
|
||||
dhcpend = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@end")
|
||||
if family == 'ipv6':
|
||||
if family == "ipv6":
|
||||
dhcpstart = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@start")
|
||||
dhcpend = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@end")
|
||||
|
||||
|
@ -192,13 +206,13 @@ class wvmNetwork(wvmConnect):
|
|||
|
||||
return [IP(dhcpstart), IP(dhcpend)]
|
||||
|
||||
def get_dhcp_range_start(self, family='ipv4'):
|
||||
def get_dhcp_range_start(self, family="ipv4"):
|
||||
dhcp = self.get_dhcp_range(family)
|
||||
if not dhcp:
|
||||
return None
|
||||
return dhcp[0]
|
||||
|
||||
def get_dhcp_range_end(self, family='ipv4'):
|
||||
def get_dhcp_range_end(self, family="ipv4"):
|
||||
dhcp = self.get_dhcp_range(family)
|
||||
if not dhcp:
|
||||
return None
|
||||
|
@ -211,74 +225,77 @@ class wvmNetwork(wvmConnect):
|
|||
return True
|
||||
return bool(util.get_xml_path(xml, "/network/ip/dhcp/bootp/@file"))
|
||||
|
||||
def get_dhcp_host_addr(self, family='ipv4'):
|
||||
def get_dhcp_host_addr(self, family="ipv4"):
|
||||
result = list()
|
||||
tree = etree.fromstring(self._XMLDesc(0))
|
||||
|
||||
for ipdhcp in tree.findall("./ip"):
|
||||
if family == 'ipv4':
|
||||
if ipdhcp.get('family') is None:
|
||||
hosts = ipdhcp.findall('./dhcp/host')
|
||||
if family == "ipv4":
|
||||
if ipdhcp.get("family") is None:
|
||||
hosts = ipdhcp.findall("./dhcp/host")
|
||||
for host in hosts:
|
||||
host_ip = host.get('ip')
|
||||
mac = host.get('mac')
|
||||
name = host.get('name', '')
|
||||
result.append({'ip': host_ip, 'mac': mac, 'name': name})
|
||||
host_ip = host.get("ip")
|
||||
mac = host.get("mac")
|
||||
name = host.get("name", "")
|
||||
result.append({"ip": host_ip, "mac": mac, "name": name})
|
||||
return result
|
||||
else:
|
||||
continue
|
||||
if family == 'ipv6':
|
||||
if family == "ipv6":
|
||||
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
|
||||
for host in hosts:
|
||||
host_ip = host.get('ip')
|
||||
host_id = host.get('id')
|
||||
name = host.get('name', '')
|
||||
result.append({'ip': host_ip, 'id': host_id, 'name': name})
|
||||
host_ip = host.get("ip")
|
||||
host_id = host.get("id")
|
||||
name = host.get("name", "")
|
||||
result.append({"ip": host_ip, "id": host_id, "name": name})
|
||||
return result
|
||||
|
||||
def modify_dhcp_range(self, range_start, range_end, family='ipv4'):
|
||||
def modify_dhcp_range(self, range_start, range_end, family="ipv4"):
|
||||
if not self.is_active():
|
||||
tree = etree.fromstring(self._XMLDesc(0))
|
||||
if family == 'ipv4':
|
||||
if family == "ipv4":
|
||||
dhcp_range = tree.xpath("./ip[not(@family='ipv6')]/dhcp/range")
|
||||
if family == 'ipv6':
|
||||
if family == "ipv6":
|
||||
dhcp_range = tree.xpath("./ip[@family='ipv6']/dhcp/range")
|
||||
dhcp_range[0].set('start', range_start)
|
||||
dhcp_range[0].set('end', range_end)
|
||||
dhcp_range[0].set("start", range_start)
|
||||
dhcp_range[0].set("end", range_end)
|
||||
self.wvm.networkDefineXML(etree.tostring(tree).decode())
|
||||
|
||||
def delete_fixed_address(self, ip, family='ipv4'):
|
||||
def delete_fixed_address(self, ip, family="ipv4"):
|
||||
tree = etree.fromstring(self._XMLDesc(0))
|
||||
if family == 'ipv4':
|
||||
if family == "ipv4":
|
||||
hosts = tree.xpath("/network/ip[not(@family='ipv6')]/dhcp/host")
|
||||
parent_index = self.parent_count - 2
|
||||
if family == 'ipv6':
|
||||
if family == "ipv6":
|
||||
hosts = tree.xpath("/network/ip[@family='ipv6']/dhcp/host")
|
||||
parent_index = self.parent_count - 1
|
||||
for h in hosts:
|
||||
if h.get('ip') == ip:
|
||||
if family == 'ipv4':
|
||||
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get('mac'), h.get('name'), ip)
|
||||
if family == 'ipv6':
|
||||
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get('id'), h.get('name'), ip)
|
||||
if h.get("ip") == ip:
|
||||
if family == "ipv4":
|
||||
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get("mac"), h.get("name"), ip)
|
||||
if family == "ipv6":
|
||||
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get("id"), h.get("name"), ip)
|
||||
|
||||
self.update(VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||
new_xml,
|
||||
parent_index,
|
||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
||||
self.update(
|
||||
VIR_NETWORK_UPDATE_COMMAND_DELETE,
|
||||
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||
new_xml,
|
||||
parent_index,
|
||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||
)
|
||||
break
|
||||
|
||||
def modify_fixed_address(self, name, address, mac_duid, family='ipv4'):
|
||||
def modify_fixed_address(self, name, address, mac_duid, family="ipv4"):
|
||||
tree = etree.fromstring(self._XMLDesc(0))
|
||||
if family == 'ipv4':
|
||||
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
|
||||
if family == "ipv4":
|
||||
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
|
||||
hosts = tree.xpath("./ip[not(@family='ipv6')]/dhcp/host")
|
||||
compare_var = 'mac'
|
||||
compare_var = "mac"
|
||||
parent_index = self.parent_count - 2
|
||||
if family == 'ipv6':
|
||||
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
|
||||
if family == "ipv6":
|
||||
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
|
||||
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
|
||||
compare_var = 'id'
|
||||
compare_var = "id"
|
||||
parent_index = self.parent_count - 1
|
||||
new_host_xml = etree.fromstring(new_xml)
|
||||
|
||||
|
@ -288,17 +305,25 @@ class wvmNetwork(wvmConnect):
|
|||
host = h
|
||||
break
|
||||
if host is None:
|
||||
self.update(VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
|
||||
parent_index,
|
||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
||||
self.update(
|
||||
VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
|
||||
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||
new_xml,
|
||||
parent_index,
|
||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||
)
|
||||
else:
|
||||
# change the host
|
||||
if host.get('name') == new_host_xml.get('name') and host.get('ip') == new_host_xml.get('ip'):
|
||||
if host.get("name") == new_host_xml.get("name") and host.get("ip") == new_host_xml.get("ip"):
|
||||
return False
|
||||
else:
|
||||
self.update(VIR_NETWORK_UPDATE_COMMAND_MODIFY, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
|
||||
parent_index,
|
||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
||||
self.update(
|
||||
VIR_NETWORK_UPDATE_COMMAND_MODIFY,
|
||||
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||
new_xml,
|
||||
parent_index,
|
||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||
)
|
||||
|
||||
def get_qos(self):
|
||||
qos_values = dict()
|
||||
|
@ -307,19 +332,19 @@ class wvmNetwork(wvmConnect):
|
|||
if qos:
|
||||
qos = qos[0]
|
||||
|
||||
in_qos = qos.find('inbound')
|
||||
in_qos = qos.find("inbound")
|
||||
if in_qos is not None:
|
||||
in_av = in_qos.get('average')
|
||||
in_peak = in_qos.get('peak')
|
||||
in_burst = in_qos.get('burst')
|
||||
qos_values['inbound'] = {'average': in_av, 'peak': in_peak, 'burst': in_burst}
|
||||
in_av = in_qos.get("average")
|
||||
in_peak = in_qos.get("peak")
|
||||
in_burst = in_qos.get("burst")
|
||||
qos_values["inbound"] = {"average": in_av, "peak": in_peak, "burst": in_burst}
|
||||
|
||||
out_qos = qos.find('outbound')
|
||||
out_qos = qos.find("outbound")
|
||||
if out_qos is not None:
|
||||
out_av = out_qos.get('average')
|
||||
out_peak = out_qos.get('peak')
|
||||
out_burst = out_qos.get('burst')
|
||||
qos_values['outbound'] = {'average': out_av, 'peak': out_peak, 'burst': out_burst}
|
||||
out_av = out_qos.get("average")
|
||||
out_peak = out_qos.get("peak")
|
||||
out_burst = out_qos.get("burst")
|
||||
qos_values["outbound"] = {"average": out_av, "peak": out_peak, "burst": out_burst}
|
||||
return qos_values
|
||||
|
||||
def set_qos(self, direction, average, peak, burst):
|
||||
|
@ -328,7 +353,7 @@ class wvmNetwork(wvmConnect):
|
|||
elif direction == "outbound":
|
||||
xml = f"<outbound average='{average}' peak='{peak}' burst='{burst}'/>"
|
||||
else:
|
||||
raise Exception('Direction must be inbound or outbound')
|
||||
raise Exception("Direction must be inbound or outbound")
|
||||
|
||||
tree = etree.fromstring(self._XMLDesc(0))
|
||||
|
||||
|
@ -363,7 +388,7 @@ class wvmNetwork(wvmConnect):
|
|||
self.leases = self.net.DHCPLeases()
|
||||
except Exception as e:
|
||||
self.leases = []
|
||||
raise f"Error getting {self} DHCP leases: {e}"
|
||||
raise "Error getting {} DHCP leases: {}".format(self, e)
|
||||
|
||||
def get_dhcp_leases(self):
|
||||
if self.leases is None:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import base64
|
||||
|
||||
from vrtManager.connection import wvmConnect
|
||||
|
||||
|
||||
|
@ -6,12 +7,12 @@ class wvmSecrets(wvmConnect):
|
|||
def create_secret(self, ephemeral, private, secret_type, data):
|
||||
xml = f"""<secret ephemeral='{ephemeral}' private='{private}'>
|
||||
<usage type='{secret_type}'>"""
|
||||
if secret_type == 'ceph':
|
||||
if secret_type == "ceph":
|
||||
xml += f"""<name>{data}</name>"""
|
||||
if secret_type == 'volume':
|
||||
if secret_type == "volume":
|
||||
xml += f"""<volume>{data}</volume>"""
|
||||
if secret_type == 'iscsi':
|
||||
xml += f"""<target>{data}</target>"""
|
||||
if secret_type == "iscsi":
|
||||
xml += f"""<target>{data}</target>"""
|
||||
xml += """</usage>
|
||||
</secret>"""
|
||||
self.wvm.secretDefineXML(xml)
|
||||
|
|
|
@ -16,13 +16,7 @@ class wvmStorages(wvmConnect):
|
|||
stg_vol = None
|
||||
stg_size = stg.info()[1]
|
||||
storages.append(
|
||||
{
|
||||
"name": pool,
|
||||
"status": stg_status,
|
||||
"type": stg_type,
|
||||
"volumes": stg_vol,
|
||||
"size": stg_size
|
||||
}
|
||||
{"name": pool, "status": stg_status, "type": stg_type, "volumes": stg_vol, "size": stg_size}
|
||||
)
|
||||
return storages
|
||||
|
||||
|
@ -103,12 +97,7 @@ class wvmStorage(wvmConnect):
|
|||
return self.pool.name()
|
||||
|
||||
def get_status(self):
|
||||
status = [
|
||||
"Not running",
|
||||
"Initializing pool, not available",
|
||||
"Running normally",
|
||||
"Running degraded"
|
||||
]
|
||||
status = ["Not running", "Initializing pool, not available", "Running normally", "Running degraded"]
|
||||
try:
|
||||
return status[self.pool.info()[0]]
|
||||
except ValueError:
|
||||
|
@ -217,12 +206,12 @@ class wvmStorage(wvmConnect):
|
|||
"name": volname,
|
||||
"size": self.get_volume_size(volname),
|
||||
"allocation": self.get_volume_allocation(volname),
|
||||
"type": self.get_volume_type(volname)
|
||||
"type": self.get_volume_type(volname),
|
||||
}
|
||||
)
|
||||
return vol_list
|
||||
|
||||
def create_volume(self, name, size, vol_fmt='qcow2', metadata=False, disk_owner_uid=0, disk_owner_gid=0):
|
||||
def create_volume(self, name, size, vol_fmt="qcow2", metadata=False, disk_owner_uid=0, disk_owner_gid=0):
|
||||
size = int(size) * 1073741824
|
||||
storage_type = self.get_type()
|
||||
alloc = size
|
||||
|
@ -258,7 +247,17 @@ class wvmStorage(wvmConnect):
|
|||
self._createXML(xml, metadata)
|
||||
return name
|
||||
|
||||
def clone_volume(self, name, target_file, vol_fmt=None, metadata=False, mode='0644', file_suffix='img', disk_owner_uid=0, disk_owner_gid=0):
|
||||
def clone_volume(
|
||||
self,
|
||||
name,
|
||||
target_file,
|
||||
vol_fmt=None,
|
||||
metadata=False,
|
||||
mode="0644",
|
||||
file_suffix="img",
|
||||
disk_owner_uid=0,
|
||||
disk_owner_gid=0,
|
||||
):
|
||||
vol = self.get_volume(name)
|
||||
if not vol_fmt:
|
||||
vol_fmt = self.get_volume_type(name)
|
||||
|
@ -266,10 +265,10 @@ class wvmStorage(wvmConnect):
|
|||
storage_type = self.get_type()
|
||||
if storage_type == "dir":
|
||||
if vol_fmt in ["qcow", "qcow2"]:
|
||||
target_file += '.' + vol_fmt
|
||||
target_file += "." + vol_fmt
|
||||
else:
|
||||
suffix = '.' + file_suffix
|
||||
target_file += suffix if len(suffix) > 1 else ''
|
||||
suffix = "." + file_suffix
|
||||
target_file += suffix if len(suffix) > 1 else ""
|
||||
|
||||
xml = f"""
|
||||
<volume>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -20,9 +20,7 @@ MIDDLEWARE += [
|
|||
]
|
||||
|
||||
# DebugToolBar
|
||||
INTERNAL_IPS = (
|
||||
"127.0.0.1",
|
||||
)
|
||||
INTERNAL_IPS = ("127.0.0.1",)
|
||||
DEBUG_TOOLBAR_CONFIG = {
|
||||
"INTERCEPT_REDIRECTS": False,
|
||||
}
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -16,7 +16,7 @@ exec(
|
|||
compile(
|
||||
open("/srv/webvirtcloud/venv/bin/activate", "rb").read(),
|
||||
"/srv/webvirtcloud/venv/bin/activate",
|
||||
"exec"
|
||||
"exec",
|
||||
)
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue