mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-24 23:25:24 +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
|
Depending on settings SHOW_PROFILE_EDIT_PASSWORD
|
||||||
'''
|
'''
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User, Permission
|
from django.contrib.auth.models import Permission, User
|
||||||
if hasattr(settings, 'SHOW_PROFILE_EDIT_PASSWORD'):
|
if hasattr(settings, 'SHOW_PROFILE_EDIT_PASSWORD'):
|
||||||
print('\033[1m! \033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m')
|
print('\033[1m! \033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m')
|
||||||
print('\033[1m* \033[92mApplying permission can_change_password for all users\033[0m')
|
print('\033[1m* \033[92mApplying permission can_change_password for all users\033[0m')
|
||||||
|
@ -29,8 +29,8 @@ def create_admin(sender, **kwargs):
|
||||||
'''
|
'''
|
||||||
Create initial admin user
|
Create initial admin user
|
||||||
'''
|
'''
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from accounts.models import UserAttributes
|
from accounts.models import UserAttributes
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
plan = kwargs.get('plan', [])
|
plan = kwargs.get('plan', [])
|
||||||
for migration, rolled_back in plan:
|
for migration, rolled_back in plan:
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
# Generated by Django 2.2.10 on 2020-01-28 07:01
|
# Generated by Django 2.2.10 on 2020-01-28 07:01
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from django import template
|
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,27 +35,27 @@ def validate_ssh_key(key):
|
||||||
return False
|
return False
|
||||||
# unpack the contents of data, from data[:4] , property of ssh key .
|
# unpack the contents of data, from data[:4] , property of ssh key .
|
||||||
try:
|
try:
|
||||||
str_len = struct.unpack('>I', data[:4])[0]
|
str_len = struct.unpack(">I", data[:4])[0]
|
||||||
except struct.error:
|
except struct.error:
|
||||||
return False
|
return False
|
||||||
# data[4:str_len] must have string which matches with the typeofkey, another ssh key property.
|
# data[4:str_len] must have string which matches with the typeofkey, another ssh key property.
|
||||||
if data[4:4 + str_len] == typeofkey:
|
if data[4 : 4 + str_len] == typeofkey:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def send_email_with_otp(user, device):
|
def send_email_with_otp(user, device):
|
||||||
send_mail(
|
send_mail(
|
||||||
_('OTP QR Code'),
|
_("OTP QR Code"),
|
||||||
_('Please view HTML version of this message.'),
|
_("Please view HTML version of this message."),
|
||||||
None,
|
None,
|
||||||
[user.email],
|
[user.email],
|
||||||
html_message=render_to_string(
|
html_message=render_to_string(
|
||||||
'accounts/email/otp.html',
|
"accounts/email/otp.html",
|
||||||
{
|
{
|
||||||
'totp_url': device.config_url,
|
"totp_url": device.config_url,
|
||||||
'user': user,
|
"user": user,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
fail_silently=False,
|
fail_silently=False,
|
||||||
|
|
|
@ -23,40 +23,52 @@ def profile(request):
|
||||||
|
|
||||||
if profile_form.is_valid():
|
if profile_form.is_valid():
|
||||||
profile_form.save()
|
profile_form.save()
|
||||||
messages.success(request, _('Profile updated'))
|
messages.success(request, _("Profile updated"))
|
||||||
return redirect('accounts:profile')
|
return redirect("accounts:profile")
|
||||||
|
|
||||||
return render(request, "profile.html", {
|
return render(
|
||||||
'publickeys': publickeys,
|
request,
|
||||||
'profile_form': profile_form,
|
"profile.html",
|
||||||
'ssh_key_form': ssh_key_form,
|
{
|
||||||
})
|
"publickeys": publickeys,
|
||||||
|
"profile_form": profile_form,
|
||||||
|
"ssh_key_form": ssh_key_form,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def ssh_key_create(request):
|
def ssh_key_create(request):
|
||||||
key_form = UserSSHKeyForm(request.POST or None, user=request.user)
|
key_form = UserSSHKeyForm(request.POST or None, user=request.user)
|
||||||
if key_form.is_valid():
|
if key_form.is_valid():
|
||||||
key_form.save()
|
key_form.save()
|
||||||
messages.success(request, _('SSH key added'))
|
messages.success(request, _("SSH key added"))
|
||||||
return redirect('accounts:profile')
|
return redirect("accounts:profile")
|
||||||
|
|
||||||
return render(request, 'common/form.html', {
|
return render(
|
||||||
'form': key_form,
|
request,
|
||||||
'title': _('Add SSH key'),
|
"common/form.html",
|
||||||
})
|
{
|
||||||
|
"form": key_form,
|
||||||
|
"title": _("Add SSH key"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def ssh_key_delete(request, pk):
|
def ssh_key_delete(request, pk):
|
||||||
ssh_key = get_object_or_404(UserSSHKey, pk=pk, user=request.user)
|
ssh_key = get_object_or_404(UserSSHKey, pk=pk, user=request.user)
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
ssh_key.delete()
|
ssh_key.delete()
|
||||||
messages.success(request, _('SSH key deleted'))
|
messages.success(request, _("SSH key deleted"))
|
||||||
return redirect('accounts:profile')
|
return redirect("accounts:profile")
|
||||||
|
|
||||||
return render(request, 'common/confirm_delete.html', {
|
return render(
|
||||||
'object': ssh_key,
|
request,
|
||||||
'title': _('Delete SSH key'),
|
"common/confirm_delete.html",
|
||||||
})
|
{
|
||||||
|
"object": ssh_key,
|
||||||
|
"title": _("Delete SSH key"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
|
@ -67,13 +79,16 @@ def account(request, user_id):
|
||||||
publickeys = UserSSHKey.objects.filter(user_id=user_id)
|
publickeys = UserSSHKey.objects.filter(user_id=user_id)
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request, "account.html", {
|
request,
|
||||||
'user': user,
|
"account.html",
|
||||||
'user_insts': user_insts,
|
{
|
||||||
'instances': instances,
|
"user": user,
|
||||||
'publickeys': publickeys,
|
"user_insts": user_insts,
|
||||||
'otp_enabled': settings.OTP_ENABLED,
|
"instances": instances,
|
||||||
})
|
"publickeys": publickeys,
|
||||||
|
"otp_enabled": settings.OTP_ENABLED,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@permission_required("accounts.change_password", raise_exception=True)
|
@permission_required("accounts.change_password", raise_exception=True)
|
||||||
|
@ -118,7 +133,7 @@ def user_instance_update(request, pk):
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
'common/form.html',
|
"common/form.html",
|
||||||
{
|
{
|
||||||
"form": form,
|
"form": form,
|
||||||
"title": _("Update User Instance"),
|
"title": _("Update User Instance"),
|
||||||
|
@ -150,29 +165,33 @@ def email_otp(request):
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
UserModel = get_user_model()
|
UserModel = get_user_model()
|
||||||
try:
|
try:
|
||||||
user = UserModel.objects.get(email=form.cleaned_data['email'])
|
user = UserModel.objects.get(email=form.cleaned_data["email"])
|
||||||
except UserModel.DoesNotExist:
|
except UserModel.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
device = get_user_totp_device(user)
|
device = get_user_totp_device(user)
|
||||||
send_email_with_otp(user, device)
|
send_email_with_otp(user, device)
|
||||||
|
|
||||||
messages.success(request, _('OTP Sent to %s') % form.cleaned_data['email'])
|
messages.success(request, _("OTP Sent to %(email)s") % {"email": form.cleaned_data["email"]})
|
||||||
return redirect('accounts:login')
|
return redirect("accounts:login")
|
||||||
|
|
||||||
return render(request, 'accounts/email_otp_form.html', {
|
return render(
|
||||||
'form': form,
|
request,
|
||||||
'title': _('Email OTP'),
|
"accounts/email_otp_form.html",
|
||||||
})
|
{
|
||||||
|
"form": form,
|
||||||
|
"title": _("Email OTP"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
def admin_email_otp(request, user_id):
|
def admin_email_otp(request, user_id):
|
||||||
user = get_object_or_404(get_user_model(), pk=user_id)
|
user = get_object_or_404(get_user_model(), pk=user_id)
|
||||||
device = get_user_totp_device(user)
|
device = get_user_totp_device(user)
|
||||||
if user.email != '':
|
if user.email != "":
|
||||||
send_email_with_otp(user, device)
|
send_email_with_otp(user, device)
|
||||||
messages.success(request, _('OTP QR code was emailed to user %s') % user)
|
messages.success(request, _("OTP QR code was emailed to user %(user)s") % {"user": user})
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('User email not set, failed to send QR code'))
|
messages.error(request, _("User email not set, failed to send QR code"))
|
||||||
return redirect('accounts:account', user.id)
|
return redirect("accounts:account", user.id)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.models import Group, User
|
|
||||||
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
||||||
|
from django.contrib.auth.models import Group, User
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.text import format_lazy
|
from django.utils.text import format_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -13,7 +13,7 @@ from .models import Permission
|
||||||
class GroupForm(forms.ModelForm):
|
class GroupForm(forms.ModelForm):
|
||||||
permissions = forms.ModelMultipleChoiceField(
|
permissions = forms.ModelMultipleChoiceField(
|
||||||
widget=forms.CheckboxSelectMultiple,
|
widget=forms.CheckboxSelectMultiple,
|
||||||
queryset=Permission.objects.filter(content_type__model='permissionset'),
|
queryset=Permission.objects.filter(content_type__model="permissionset"),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,12 +25,12 @@ class GroupForm(forms.ModelForm):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(GroupForm, self).__init__(*args, **kwargs)
|
super(GroupForm, self).__init__(*args, **kwargs)
|
||||||
instance = getattr(self, 'instance', None)
|
instance = getattr(self, "instance", None)
|
||||||
if instance and instance.id:
|
if instance and instance.id:
|
||||||
self.fields['users'].initial = self.instance.user_set.all()
|
self.fields["users"].initial = self.instance.user_set.all()
|
||||||
|
|
||||||
def save_m2m(self):
|
def save_m2m(self):
|
||||||
self.instance.user_set.set(self.cleaned_data['users'])
|
self.instance.user_set.set(self.cleaned_data["users"])
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
instance = super(GroupForm, self).save()
|
instance = super(GroupForm, self).save()
|
||||||
|
@ -39,36 +39,36 @@ class GroupForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
fields = '__all__'
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
class UserForm(forms.ModelForm):
|
class UserForm(forms.ModelForm):
|
||||||
user_permissions = forms.ModelMultipleChoiceField(
|
user_permissions = forms.ModelMultipleChoiceField(
|
||||||
widget=forms.CheckboxSelectMultiple,
|
widget=forms.CheckboxSelectMultiple,
|
||||||
queryset=Permission.objects.filter(content_type__model='permissionset'),
|
queryset=Permission.objects.filter(content_type__model="permissionset"),
|
||||||
label=_('Permissions'),
|
label=_("Permissions"),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
groups = forms.ModelMultipleChoiceField(
|
groups = forms.ModelMultipleChoiceField(
|
||||||
widget=forms.CheckboxSelectMultiple,
|
widget=forms.CheckboxSelectMultiple,
|
||||||
queryset=Group.objects.all(),
|
queryset=Group.objects.all(),
|
||||||
label=_('Groups'),
|
label=_("Groups"),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = [
|
fields = [
|
||||||
'username',
|
"username",
|
||||||
'groups',
|
"groups",
|
||||||
'first_name',
|
"first_name",
|
||||||
'last_name',
|
"last_name",
|
||||||
'email',
|
"email",
|
||||||
'user_permissions',
|
"user_permissions",
|
||||||
'is_staff',
|
"is_staff",
|
||||||
'is_active',
|
"is_active",
|
||||||
'is_superuser',
|
"is_superuser",
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -76,12 +76,20 @@ class UserForm(forms.ModelForm):
|
||||||
if self.instance.id:
|
if self.instance.id:
|
||||||
password = ReadOnlyPasswordHashField(
|
password = ReadOnlyPasswordHashField(
|
||||||
label=_("Password"),
|
label=_("Password"),
|
||||||
help_text=format_lazy(_("""Raw passwords are not stored, so there is no way to see
|
help_text=format_lazy(
|
||||||
this user's password, but you can change the password using <a href='{}'>this form</a>."""),
|
_(
|
||||||
reverse_lazy('admin:user_update_password',
|
"""Raw passwords are not stored, so there is no way to see this user's password,
|
||||||
args=[self.instance.id,]))
|
but you can change the password using <a href='{}'>this form</a>."""
|
||||||
|
),
|
||||||
|
reverse_lazy(
|
||||||
|
"admin:user_update_password",
|
||||||
|
args=[
|
||||||
|
self.instance.id,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.fields['Password'] = password
|
self.fields["Password"] = password
|
||||||
|
|
||||||
|
|
||||||
class UserCreateForm(UserForm):
|
class UserCreateForm(UserForm):
|
||||||
|
@ -90,20 +98,20 @@ class UserCreateForm(UserForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = [
|
fields = [
|
||||||
'username',
|
"username",
|
||||||
'password',
|
"password",
|
||||||
'groups',
|
"groups",
|
||||||
'first_name',
|
"first_name",
|
||||||
'last_name',
|
"last_name",
|
||||||
'email',
|
"email",
|
||||||
'user_permissions',
|
"user_permissions",
|
||||||
'is_staff',
|
"is_staff",
|
||||||
'is_active',
|
"is_active",
|
||||||
'is_superuser',
|
"is_superuser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class UserAttributesForm(forms.ModelForm):
|
class UserAttributesForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = UserAttributes
|
model = UserAttributes
|
||||||
exclude = ['user', 'can_clone_instances']
|
exclude = ["user", "can_clone_instances"]
|
||||||
|
|
|
@ -50,7 +50,7 @@ def group_update(request, pk):
|
||||||
form = forms.GroupForm(request.POST or None, instance=group)
|
form = forms.GroupForm(request.POST or None, instance=group)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
return redirect('admin:group_list')
|
return redirect("admin:group_list")
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
|
@ -107,11 +107,7 @@ def user_create(request):
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"admin/user_form.html",
|
"admin/user_form.html",
|
||||||
{
|
{"user_form": user_form, "attributes_form": attributes_form, "title": _("Create User")},
|
||||||
"user_form": user_form,
|
|
||||||
"attributes_form": attributes_form,
|
|
||||||
"title": _("Create User")
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,29 +120,25 @@ def user_update(request, pk):
|
||||||
if user_form.is_valid() and attributes_form.is_valid():
|
if user_form.is_valid() and attributes_form.is_valid():
|
||||||
user_form.save()
|
user_form.save()
|
||||||
attributes_form.save()
|
attributes_form.save()
|
||||||
next = request.GET.get('next')
|
next = request.GET.get("next")
|
||||||
return redirect(next or "admin:user_list")
|
return redirect(next or "admin:user_list")
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"admin/user_form.html",
|
"admin/user_form.html",
|
||||||
{
|
{"user_form": user_form, "attributes_form": attributes_form, "title": _("Update User")},
|
||||||
"user_form": user_form,
|
|
||||||
"attributes_form": attributes_form,
|
|
||||||
"title": _("Update User")
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
def user_update_password(request, pk):
|
def user_update_password(request, pk):
|
||||||
user = get_object_or_404(User, pk=pk)
|
user = get_object_or_404(User, pk=pk)
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
form = AdminPasswordChangeForm(user, request.POST)
|
form = AdminPasswordChangeForm(user, request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
user = form.save()
|
user = form.save()
|
||||||
update_session_auth_hash(request, user) # Important!
|
update_session_auth_hash(request, user) # Important!
|
||||||
messages.success(request, _("User password changed: {}".format(user.username)))
|
messages.success(request, _("Password changed for %(user)s") % {"user": user.username})
|
||||||
return redirect("admin:user_list")
|
return redirect("admin:user_list")
|
||||||
else:
|
else:
|
||||||
messages.error(request, _("Wrong Data Provided"))
|
messages.error(request, _("Wrong Data Provided"))
|
||||||
|
|
|
@ -29,13 +29,13 @@ def appsettings(request):
|
||||||
# Bootstrap settings related with filesystems, because of that they are excluded from other settings
|
# Bootstrap settings related with filesystems, because of that they are excluded from other settings
|
||||||
appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name")
|
appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name")
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if 'SASS_DIR' in request.POST:
|
if "SASS_DIR" in request.POST:
|
||||||
try:
|
try:
|
||||||
sass_dir.value = request.POST.get("SASS_DIR", "")
|
sass_dir.value = request.POST.get("SASS_DIR", "")
|
||||||
sass_dir.save()
|
sass_dir.save()
|
||||||
|
|
||||||
msg = _(f"SASS directory path is changed. Now: {sass_dir.value}")
|
msg = _("SASS directory path is changed. Now: %(dir)s") % {"dir": sass_dir.value}
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = err
|
msg = err
|
||||||
|
@ -44,7 +44,7 @@ def appsettings(request):
|
||||||
addlogmsg(request.user.username, "", msg)
|
addlogmsg(request.user.username, "", msg)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
||||||
if 'BOOTSTRAP_THEME' in request.POST:
|
if "BOOTSTRAP_THEME" in request.POST:
|
||||||
theme = request.POST.get("BOOTSTRAP_THEME", "")
|
theme = request.POST.get("BOOTSTRAP_THEME", "")
|
||||||
scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';"
|
scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';"
|
||||||
scss_bootswatch = f"@import '{sass_dir.value}/wvc-theme/{theme}/bootswatch';"
|
scss_bootswatch = f"@import '{sass_dir.value}/wvc-theme/{theme}/bootswatch';"
|
||||||
|
@ -54,15 +54,17 @@ def appsettings(request):
|
||||||
with open(sass_dir.value + "/wvc-main.scss", "w") as main:
|
with open(sass_dir.value + "/wvc-main.scss", "w") as main:
|
||||||
main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch + "\n")
|
main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch + "\n")
|
||||||
|
|
||||||
css_compressed = sass.compile(string=scss_var + "\n" + scss_boot + "\n" + scss_bootswatch,
|
css_compressed = sass.compile(
|
||||||
output_style='compressed')
|
string=scss_var + "\n" + scss_boot + "\n" + scss_bootswatch,
|
||||||
|
output_style="compressed",
|
||||||
|
)
|
||||||
with open("static/css/" + main_css, "w") as css:
|
with open("static/css/" + main_css, "w") as css:
|
||||||
css.write(css_compressed)
|
css.write(css_compressed)
|
||||||
|
|
||||||
bootstrap_theme.value = theme
|
bootstrap_theme.value = theme
|
||||||
bootstrap_theme.save()
|
bootstrap_theme.save()
|
||||||
|
|
||||||
msg = _(f"Theme changed. Now: {theme}")
|
msg = _("Theme is changed. Now: %(theme)s") % {"theme": theme}
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = err
|
msg = err
|
||||||
|
@ -77,7 +79,7 @@ def appsettings(request):
|
||||||
setting.value = request.POST.get(setting.key, "")
|
setting.value = request.POST.get(setting.key, "")
|
||||||
setting.save()
|
setting.save()
|
||||||
|
|
||||||
msg = _(f"{setting.name} is changed. Now: {setting.value}")
|
msg = _("%(setting)s is changed. Now: %(value)s") % {"setting": setting.name, "value": setting.value}
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = err
|
msg = err
|
||||||
|
@ -86,4 +88,4 @@ def appsettings(request):
|
||||||
addlogmsg(request.user.username, "", msg)
|
addlogmsg(request.user.username, "", msg)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
||||||
return render(request, 'appsettings.html', locals())
|
return render(request, "appsettings.html", locals())
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from secrets.views import secrets
|
from secrets.views import secrets
|
||||||
|
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
# from instances.views import create_instance, create_instance_select_type
|
# from instances.views import create_instance, create_instance_select_type
|
||||||
from interfaces.views import interface, interfaces
|
from interfaces.views import interface, interfaces
|
||||||
from networks.views import network, networks
|
from networks.views import network, networks
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
have_symbol = re.compile('[^a-zA-Z0-9._-]+')
|
have_symbol = re.compile('[^a-zA-Z0-9._-]+')
|
||||||
wrong_ip = re.compile('^0.|^255.')
|
wrong_ip = re.compile('^0.|^255.')
|
||||||
wrong_name = re.compile('[^a-zA-Z0-9._-]+')
|
wrong_name = re.compile('[^a-zA-Z0-9._-]+')
|
||||||
|
|
|
@ -1,18 +1,23 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.http import HttpResponse
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.shortcuts import get_object_or_404, redirect, render, reverse
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
|
||||||
from accounts.models import UserInstance
|
|
||||||
from admin.decorators import superuser_only
|
from admin.decorators import superuser_only
|
||||||
from computes.forms import (SocketComputeForm, SshComputeForm, TcpComputeForm, TlsComputeForm)
|
from computes.forms import SocketComputeForm, SshComputeForm, TcpComputeForm, TlsComputeForm
|
||||||
from computes.models import Compute
|
from computes.models import Compute
|
||||||
from instances.models import Instance
|
from instances.models import Instance
|
||||||
from vrtManager.connection import (CONN_SOCKET, CONN_SSH, CONN_TCP, CONN_TLS, connection_manager, wvmConnect)
|
from vrtManager.connection import (
|
||||||
|
CONN_SOCKET,
|
||||||
|
CONN_SSH,
|
||||||
|
CONN_TCP,
|
||||||
|
CONN_TLS,
|
||||||
|
connection_manager,
|
||||||
|
wvmConnect,
|
||||||
|
)
|
||||||
from vrtManager.hostdetails import wvmHostDetails
|
from vrtManager.hostdetails import wvmHostDetails
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
|
@ -25,15 +30,17 @@ def computes(request):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
computes = Compute.objects.filter().order_by('name')
|
computes = Compute.objects.filter().order_by("name")
|
||||||
|
|
||||||
return render(request, 'computes/list.html', {'computes': computes})
|
return render(request, "computes/list.html", {"computes": computes})
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
def overview(request, compute_id):
|
def overview(request, compute_id):
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
status = 'true' if connection_manager.host_is_up(compute.type, compute.hostname) is True else 'false'
|
status = (
|
||||||
|
"true" if connection_manager.host_is_up(compute.type, compute.hostname) is True else "false"
|
||||||
|
)
|
||||||
|
|
||||||
conn = wvmHostDetails(
|
conn = wvmHostDetails(
|
||||||
compute.hostname,
|
compute.hostname,
|
||||||
|
@ -49,7 +56,7 @@ def overview(request, compute_id):
|
||||||
lib_version = conn.get_lib_version()
|
lib_version = conn.get_lib_version()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return render(request, 'overview.html', locals())
|
return render(request, "overview.html", locals())
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
|
@ -57,9 +64,9 @@ def instances(request, compute_id):
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
utils.refresh_instance_database(compute)
|
utils.refresh_instance_database(compute)
|
||||||
instances = Instance.objects.filter(compute=compute).prefetch_related('userinstance_set')
|
instances = Instance.objects.filter(compute=compute).prefetch_related("userinstance_set")
|
||||||
|
|
||||||
return render(request, 'computes/instances.html', {'compute': compute, 'instances': instances})
|
return render(request, "computes/instances.html", {"compute": compute, "instances": instances})
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
|
@ -67,9 +74,9 @@ def compute_create(request, FormClass):
|
||||||
form = FormClass(request.POST or None)
|
form = FormClass(request.POST or None)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
return redirect(reverse('computes'))
|
return redirect(reverse("computes"))
|
||||||
|
|
||||||
return render(request, 'computes/form.html', {'form': form})
|
return render(request, "computes/form.html", {"form": form})
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
|
@ -88,22 +95,22 @@ def compute_update(request, compute_id):
|
||||||
form = FormClass(request.POST or None, instance=compute)
|
form = FormClass(request.POST or None, instance=compute)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
return redirect(reverse('computes'))
|
return redirect(reverse("computes"))
|
||||||
|
|
||||||
return render(request, 'computes/form.html', {'form': form})
|
return render(request, "computes/form.html", {"form": form})
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
def compute_delete(request, compute_id):
|
def compute_delete(request, compute_id):
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
compute.delete()
|
compute.delete()
|
||||||
return redirect('computes')
|
return redirect("computes")
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
'common/confirm_delete.html',
|
"common/confirm_delete.html",
|
||||||
{'object': compute},
|
{"object": compute},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,17 +133,19 @@ def compute_graph(request, compute_id):
|
||||||
mem_usage = conn.get_memory_usage()
|
mem_usage = conn.get_memory_usage()
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
cpu_usage = {'usage': 0}
|
cpu_usage = {"usage": 0}
|
||||||
mem_usage = {'usage': 0}
|
mem_usage = {"usage": 0}
|
||||||
current_time = 0
|
current_time = 0
|
||||||
|
|
||||||
data = json.dumps({
|
data = json.dumps(
|
||||||
'cpudata': cpu_usage['usage'],
|
{
|
||||||
'memdata': mem_usage,
|
"cpudata": cpu_usage["usage"],
|
||||||
'timeline': current_time,
|
"memdata": mem_usage,
|
||||||
})
|
"timeline": current_time,
|
||||||
|
}
|
||||||
|
)
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
response['Content-Type'] = "text/javascript"
|
response["Content-Type"] = "text/javascript"
|
||||||
response.write(data)
|
response.write(data)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -163,14 +172,14 @@ def get_compute_disk_buses(request, compute_id, arch, machine, disk):
|
||||||
disk_device_types = conn.get_disk_device_types(arch, machine)
|
disk_device_types = conn.get_disk_device_types(arch, machine)
|
||||||
|
|
||||||
if disk in disk_device_types:
|
if disk in disk_device_types:
|
||||||
if disk == 'disk':
|
if disk == "disk":
|
||||||
data['bus'] = sorted(disk_device_types)
|
data["bus"] = sorted(disk_device_types)
|
||||||
elif disk == 'cdrom':
|
elif disk == "cdrom":
|
||||||
data['bus'] = ['ide', 'sata', 'scsi']
|
data["bus"] = ["ide", "sata", "scsi"]
|
||||||
elif disk == 'floppy':
|
elif disk == "floppy":
|
||||||
data['bus'] = ['fdc']
|
data["bus"] = ["fdc"]
|
||||||
elif disk == 'lun':
|
elif disk == "lun":
|
||||||
data['bus'] = ['scsi']
|
data["bus"] = ["scsi"]
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -193,7 +202,7 @@ def get_compute_machine_types(request, compute_id, arch):
|
||||||
compute.password,
|
compute.password,
|
||||||
compute.type,
|
compute.type,
|
||||||
)
|
)
|
||||||
data['machines'] = conn.get_machine_types(arch)
|
data["machines"] = conn.get_machine_types(arch)
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -217,7 +226,7 @@ def get_compute_video_models(request, compute_id, arch, machine):
|
||||||
compute.password,
|
compute.password,
|
||||||
compute.type,
|
compute.type,
|
||||||
)
|
)
|
||||||
data['videos'] = conn.get_video_models(arch, machine)
|
data["videos"] = conn.get_video_models(arch, machine)
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -241,8 +250,8 @@ def get_dom_capabilities(request, compute_id, arch, machine):
|
||||||
compute.password,
|
compute.password,
|
||||||
compute.type,
|
compute.type,
|
||||||
)
|
)
|
||||||
data['videos'] = conn.get_disk_device_types(arch, machine)
|
data["videos"] = conn.get_disk_device_types(arch, machine)
|
||||||
data['bus'] = conn.get_disk_device_types(arch, machine)
|
data["bus"] = conn.get_disk_device_types(arch, machine)
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import random, string
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
haystack = string.ascii_letters + string.digits + string.punctuation
|
haystack = string.ascii_letters + string.digits + string.punctuation
|
||||||
print(''.join([random.SystemRandom().choice(haystack.replace('/', '').replace('\'', '').replace('\"', '')) for _ in range(50)]))
|
print(''.join([random.SystemRandom().choice(haystack.replace('/', '').replace('\'', '').replace('\"', '')) for _ in range(50)]))
|
||||||
|
|
|
@ -4,14 +4,13 @@
|
||||||
# See the COPYING file in the top-level directory.
|
# See the COPYING file in the top-level directory.
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
import logging as log
|
||||||
import os
|
import os
|
||||||
import queue
|
import queue
|
||||||
import socket
|
|
||||||
import signal
|
import signal
|
||||||
|
import socket
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import logging as log
|
|
||||||
|
|
||||||
|
|
||||||
class _TunnelScheduler(object):
|
class _TunnelScheduler(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -6,7 +6,11 @@ from libvirt import libvirtError
|
||||||
from appsettings.settings import app_settings
|
from appsettings.settings import app_settings
|
||||||
from instances.models import Instance
|
from instances.models import Instance
|
||||||
from vrtManager.instance import wvmInstance
|
from vrtManager.instance import wvmInstance
|
||||||
from webvirtcloud.settings import WS_PUBLIC_HOST, WS_PUBLIC_PATH, WS_PUBLIC_PORT
|
from webvirtcloud.settings import (
|
||||||
|
WS_PUBLIC_HOST,
|
||||||
|
WS_PUBLIC_PATH,
|
||||||
|
WS_PUBLIC_PORT,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def console(request):
|
def console(request):
|
||||||
|
@ -61,7 +65,7 @@ def console(request):
|
||||||
if console_type is None:
|
if console_type is None:
|
||||||
console_error = "Fail to get console. Please check the console configuration of your VM."
|
console_error = "Fail to get console. Please check the console configuration of your VM."
|
||||||
else:
|
else:
|
||||||
console_error = f"Console type: {console_type} no support"
|
console_error = "Console type '%(type)s' has not support" % {"type": console_type}
|
||||||
response = render(request, "console-vnc-lite.html", locals())
|
response = render(request, "console-vnc-lite.html", locals())
|
||||||
|
|
||||||
response.set_cookie("token", token)
|
response.set_cookie("token", token)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
|
||||||
from accounts.models import UserInstance, UserSSHKey
|
from accounts.models import UserInstance, UserSSHKey
|
||||||
from computes.models import Compute
|
from computes.models import Compute
|
||||||
from vrtManager.instance import wvmInstance
|
from vrtManager.instance import wvmInstance
|
||||||
|
|
||||||
|
|
||||||
OS_VERSIONS = ['latest', '']
|
OS_VERSIONS = ["latest", ""]
|
||||||
OS_UUID = "iid-dswebvirtcloud"
|
OS_UUID = "iid-dswebvirtcloud"
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +19,7 @@ def os_index(request):
|
||||||
:param request:
|
:param request:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
response = '\n'.join(OS_VERSIONS)
|
response = "\n".join(OS_VERSIONS)
|
||||||
return HttpResponse(response)
|
return HttpResponse(response)
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,13 +30,13 @@ def os_metadata_json(request, version):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if version == 'latest':
|
if version == "latest":
|
||||||
ip = get_client_ip(request)
|
ip = get_client_ip(request)
|
||||||
hostname = get_hostname_by_ip(ip)
|
hostname = get_hostname_by_ip(ip)
|
||||||
response = {'uuid': OS_UUID, 'hostname': hostname}
|
response = {"uuid": OS_UUID, "hostname": hostname}
|
||||||
return HttpResponse(json.dumps(response))
|
return HttpResponse(json.dumps(response))
|
||||||
else:
|
else:
|
||||||
err = f"Invalid version: {version}"
|
err = "Invalid version: %(version)s" % {"version": version}
|
||||||
raise Http404(err)
|
raise Http404(err)
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,10 +46,10 @@ def os_userdata(request, version):
|
||||||
:param version:
|
:param version:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if version == 'latest':
|
if version == "latest":
|
||||||
ip = get_client_ip(request)
|
ip = get_client_ip(request)
|
||||||
hostname = get_hostname_by_ip(ip)
|
hostname = get_hostname_by_ip(ip)
|
||||||
vname = hostname.split('.')[0]
|
vname = hostname.split(".")[0]
|
||||||
|
|
||||||
instance_keys = []
|
instance_keys = []
|
||||||
userinstances = UserInstance.objects.filter(instance__name=vname)
|
userinstances = UserInstance.objects.filter(instance__name=vname)
|
||||||
|
@ -57,9 +59,9 @@ def os_userdata(request, version):
|
||||||
for k in keys:
|
for k in keys:
|
||||||
instance_keys.append(k.keypublic)
|
instance_keys.append(k.keypublic)
|
||||||
|
|
||||||
return render(request, 'user_data', locals())
|
return render(request, "user_data", locals())
|
||||||
else:
|
else:
|
||||||
err = f"Invalid version: {version}"
|
err = "Invalid version: %(version)s" % {"version": version}
|
||||||
raise Http404(err)
|
raise Http404(err)
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,11 +70,11 @@ def get_client_ip(request):
|
||||||
:param request:
|
:param request:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
|
||||||
if x_forwarded_for:
|
if x_forwarded_for:
|
||||||
ip = x_forwarded_for.split(',')[-1].strip()
|
ip = x_forwarded_for.split(",")[-1].strip()
|
||||||
else:
|
else:
|
||||||
ip = request.META.get('REMOTE_ADDR')
|
ip = request.META.get("REMOTE_ADDR")
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,16 +99,12 @@ def get_vdi_url(request, compute_id, vname):
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = wvmInstance(compute.hostname,
|
conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, vname)
|
||||||
compute.login,
|
|
||||||
compute.password,
|
|
||||||
compute.type,
|
|
||||||
vname)
|
|
||||||
|
|
||||||
fqdn = get_hostname_by_ip(compute.hostname)
|
fqdn = get_hostname_by_ip(compute.hostname)
|
||||||
url = f"{conn.get_console_type()}://{fqdn}:{conn.get_console_port()}"
|
url = f"{conn.get_console_type()}://{fqdn}:{conn.get_console_port()}"
|
||||||
response = url
|
response = url
|
||||||
return HttpResponse(response)
|
return HttpResponse(response)
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
err = f"Error getting VDI URL for {vname}"
|
err = "Error getting VDI URL for %(name)s" % {"name": vname}
|
||||||
raise Http404(err)
|
raise Http404(err)
|
||||||
|
|
|
@ -25,8 +25,8 @@ def apply_passwordless_console(sender, **kwargs):
|
||||||
'''
|
'''
|
||||||
Apply new passwordless_console permission for all users
|
Apply new passwordless_console permission for all users
|
||||||
'''
|
'''
|
||||||
from django.contrib.auth.models import Permission
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth.models import Permission
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
plan = kwargs.get('plan', [])
|
plan = kwargs.get('plan', [])
|
||||||
for migration, rolled_back in plan:
|
for migration, rolled_back in plan:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# Generated by Django 2.2.10 on 2020-01-28 07:01
|
# Generated by Django 2.2.10 on 2020-01-28 07:01
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -32,4 +32,4 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(add_flavors, del_flavors),
|
migrations.RunPython(add_flavors, del_flavors),
|
||||||
]
|
]
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="takesnapshot">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="takesnapshot">
|
||||||
{% if instance.status == 5 %}
|
{% if instance.status == 5 %}
|
||||||
<p>{% trans "This may take more than an hour, depending on how much content is on your droplet and how large the disk is." %}</p>
|
<p>{% trans "This may take more than an hour, depending on how much content is on your instance and how large the disk is." %}</p>
|
||||||
<form action="{% url 'instances:snapshot' instance.id %}" class="form-inline" method="post" role="form" aria-label="Create snapshot form">
|
<form action="{% url 'instances:snapshot' instance.id %}" class="form-inline" method="post" role="form" aria-label="Create snapshot form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django import template
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,11 @@ from django.contrib.auth.models import Permission
|
||||||
from django.http.response import Http404
|
from django.http.response import Http404
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from instances.views import instance
|
||||||
from libvirt import VIR_DOMAIN_UNDEFINE_NVRAM
|
from libvirt import VIR_DOMAIN_UNDEFINE_NVRAM
|
||||||
from vrtManager.create import wvmCreate
|
from vrtManager.create import wvmCreate
|
||||||
from vrtManager.util import randomUUID
|
from vrtManager.util import randomUUID
|
||||||
|
|
||||||
from instances.views import instance
|
|
||||||
|
|
||||||
from .models import Flavor, Instance
|
from .models import Flavor, Instance
|
||||||
from .utils import refr
|
from .utils import refr
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,5 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
|
@ -26,19 +26,30 @@ def interfaces(request, compute_id):
|
||||||
try:
|
try:
|
||||||
netdevs = conn.get_net_devices()
|
netdevs = conn.get_net_devices()
|
||||||
except:
|
except:
|
||||||
netdevs = ['eth0', 'eth1']
|
netdevs = ["eth0", "eth1"]
|
||||||
|
|
||||||
for iface in ifaces:
|
for iface in ifaces:
|
||||||
ifaces_all.append(conn.get_iface_info(iface))
|
ifaces_all.append(conn.get_iface_info(iface))
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if 'create' in request.POST:
|
if "create" in request.POST:
|
||||||
form = AddInterface(request.POST)
|
form = AddInterface(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
conn.create_iface(data['name'], data['itype'], data['start_mode'], data['netdev'], data['ipv4_type'],
|
conn.create_iface(
|
||||||
data['ipv4_addr'], data['ipv4_gw'], data['ipv6_type'], data['ipv6_addr'],
|
data["name"],
|
||||||
data['ipv6_gw'], data['stp'], data['delay'])
|
data["itype"],
|
||||||
|
data["start_mode"],
|
||||||
|
data["netdev"],
|
||||||
|
data["ipv4_type"],
|
||||||
|
data["ipv4_addr"],
|
||||||
|
data["ipv4_gw"],
|
||||||
|
data["ipv6_type"],
|
||||||
|
data["ipv6_addr"],
|
||||||
|
data["ipv6_gw"],
|
||||||
|
data["stp"],
|
||||||
|
data["delay"],
|
||||||
|
)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
|
@ -47,7 +58,7 @@ def interfaces(request, compute_id):
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'interfaces.html', locals())
|
return render(request, "interfaces.html", locals())
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
|
@ -75,18 +86,18 @@ def interface(request, compute_id, iface):
|
||||||
bridge = conn.get_bridge()
|
bridge = conn.get_bridge()
|
||||||
slave_ifaces = conn.get_bridge_slave_ifaces()
|
slave_ifaces = conn.get_bridge_slave_ifaces()
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if 'stop' in request.POST:
|
if "stop" in request.POST:
|
||||||
conn.stop_iface()
|
conn.stop_iface()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'start' in request.POST:
|
if "start" in request.POST:
|
||||||
conn.start_iface()
|
conn.start_iface()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'delete' in request.POST:
|
if "delete" in request.POST:
|
||||||
conn.delete_iface()
|
conn.delete_iface()
|
||||||
return HttpResponseRedirect(reverse('interfaces', args=[compute_id]))
|
return HttpResponseRedirect(reverse("interfaces", args=[compute_id]))
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'interface.html', locals())
|
return render(request, "interface.html", locals())
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
from django.db.models import Model, CharField, DateTimeField
|
from django.db.models import CharField, DateTimeField, Model
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class Logs(Model):
|
class Logs(Model):
|
||||||
user = CharField(_('user'), max_length=50)
|
user = CharField(_("user"), max_length=50)
|
||||||
instance = CharField(_('instance'), max_length=50)
|
instance = CharField(_("instance"), max_length=50)
|
||||||
message = CharField(_('message'), max_length=255)
|
message = CharField(_("message"), max_length=255)
|
||||||
date = DateTimeField(_('date'), auto_now=True)
|
date = DateTimeField(_("date"), auto_now=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.instance
|
return self.instance
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('vm_logs/<vname>/', views.vm_logs, name='vm_logs'),
|
path("vm_logs/<vname>/", views.vm_logs, name="vm_logs"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from admin.decorators import superuser_only
|
from admin.decorators import superuser_only
|
||||||
from instances.models import Instance
|
from instances.models import Instance
|
||||||
|
@ -29,14 +27,14 @@ def vm_logs(request, vname):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
vm = Instance.objects.get(name=vname)
|
vm = Instance.objects.get(name=vname)
|
||||||
logs_ = Logs.objects.filter(instance=vm.name, date__gte=vm.created).order_by('-date')
|
logs_ = Logs.objects.filter(instance=vm.name, date__gte=vm.created).order_by("-date")
|
||||||
logs = []
|
logs = []
|
||||||
for l in logs_:
|
for l in logs_:
|
||||||
log = dict()
|
log = dict()
|
||||||
log['user'] = l.user
|
log["user"] = l.user
|
||||||
log['instance'] = l.instance
|
log["instance"] = l.instance
|
||||||
log['message'] = l.message
|
log["message"] = l.message
|
||||||
log['date'] = l.date.strftime('%x %X')
|
log["date"] = l.date.strftime("%x %X")
|
||||||
logs.append(log)
|
logs.append(log)
|
||||||
|
|
||||||
return HttpResponse(json.dumps(logs))
|
return HttpResponse(json.dumps(logs))
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class AddNetPool(forms.Form):
|
class AddNetPool(forms.Form):
|
||||||
name = forms.CharField(error_messages={'required': _('No pool name has been entered')},
|
name = forms.CharField(error_messages={"required": _("No pool name has been entered")}, max_length=20)
|
||||||
max_length=20)
|
subnet = forms.CharField(
|
||||||
subnet = forms.CharField(error_messages={'required': _('No IPv4 subnet has been entered')},
|
error_messages={"required": _("No IPv4 subnet has been entered")},
|
||||||
max_length=20, required=False)
|
max_length=20,
|
||||||
subnet6 = forms.CharField(error_messages={'required': _('No IPv6 subnet has been entered')},
|
required=False,
|
||||||
max_length=42, required=False)
|
)
|
||||||
|
subnet6 = forms.CharField(
|
||||||
|
error_messages={"required": _("No IPv6 subnet has been entered")},
|
||||||
|
max_length=42,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
forward = forms.CharField(max_length=100)
|
forward = forms.CharField(max_length=100)
|
||||||
dhcp4 = forms.BooleanField(required=False)
|
dhcp4 = forms.BooleanField(required=False)
|
||||||
dhcp6 = forms.BooleanField(required=False)
|
dhcp6 = forms.BooleanField(required=False)
|
||||||
|
@ -18,38 +24,38 @@ class AddNetPool(forms.Form):
|
||||||
openvswitch = forms.BooleanField(required=False)
|
openvswitch = forms.BooleanField(required=False)
|
||||||
|
|
||||||
def clean_name(self):
|
def clean_name(self):
|
||||||
name = self.cleaned_data['name']
|
name = self.cleaned_data["name"]
|
||||||
have_symbol = re.match('^[a-zA-Z0-9\.\_\-]+$', name)
|
have_symbol = re.match(r"^[a-zA-Z0-9\.\_\-]+$", name)
|
||||||
if not have_symbol:
|
if not have_symbol:
|
||||||
raise forms.ValidationError(_('The pool name must not contain any special characters'))
|
raise forms.ValidationError(_("The pool name must not contain any special characters"))
|
||||||
elif len(name) > 20:
|
elif len(name) > 20:
|
||||||
raise forms.ValidationError(_('The pool name must not exceed 20 characters'))
|
raise forms.ValidationError(_("The pool name must not exceed 20 characters"))
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def clean_subnet(self):
|
def clean_subnet(self):
|
||||||
subnet = self.cleaned_data['subnet']
|
subnet = self.cleaned_data["subnet"]
|
||||||
have_symbol = re.match('^[0-9./]+$', subnet if subnet else ".")
|
have_symbol = re.match("^[0-9./]+$", subnet if subnet else ".")
|
||||||
if not have_symbol:
|
if not have_symbol:
|
||||||
raise forms.ValidationError(_('The IPv4 subnet must not contain any special characters'))
|
raise forms.ValidationError(_("The IPv4 subnet must not contain any special characters"))
|
||||||
elif len(subnet) > 20:
|
elif len(subnet) > 20:
|
||||||
raise forms.ValidationError(_('The IPv4 subnet must not exceed 20 characters'))
|
raise forms.ValidationError(_("The IPv4 subnet must not exceed 20 characters"))
|
||||||
return subnet
|
return subnet
|
||||||
|
|
||||||
def clean_subnet6(self):
|
def clean_subnet6(self):
|
||||||
subnet = self.cleaned_data['subnet6']
|
subnet = self.cleaned_data["subnet6"]
|
||||||
have_symbol = re.match('^[0-9a-fA-F:/]+$', subnet if subnet else ":")
|
have_symbol = re.match("^[0-9a-fA-F:/]+$", subnet if subnet else ":")
|
||||||
if not have_symbol:
|
if not have_symbol:
|
||||||
raise forms.ValidationError(_('The IPv6 subnet must not contain any special characters'))
|
raise forms.ValidationError(_("The IPv6 subnet must not contain any special characters"))
|
||||||
elif len(subnet) > 42:
|
elif len(subnet) > 42:
|
||||||
raise forms.ValidationError(_('The IPv6 subnet must not exceed 42 characters'))
|
raise forms.ValidationError(_("The IPv6 subnet must not exceed 42 characters"))
|
||||||
return subnet
|
return subnet
|
||||||
|
|
||||||
def clean_bridge_name(self):
|
def clean_bridge_name(self):
|
||||||
bridge_name = self.cleaned_data['bridge_name']
|
bridge_name = self.cleaned_data["bridge_name"]
|
||||||
if self.cleaned_data['forward'] in ['bridge', 'macvtap']:
|
if self.cleaned_data["forward"] in ["bridge", "macvtap"]:
|
||||||
have_symbol = re.match('^[a-zA-Z0-9\.\_\:\-]+$', bridge_name)
|
have_symbol = re.match(r"^[a-zA-Z0-9\.\_\:\-]+$", bridge_name)
|
||||||
if not have_symbol:
|
if not have_symbol:
|
||||||
raise forms.ValidationError(_('The pool bridge name must not contain any special characters'))
|
raise forms.ValidationError(_("The pool bridge name must not contain any special characters"))
|
||||||
elif len(bridge_name) > 20:
|
elif len(bridge_name) > 20:
|
||||||
raise forms.ValidationError(_('The pool bridge name must not exceed 20 characters'))
|
raise forms.ValidationError(_("The pool bridge name must not exceed 20 characters"))
|
||||||
return bridge_name
|
return bridge_name
|
||||||
|
|
|
@ -30,35 +30,37 @@ def networks(request, compute_id):
|
||||||
compute.type,
|
compute.type,
|
||||||
)
|
)
|
||||||
networks = conn.get_networks_info()
|
networks = conn.get_networks_info()
|
||||||
dhcp4 = netmask4 = gateway4 = ''
|
dhcp4 = netmask4 = gateway4 = ""
|
||||||
dhcp6 = prefix6 = gateway6 = ''
|
dhcp6 = prefix6 = gateway6 = ""
|
||||||
ipv4 = ipv6 = False
|
ipv4 = ipv6 = False
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if 'create' in request.POST:
|
if "create" in request.POST:
|
||||||
form = AddNetPool(request.POST)
|
form = AddNetPool(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
if data['name'] in networks:
|
if data["name"] in networks:
|
||||||
msg = _("Network pool name already in use")
|
msg = _("Network pool name already in use")
|
||||||
messages.error(request, msg)
|
messages.error(request, msg)
|
||||||
errors = True
|
errors = True
|
||||||
if data['forward'] in ['bridge', 'macvtap'] and data['bridge_name'] == '':
|
if data["forward"] in ["bridge", "macvtap"] and data["bridge_name"] == "":
|
||||||
messages.error(request, _('Please enter bridge/dev name'))
|
messages.error(request, _("Please enter bridge/dev name"))
|
||||||
errors = True
|
errors = True
|
||||||
if data['subnet']:
|
if data["subnet"]:
|
||||||
ipv4 = True
|
ipv4 = True
|
||||||
gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4'])
|
gateway4, netmask4, dhcp4 = network_size(data["subnet"], data["dhcp4"])
|
||||||
if data['subnet6']:
|
if data["subnet6"]:
|
||||||
ipv6 = True
|
ipv6 = True
|
||||||
gateway6, prefix6, dhcp6 = network_size(data['subnet6'], data['dhcp6'])
|
gateway6, prefix6, dhcp6 = network_size(data["subnet6"], data["dhcp6"])
|
||||||
if prefix6 != '64':
|
if prefix6 != "64":
|
||||||
messages.error(request, _('For libvirt, the IPv6 network prefix must be /64'))
|
messages.error(
|
||||||
|
request, _("For libvirt, the IPv6 network prefix must be /64")
|
||||||
|
)
|
||||||
errors = True
|
errors = True
|
||||||
if not errors:
|
if not errors:
|
||||||
conn.create_network(
|
conn.create_network(
|
||||||
data['name'],
|
data["name"],
|
||||||
data['forward'],
|
data["forward"],
|
||||||
ipv4,
|
ipv4,
|
||||||
gateway4,
|
gateway4,
|
||||||
netmask4,
|
netmask4,
|
||||||
|
@ -67,11 +69,13 @@ def networks(request, compute_id):
|
||||||
gateway6,
|
gateway6,
|
||||||
prefix6,
|
prefix6,
|
||||||
dhcp6,
|
dhcp6,
|
||||||
data['bridge_name'],
|
data["bridge_name"],
|
||||||
data['openvswitch'],
|
data["openvswitch"],
|
||||||
data['fixed'],
|
data["fixed"],
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(
|
||||||
|
reverse("network", args=[compute_id, data["name"]])
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(reverse('network', args=[compute_id, data['name']]))
|
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
messages.error(request, msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
|
@ -79,7 +83,7 @@ def networks(request, compute_id):
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'networks.html', locals())
|
return render(request, "networks.html", locals())
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
|
@ -128,112 +132,119 @@ def network(request, compute_id, pool):
|
||||||
xml = conn._XMLDesc(0)
|
xml = conn._XMLDesc(0)
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
return HttpResponseRedirect(reverse('networks', args=compute_id))
|
return HttpResponseRedirect(reverse("networks", args=compute_id))
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if 'start' in request.POST:
|
if "start" in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.start()
|
conn.start()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'stop' in request.POST:
|
if "stop" in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.stop()
|
conn.stop()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'delete' in request.POST:
|
if "delete" in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.delete()
|
conn.delete()
|
||||||
return HttpResponseRedirect(reverse('networks', args=[compute_id]))
|
return HttpResponseRedirect(reverse("networks", args=[compute_id]))
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'set_autostart' in request.POST:
|
if "set_autostart" in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.set_autostart(1)
|
conn.set_autostart(1)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'unset_autostart' in request.POST:
|
if "unset_autostart" in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.set_autostart(0)
|
conn.set_autostart(0)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'modify_fixed_address' in request.POST:
|
if "modify_fixed_address" in request.POST:
|
||||||
name = request.POST.get('name', '')
|
name = request.POST.get("name", "")
|
||||||
address = request.POST.get('address', '')
|
address = request.POST.get("address", "")
|
||||||
family = request.POST.get('family', 'ipv4')
|
family = request.POST.get("family", "ipv4")
|
||||||
|
|
||||||
if family == 'ipv4':
|
if family == "ipv4":
|
||||||
mac_duid = request.POST.get('mac', '')
|
mac_duid = request.POST.get("mac", "")
|
||||||
if family == 'ipv6':
|
if family == "ipv6":
|
||||||
mac_duid = request.POST.get('id', '')
|
mac_duid = request.POST.get("id", "")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ret_val = conn.modify_fixed_address(name, address, mac_duid, family)
|
ret_val = conn.modify_fixed_address(name, address, mac_duid, family)
|
||||||
messages.success(request, _(f"{family.upper()} Fixed Address Operation Completed."))
|
messages.success(request, _("Fixed address operation completed for %(family)s") % {"family": family.upper()})
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
except ValueError as val_err:
|
except ValueError as val_err:
|
||||||
messages.error(request, val_err)
|
messages.error(request, val_err)
|
||||||
if 'delete_fixed_address' in request.POST:
|
if "delete_fixed_address" in request.POST:
|
||||||
ip = request.POST.get('address', '')
|
ip = request.POST.get("address", "")
|
||||||
family = request.POST.get('family', 'ipv4')
|
family = request.POST.get("family", "ipv4")
|
||||||
conn.delete_fixed_address(ip, family)
|
conn.delete_fixed_address(ip, family)
|
||||||
messages.success(request, _(f"{family.upper()} Fixed Address is Deleted."))
|
messages.success(request, _("%(family)s Fixed Address is Deleted.") % {"family": family.upper()})
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'modify_dhcp_range' in request.POST:
|
if "modify_dhcp_range" in request.POST:
|
||||||
range_start = request.POST.get('range_start', '')
|
range_start = request.POST.get("range_start", "")
|
||||||
range_end = request.POST.get('range_end', '')
|
range_end = request.POST.get("range_end", "")
|
||||||
family = request.POST.get('family', 'ipv4')
|
family = request.POST.get("family", "ipv4")
|
||||||
try:
|
try:
|
||||||
conn.modify_dhcp_range(range_start, range_end, family)
|
conn.modify_dhcp_range(range_start, range_end, family)
|
||||||
messages.success(request, _(f"{family.upper()} DHCP Range is Changed."))
|
messages.success(request, _("%(family)s DHCP Range is Changed.") % {"family": family.upper()})
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'edit_network' in request.POST:
|
if "edit_network" in request.POST:
|
||||||
edit_xml = request.POST.get('edit_xml', '')
|
edit_xml = request.POST.get("edit_xml", "")
|
||||||
if edit_xml:
|
if edit_xml:
|
||||||
conn.edit_network(edit_xml)
|
conn.edit_network(edit_xml)
|
||||||
if conn.is_active():
|
if conn.is_active():
|
||||||
messages.success(request, _("Network XML is changed. \\" "Stop and start network to activate new config."))
|
messages.success(
|
||||||
|
request,
|
||||||
|
_(
|
||||||
|
"Network XML is changed. \\"
|
||||||
|
"Stop and start network to activate new config."
|
||||||
|
),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
messages.success(request, _("Network XML is changed."))
|
messages.success(request, _("Network XML is changed."))
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'set_qos' in request.POST:
|
if "set_qos" in request.POST:
|
||||||
qos_dir = request.POST.get('qos_direction', '')
|
qos_dir = request.POST.get("qos_direction", "")
|
||||||
average = request.POST.get('qos_average') or 0
|
average = request.POST.get("qos_average") or 0
|
||||||
peak = request.POST.get('qos_peak') or 0
|
peak = request.POST.get("qos_peak") or 0
|
||||||
burst = request.POST.get('qos_burst') or 0
|
burst = request.POST.get("qos_burst") or 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn.set_qos(qos_dir, average, peak, burst)
|
conn.set_qos(qos_dir, average, peak, burst)
|
||||||
if conn.is_active():
|
if conn.is_active():
|
||||||
messages.success(
|
messages.success(
|
||||||
request,
|
request,
|
||||||
_(f"{qos_dir.capitalize()} QoS is set. Network XML is changed.") +
|
_("%(qos_dir)s QoS is updated. Network XML is changed. Stop and start network to activate new config") % {"qos_dir": qos_dir.capitalize()}
|
||||||
_("Stop and start network to activate new config"))
|
)
|
||||||
else:
|
else:
|
||||||
messages.success(request, _("{} QoS is set").format(qos_dir.capitalize()))
|
messages.success(request, _("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()})
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'unset_qos' in request.POST:
|
if "unset_qos" in request.POST:
|
||||||
qos_dir = request.POST.get('qos_direction', '')
|
qos_dir = request.POST.get("qos_direction", "")
|
||||||
conn.unset_qos(qos_dir)
|
conn.unset_qos(qos_dir)
|
||||||
|
|
||||||
if conn.is_active():
|
if conn.is_active():
|
||||||
messages.success(
|
messages.success(
|
||||||
request,
|
request,
|
||||||
_(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. ") +
|
_("%(qos_dir)s QoS is deleted. Network XML is changed. \
|
||||||
_("Stop and start network to activate new config."))
|
Stop and start network to activate new config") % {"qos_dir": qos_dir.capitalize()}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
messages.success(request, _(f"{qos_dir.capitalize()} QoS is deleted"))
|
messages.success(request, _("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()})
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return render(request, 'network.html', locals())
|
return render(request, "network.html", locals())
|
||||||
|
|
|
@ -5,4 +5,4 @@ from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class NwfiltersConfig(AppConfig):
|
class NwfiltersConfig(AppConfig):
|
||||||
name = 'nwfilters'
|
name = "nwfilters"
|
||||||
|
|
|
@ -25,48 +25,55 @@ def nwfilters(request, compute_id):
|
||||||
try:
|
try:
|
||||||
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
|
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
|
||||||
|
|
||||||
if request.method == 'POST':
|
for nwf in conn.get_nwfilters():
|
||||||
if 'create_nwfilter' in request.POST:
|
nwfilters_all.append(conn.get_nwfilter_info(nwf))
|
||||||
xml = request.POST.get('nwfilter_xml', '')
|
|
||||||
|
if request.method == "POST":
|
||||||
|
if "create_nwfilter" in request.POST:
|
||||||
|
xml = request.POST.get("nwfilter_xml", "")
|
||||||
if xml:
|
if xml:
|
||||||
try:
|
try:
|
||||||
util.etree.fromstring(xml)
|
util.etree.fromstring(xml)
|
||||||
name = util.get_xml_path(xml, '/filter/@name')
|
name = util.get_xml_path(xml, "/filter/@name")
|
||||||
uuid = util.get_xml_path(xml, '/filter/uuid')
|
uuid = util.get_xml_path(xml, "/filter/uuid")
|
||||||
except util.etree.ParseError:
|
except util.etree.ParseError:
|
||||||
name = None
|
name = None
|
||||||
|
|
||||||
for nwf in nwfilters:
|
for nwf in nwfilters_all:
|
||||||
if name == nwf.name():
|
if name == nwf["name"]:
|
||||||
error_msg = _("A network filter with this name already exists")
|
error_msg = _("A network filter with this name already exists")
|
||||||
raise Exception(error_msg)
|
raise Exception(error_msg)
|
||||||
if uuid == nwf.UUIDString():
|
if uuid == nwf["uuid"]:
|
||||||
error_msg = _("A network filter with this UUID already exists")
|
error_msg = _("A network filter with this UUID already exists")
|
||||||
raise Exception(error_msg)
|
raise Exception(error_msg)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
msg = _("Creating NWFilter: %s" % name)
|
msg = _("%(filter)s network filter is created") % {"filter": name}
|
||||||
conn.create_nwfilter(xml)
|
conn.create_nwfilter(xml)
|
||||||
addlogmsg(request.user.username, compute.hostname, msg)
|
addlogmsg(request.user.username, compute.hostname, msg)
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
addlogmsg(request.user.username, compute.hostname, lib_err)
|
addlogmsg(request.user.username, compute.hostname, lib_err)
|
||||||
|
|
||||||
if 'del_nwfilter' in request.POST:
|
if "del_nwfilter" in request.POST:
|
||||||
name = request.POST.get('nwfiltername', '')
|
name = request.POST.get("nwfiltername", "")
|
||||||
msg = _(f"Deleting NWFilter: {name}")
|
msg = _("%(filter)s network filter is deleted") % {"filter": name}
|
||||||
in_use = False
|
in_use = False
|
||||||
nwfilter = conn.get_nwfilter(name)
|
nwfilter = conn.get_nwfilter(name)
|
||||||
|
|
||||||
is_conn = wvmInstances(compute.hostname, compute.login, compute.password, compute.type)
|
is_conn = wvmInstances(
|
||||||
|
compute.hostname, compute.login, compute.password, compute.type
|
||||||
|
)
|
||||||
instances = is_conn.get_instances()
|
instances = is_conn.get_instances()
|
||||||
for inst in instances:
|
for inst in instances:
|
||||||
i_conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, inst)
|
i_conn = wvmInstance(
|
||||||
|
compute.hostname, compute.login, compute.password, compute.type, inst
|
||||||
|
)
|
||||||
dom_filterrefs = i_conn.get_filterrefs()
|
dom_filterrefs = i_conn.get_filterrefs()
|
||||||
|
|
||||||
if name in dom_filterrefs:
|
if name in dom_filterrefs:
|
||||||
in_use = True
|
in_use = True
|
||||||
msg = _(f"NWFilter is in use by {inst}. Cannot be deleted.")
|
msg = _("NWFilter is in use by %(instance)s. Cannot be deleted.") % {"instance": inst}
|
||||||
messages.error(request, msg)
|
messages.error(request, msg)
|
||||||
addlogmsg(request.user.username, compute.hostname, msg)
|
addlogmsg(request.user.username, compute.hostname, msg)
|
||||||
i_conn.close()
|
i_conn.close()
|
||||||
|
@ -77,18 +84,15 @@ def nwfilters(request, compute_id):
|
||||||
nwfilter.undefine()
|
nwfilter.undefine()
|
||||||
addlogmsg(request.user.username, compute.hostname, msg)
|
addlogmsg(request.user.username, compute.hostname, msg)
|
||||||
|
|
||||||
if 'cln_nwfilter' in request.POST:
|
if "cln_nwfilter" in request.POST:
|
||||||
|
|
||||||
name = request.POST.get('nwfiltername', '')
|
name = request.POST.get("nwfiltername", "")
|
||||||
cln_name = request.POST.get('cln_name', name + '-clone')
|
cln_name = request.POST.get("cln_name", name + "-clone")
|
||||||
|
|
||||||
conn.clone_nwfilter(name, cln_name)
|
conn.clone_nwfilter(name, cln_name)
|
||||||
msg = _(f"Cloning NWFilter {name} as {cln_name}")
|
msg = _("Cloning NWFilter %(name)s as %(clone)s") % {"name":name, "clone": cln_name}
|
||||||
addlogmsg(request.user.username, compute.hostname, msg)
|
addlogmsg(request.user.username, compute.hostname, msg)
|
||||||
|
|
||||||
for nwf in conn.get_nwfilters():
|
|
||||||
nwfilters_all.append(conn.get_nwfilter_info(nwf))
|
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
|
@ -97,10 +101,14 @@ def nwfilters(request, compute_id):
|
||||||
messages.error(request, err)
|
messages.error(request, err)
|
||||||
addlogmsg(request.user.username, compute.hostname, err)
|
addlogmsg(request.user.username, compute.hostname, err)
|
||||||
|
|
||||||
return render(request, 'nwfilters.html', {
|
return render(
|
||||||
'nwfilters': nwfilters_all,
|
request,
|
||||||
'compute': compute,
|
"nwfilters.html",
|
||||||
})
|
{
|
||||||
|
"nwfilters": nwfilters_all,
|
||||||
|
"compute": compute,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def nwfilter(request, compute_id, nwfltr):
|
def nwfilter(request, compute_id, nwfltr):
|
||||||
|
@ -114,7 +122,9 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
nwfilter = wvmNWFilter(compute.hostname, compute.login, compute.password, compute.type, nwfltr)
|
nwfilter = wvmNWFilter(
|
||||||
|
compute.hostname, compute.login, compute.password, compute.type, nwfltr
|
||||||
|
)
|
||||||
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
|
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
|
||||||
|
|
||||||
for nwf in conn.get_nwfilters():
|
for nwf in conn.get_nwfilters():
|
||||||
|
@ -126,10 +136,10 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
rules = nwfilter.get_rules()
|
rules = nwfilter.get_rules()
|
||||||
refs = nwfilter.get_filter_refs()
|
refs = nwfilter.get_filter_refs()
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
|
|
||||||
if 'edit_nwfilter' in request.POST:
|
if "edit_nwfilter" in request.POST:
|
||||||
new_xml = request.POST.get('edit_xml', '')
|
new_xml = request.POST.get("edit_xml", "")
|
||||||
|
|
||||||
if new_xml:
|
if new_xml:
|
||||||
nwfilter.delete()
|
nwfilter.delete()
|
||||||
|
@ -139,10 +149,10 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
conn.create_nwfilter(xml)
|
conn.create_nwfilter(xml)
|
||||||
raise libvirtError(lib_err)
|
raise libvirtError(lib_err)
|
||||||
|
|
||||||
if 'del_nwfilter_rule' in request.POST:
|
if "del_nwfilter_rule" in request.POST:
|
||||||
action = request.POST.get('action', '')
|
action = request.POST.get("action", "")
|
||||||
direction = request.POST.get('direction', '')
|
direction = request.POST.get("direction", "")
|
||||||
priority = request.POST.get('priority', '')
|
priority = request.POST.get("priority", "")
|
||||||
|
|
||||||
new_xml = nwfilter.delete_rule(action, direction, priority)
|
new_xml = nwfilter.delete_rule(action, direction, priority)
|
||||||
nwfilter.delete()
|
nwfilter.delete()
|
||||||
|
@ -152,8 +162,8 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
conn.create_nwfilter(xml)
|
conn.create_nwfilter(xml)
|
||||||
raise libvirtError(lib_err)
|
raise libvirtError(lib_err)
|
||||||
|
|
||||||
if 'del_nwfilter_ref' in request.POST:
|
if "del_nwfilter_ref" in request.POST:
|
||||||
ref_name = request.POST.get('ref')
|
ref_name = request.POST.get("ref")
|
||||||
new_xml = nwfilter.delete_ref(ref_name)
|
new_xml = nwfilter.delete_ref(ref_name)
|
||||||
nwfilter.delete()
|
nwfilter.delete()
|
||||||
try:
|
try:
|
||||||
|
@ -162,8 +172,8 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
conn.create_nwfilter(xml)
|
conn.create_nwfilter(xml)
|
||||||
raise libvirtError(lib_err)
|
raise libvirtError(lib_err)
|
||||||
|
|
||||||
if 'add_nwfilter_rule' in request.POST:
|
if "add_nwfilter_rule" in request.POST:
|
||||||
rule_xml = request.POST.get('nwfilterrule_xml', '')
|
rule_xml = request.POST.get("nwfilterrule_xml", "")
|
||||||
if not rule_xml:
|
if not rule_xml:
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
new_xml = nwfilter.add_rule(rule_xml)
|
new_xml = nwfilter.add_rule(rule_xml)
|
||||||
|
@ -174,8 +184,8 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
conn.create_nwfilter(xml)
|
conn.create_nwfilter(xml)
|
||||||
raise libvirtError(lib_err)
|
raise libvirtError(lib_err)
|
||||||
|
|
||||||
if 'add_nwfilter_ref' in request.POST:
|
if "add_nwfilter_ref" in request.POST:
|
||||||
ref_name = request.POST.get('nwfilters_select', '')
|
ref_name = request.POST.get("nwfilters_select", "")
|
||||||
if not ref_name:
|
if not ref_name:
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
new_xml = nwfilter.add_ref(ref_name)
|
new_xml = nwfilter.add_ref(ref_name)
|
||||||
|
@ -194,4 +204,4 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
except Exception as error_msg:
|
except Exception as error_msg:
|
||||||
messages.error(request, error_msg)
|
messages.error(request, error_msg)
|
||||||
|
|
||||||
return render(request, 'nwfilter.html', locals())
|
return render(request, "nwfilter.html", locals())
|
||||||
|
|
|
@ -5,8 +5,14 @@ from computes.models import Compute
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from libvirt import (VIR_SECRET_USAGE_TYPE_CEPH, VIR_SECRET_USAGE_TYPE_ISCSI, VIR_SECRET_USAGE_TYPE_NONE,
|
from libvirt import (
|
||||||
VIR_SECRET_USAGE_TYPE_TLS, VIR_SECRET_USAGE_TYPE_VOLUME, libvirtError)
|
VIR_SECRET_USAGE_TYPE_CEPH,
|
||||||
|
VIR_SECRET_USAGE_TYPE_ISCSI,
|
||||||
|
VIR_SECRET_USAGE_TYPE_NONE,
|
||||||
|
VIR_SECRET_USAGE_TYPE_TLS,
|
||||||
|
VIR_SECRET_USAGE_TYPE_VOLUME,
|
||||||
|
libvirtError,
|
||||||
|
)
|
||||||
from vrtManager.secrets import wvmSecrets
|
from vrtManager.secrets import wvmSecrets
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,36 +42,38 @@ def secrets(request, compute_id):
|
||||||
secrt = conn.get_secret(uuid)
|
secrt = conn.get_secret(uuid)
|
||||||
try:
|
try:
|
||||||
secrt_value = conn.get_secret_value(uuid)
|
secrt_value = conn.get_secret_value(uuid)
|
||||||
except libvirtError as lib_err:
|
except libvirtError:
|
||||||
secrt_value = None
|
secrt_value = None
|
||||||
secrets_all.append({
|
secrets_all.append(
|
||||||
'usage': secrt.usageID(),
|
{
|
||||||
'uuid': secrt.UUIDString(),
|
"usage": secrt.usageID(),
|
||||||
'usageType': secret_usage_types[secrt.usageType()],
|
"uuid": secrt.UUIDString(),
|
||||||
'value': secrt_value
|
"usageType": secret_usage_types[secrt.usageType()],
|
||||||
})
|
"value": secrt_value,
|
||||||
if request.method == 'POST':
|
}
|
||||||
if 'create' in request.POST:
|
)
|
||||||
|
if request.method == "POST":
|
||||||
|
if "create" in request.POST:
|
||||||
form = AddSecret(request.POST)
|
form = AddSecret(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
conn.create_secret(
|
conn.create_secret(
|
||||||
data['ephemeral'],
|
data["ephemeral"],
|
||||||
data['private'],
|
data["private"],
|
||||||
data['usage_type'],
|
data["usage_type"],
|
||||||
data['data'],
|
data["data"],
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
messages.error(request, msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
if 'delete' in request.POST:
|
if "delete" in request.POST:
|
||||||
uuid = request.POST.get('uuid', '')
|
uuid = request.POST.get("uuid", "")
|
||||||
conn.delete_secret(uuid)
|
conn.delete_secret(uuid)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'set_value' in request.POST:
|
if "set_value" in request.POST:
|
||||||
uuid = request.POST.get('uuid', '')
|
uuid = request.POST.get("uuid", "")
|
||||||
value = request.POST.get('value', '')
|
value = request.POST.get("value", "")
|
||||||
try:
|
try:
|
||||||
conn.set_secret_value(uuid, value)
|
conn.set_secret_value(uuid, value)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -74,4 +82,4 @@ def secrets(request, compute_id):
|
||||||
except libvirtError as err:
|
except libvirtError as err:
|
||||||
messages.error(request, err)
|
messages.error(request, err)
|
||||||
|
|
||||||
return render(request, 'secrets.html', locals())
|
return render(request, "secrets.html", locals())
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
|
||||||
from admin.decorators import superuser_only
|
from admin.decorators import superuser_only
|
||||||
from appsettings.models import AppSettings
|
|
||||||
from appsettings.settings import app_settings
|
from appsettings.settings import app_settings
|
||||||
from computes.models import Compute
|
from computes.models import Compute
|
||||||
from storages.forms import AddStgPool, CloneImage, CreateVolumeForm
|
from storages.forms import AddStgPool, CloneImage, CreateVolumeForm
|
||||||
|
@ -31,34 +30,46 @@ def storages(request, compute_id):
|
||||||
storages = conn.get_storages_info()
|
storages = conn.get_storages_info()
|
||||||
secrets = conn.get_secrets()
|
secrets = conn.get_secrets()
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if 'create' in request.POST:
|
if "create" in request.POST:
|
||||||
form = AddStgPool(request.POST)
|
form = AddStgPool(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
if data['name'] in storages:
|
if data["name"] in storages:
|
||||||
msg = _("Pool name already use")
|
msg = _("Pool name already use")
|
||||||
messages.error(request, msg)
|
messages.error(request, msg)
|
||||||
errors = True
|
errors = True
|
||||||
if data['stg_type'] == 'rbd':
|
if data["stg_type"] == "rbd":
|
||||||
if not data['secret']:
|
if not data["secret"]:
|
||||||
msg = _("You need create secret for pool")
|
msg = _("You need create secret for pool")
|
||||||
messages.error(request, msg)
|
messages.error(request, msg)
|
||||||
errors = True
|
errors = True
|
||||||
if not data['ceph_pool'] and not data['ceph_host'] and not data['ceph_user']:
|
if not data["ceph_pool"] and not data["ceph_host"] and not data["ceph_user"]:
|
||||||
msg = _("You need input all fields for creating ceph pool")
|
msg = _("You need input all fields for creating ceph pool")
|
||||||
messages.error(request, msg)
|
messages.error(request, msg)
|
||||||
errors = True
|
errors = True
|
||||||
if not errors:
|
if not errors:
|
||||||
if data['stg_type'] == 'rbd':
|
if data["stg_type"] == "rbd":
|
||||||
conn.create_storage_ceph(data['stg_type'], data['name'], data['ceph_pool'], data['ceph_host'],
|
conn.create_storage_ceph(
|
||||||
data['ceph_user'], data['secret'])
|
data["stg_type"],
|
||||||
elif data['stg_type'] == 'netfs':
|
data["name"],
|
||||||
conn.create_storage_netfs(data['stg_type'], data['name'], data['netfs_host'], data['source'],
|
data["ceph_pool"],
|
||||||
data['source_format'], data['target'])
|
data["ceph_host"],
|
||||||
|
data["ceph_user"],
|
||||||
|
data["secret"],
|
||||||
|
)
|
||||||
|
elif data["stg_type"] == "netfs":
|
||||||
|
conn.create_storage_netfs(
|
||||||
|
data["stg_type"],
|
||||||
|
data["name"],
|
||||||
|
data["netfs_host"],
|
||||||
|
data["source"],
|
||||||
|
data["source_format"],
|
||||||
|
data["target"],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
conn.create_storage(data['stg_type'], data['name'], data['source'], data['target'])
|
conn.create_storage(data["stg_type"], data["name"], data["source"], data["target"])
|
||||||
return HttpResponseRedirect(reverse('storage', args=[compute_id, data['name']]))
|
return HttpResponseRedirect(reverse("storage", args=[compute_id, data["name"]]))
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
messages.error(request, msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
|
@ -66,7 +77,7 @@ def storages(request, compute_id):
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'storages.html', locals())
|
return render(request, "storages.html", locals())
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
|
@ -77,9 +88,10 @@ def storage(request, compute_id, pool):
|
||||||
:param pool:
|
:param pool:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle_uploaded_file(path, f_name):
|
def handle_uploaded_file(path, f_name):
|
||||||
target = path + '/' + str(f_name)
|
target = path + "/" + str(f_name)
|
||||||
destination = open(target, 'wb+')
|
destination = open(target, "wb+")
|
||||||
for chunk in f_name.chunks():
|
for chunk in f_name.chunks():
|
||||||
destination.write(chunk)
|
destination.write(chunk)
|
||||||
destination.close()
|
destination.close()
|
||||||
|
@ -93,7 +105,7 @@ def storage(request, compute_id, pool):
|
||||||
storages = conn.get_storages()
|
storages = conn.get_storages()
|
||||||
state = conn.is_active()
|
state = conn.is_active()
|
||||||
size, free = conn.get_size()
|
size, free = conn.get_size()
|
||||||
used = (size - free)
|
used = size - free
|
||||||
if state:
|
if state:
|
||||||
percent = (used * 100) // size
|
percent = (used * 100) // size
|
||||||
else:
|
else:
|
||||||
|
@ -109,55 +121,58 @@ def storage(request, compute_id, pool):
|
||||||
else:
|
else:
|
||||||
volumes = None
|
volumes = None
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if 'start' in request.POST:
|
if "start" in request.POST:
|
||||||
conn.start()
|
conn.start()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'stop' in request.POST:
|
if "stop" in request.POST:
|
||||||
conn.stop()
|
conn.stop()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'delete' in request.POST:
|
if "delete" in request.POST:
|
||||||
conn.delete()
|
conn.delete()
|
||||||
return HttpResponseRedirect(reverse('storages', args=[compute_id]))
|
return HttpResponseRedirect(reverse("storages", args=[compute_id]))
|
||||||
if 'set_autostart' in request.POST:
|
if "set_autostart" in request.POST:
|
||||||
conn.set_autostart(1)
|
conn.set_autostart(1)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'unset_autostart' in request.POST:
|
if "unset_autostart" in request.POST:
|
||||||
conn.set_autostart(0)
|
conn.set_autostart(0)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'del_volume' in request.POST:
|
if "del_volume" in request.POST:
|
||||||
volname = request.POST.get('volname', '')
|
volname = request.POST.get("volname", "")
|
||||||
vol = conn.get_volume(volname)
|
vol = conn.get_volume(volname)
|
||||||
vol.delete(0)
|
vol.delete(0)
|
||||||
messages.success(request, _(f"Volume: {volname} is deleted."))
|
messages.success(request, _("Volume: %(volume)s is deleted.") % {"vol": volname})
|
||||||
return redirect(reverse('storage', args=[compute.id, pool]))
|
return redirect(reverse("storage", args=[compute.id, pool]))
|
||||||
# return HttpResponseRedirect(request.get_full_path())
|
# return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'iso_upload' in request.POST:
|
if "iso_upload" in request.POST:
|
||||||
if str(request.FILES['file']) in conn.update_volumes():
|
if str(request.FILES["file"]) in conn.update_volumes():
|
||||||
error_msg = _("ISO image already exist")
|
error_msg = _("ISO image already exist")
|
||||||
messages.error(request, error_msg)
|
messages.error(request, error_msg)
|
||||||
else:
|
else:
|
||||||
handle_uploaded_file(path, request.FILES['file'])
|
handle_uploaded_file(path, request.FILES["file"])
|
||||||
messages.success(request, _(f"ISO: {request.FILES['file']} is uploaded."))
|
messages.success(request, _("ISO: %(file)s is uploaded.") % {"file": request.FILES["file"]})
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'cln_volume' in request.POST:
|
if "cln_volume" in request.POST:
|
||||||
form = CloneImage(request.POST)
|
form = CloneImage(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
img_name = data['name']
|
img_name = data["name"]
|
||||||
meta_prealloc = 0
|
meta_prealloc = 0
|
||||||
if img_name in conn.update_volumes():
|
if img_name in conn.update_volumes():
|
||||||
msg = _("Name of volume already in use")
|
msg = _("Name of volume already in use")
|
||||||
messages.error(request, msg)
|
messages.error(request, msg)
|
||||||
if data['convert']:
|
if data["convert"]:
|
||||||
format = data['format']
|
format = data["format"]
|
||||||
if data['meta_prealloc'] and data['format'] == 'qcow2':
|
if data["meta_prealloc"] and data["format"] == "qcow2":
|
||||||
meta_prealloc = True
|
meta_prealloc = True
|
||||||
else:
|
else:
|
||||||
format = None
|
format = None
|
||||||
try:
|
try:
|
||||||
name = conn.clone_volume(data['image'], data['name'], format, meta_prealloc)
|
name = conn.clone_volume(data["image"], data["name"], format, meta_prealloc)
|
||||||
messages.success(request, _(f"{data['image']} image cloned as {name} successfully"))
|
messages.success(
|
||||||
|
request,
|
||||||
|
_("%(image)s image cloned as %(clone)s successfully") % {"image": data["image"], "name": name},
|
||||||
|
)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
messages.error(request, lib_err)
|
messages.error(request, lib_err)
|
||||||
|
@ -167,11 +182,17 @@ def storage(request, compute_id, pool):
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return render(request, 'storage.html', locals())
|
return render(request, "storage.html", locals())
|
||||||
|
|
||||||
|
|
||||||
@superuser_only
|
@superuser_only
|
||||||
def create_volume(request, compute_id, pool):
|
def create_volume(request, compute_id, pool):
|
||||||
|
"""
|
||||||
|
:param request:
|
||||||
|
:param compute_id: compute id
|
||||||
|
:param pool: pool name
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
meta_prealloc = False
|
meta_prealloc = False
|
||||||
|
|
||||||
|
@ -182,26 +203,26 @@ def create_volume(request, compute_id, pool):
|
||||||
form = CreateVolumeForm(request.POST or None)
|
form = CreateVolumeForm(request.POST or None)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
if data['meta_prealloc'] and data['format'] == 'qcow2':
|
if data["meta_prealloc"] and data["format"] == "qcow2":
|
||||||
meta_prealloc = True
|
meta_prealloc = True
|
||||||
|
|
||||||
disk_owner_uid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
|
disk_owner_uid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
|
||||||
disk_owner_gid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID)
|
disk_owner_gid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID)
|
||||||
|
|
||||||
name = conn.create_volume(
|
name = conn.create_volume(
|
||||||
data['name'],
|
data["name"],
|
||||||
data['size'],
|
data["size"],
|
||||||
data['format'],
|
data["format"],
|
||||||
meta_prealloc,
|
meta_prealloc,
|
||||||
disk_owner_uid,
|
disk_owner_uid,
|
||||||
disk_owner_gid,
|
disk_owner_gid,
|
||||||
)
|
)
|
||||||
messages.success(request, _(f"Image file {name} is created successfully"))
|
messages.success(request, _("Image file %(name)s is created successfully") % {"name": name})
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
messages.error(request, msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
|
|
||||||
return redirect(reverse('storage', args=[compute.id, pool]))
|
return redirect(reverse("storage", args=[compute.id, pool]))
|
||||||
|
|
||||||
|
|
||||||
def get_volumes(request, compute_id, pool):
|
def get_volumes(request, compute_id, pool):
|
||||||
|
@ -216,7 +237,7 @@ def get_volumes(request, compute_id, pool):
|
||||||
try:
|
try:
|
||||||
conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
|
conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
|
||||||
conn.refresh()
|
conn.refresh()
|
||||||
data['vols'] = sorted(conn.get_volumes())
|
data["vols"] = sorted(conn.get_volumes())
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
pass
|
pass
|
||||||
return HttpResponse(json.dumps(data))
|
return HttpResponse(json.dumps(data))
|
||||||
|
|
|
@ -6,7 +6,7 @@ Further Information might be available at:
|
||||||
https://github.com/haypo/python-ipy
|
https://github.com/haypo/python-ipy
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '1.00'
|
__version__ = "1.00"
|
||||||
|
|
||||||
import bisect
|
import bisect
|
||||||
import collections
|
import collections
|
||||||
|
@ -17,16 +17,16 @@ import types
|
||||||
# this should include www.iana.org/assignments/ipv4-address-space
|
# this should include www.iana.org/assignments/ipv4-address-space
|
||||||
# and www.iana.org/assignments/multicast-addresses
|
# and www.iana.org/assignments/multicast-addresses
|
||||||
IPv4ranges = {
|
IPv4ranges = {
|
||||||
'0': 'PUBLIC', # fall back
|
"0": "PUBLIC", # fall back
|
||||||
'00000000': 'PRIVATE', # 0/8
|
"00000000": "PRIVATE", # 0/8
|
||||||
'00001010': 'PRIVATE', # 10/8
|
"00001010": "PRIVATE", # 10/8
|
||||||
'0110010001': 'CARRIER_GRADE_NAT', # 100.64/10
|
"0110010001": "CARRIER_GRADE_NAT", # 100.64/10
|
||||||
'01111111': 'LOOPBACK', # 127.0/8
|
"01111111": "LOOPBACK", # 127.0/8
|
||||||
'1': 'PUBLIC', # fall back
|
"1": "PUBLIC", # fall back
|
||||||
'1010100111111110': 'PRIVATE', # 169.254/16
|
"1010100111111110": "PRIVATE", # 169.254/16
|
||||||
'101011000001': 'PRIVATE', # 172.16/12
|
"101011000001": "PRIVATE", # 172.16/12
|
||||||
'1100000010101000': 'PRIVATE', # 192.168/16
|
"1100000010101000": "PRIVATE", # 192.168/16
|
||||||
'111': 'RESERVED', # 224/3
|
"111": "RESERVED", # 224/3
|
||||||
}
|
}
|
||||||
|
|
||||||
# Definition of the Ranges for IPv6 IPs
|
# Definition of the Ranges for IPv6 IPs
|
||||||
|
@ -34,92 +34,92 @@ IPv4ranges = {
|
||||||
# http://www.iana.org/assignments/ipv6-unicast-address-assignments/
|
# http://www.iana.org/assignments/ipv6-unicast-address-assignments/
|
||||||
# http://www.iana.org/assignments/ipv6-multicast-addresses/
|
# http://www.iana.org/assignments/ipv6-multicast-addresses/
|
||||||
IPv6ranges = {
|
IPv6ranges = {
|
||||||
'00000000': 'RESERVED', # ::/8
|
"00000000": "RESERVED", # ::/8
|
||||||
'0' * 96: 'RESERVED', # ::/96 Formerly IPV4COMP [RFC4291]
|
"0" * 96: "RESERVED", # ::/96 Formerly IPV4COMP [RFC4291]
|
||||||
'0' * 128: 'UNSPECIFIED', # ::/128
|
"0" * 128: "UNSPECIFIED", # ::/128
|
||||||
'0' * 127 + '1': 'LOOPBACK', # ::1/128
|
"0" * 127 + "1": "LOOPBACK", # ::1/128
|
||||||
'0' * 80 + '1' * 16: 'IPV4MAP', # ::ffff:0:0/96
|
"0" * 80 + "1" * 16: "IPV4MAP", # ::ffff:0:0/96
|
||||||
'00000000011001001111111110011011' + '0' * 64: 'WKP46TRANS', # 0064:ff9b::/96 Well-Known-Prefix [RFC6052]
|
"00000000011001001111111110011011" + "0" * 64: "WKP46TRANS", # 0064:ff9b::/96 Well-Known-Prefix [RFC6052]
|
||||||
'00000001': 'UNASSIGNED', # 0100::/8
|
"00000001": "UNASSIGNED", # 0100::/8
|
||||||
'0000001': 'RESERVED', # 0200::/7 Formerly NSAP [RFC4048]
|
"0000001": "RESERVED", # 0200::/7 Formerly NSAP [RFC4048]
|
||||||
'0000010': 'RESERVED', # 0400::/7 Formerly IPX [RFC3513]
|
"0000010": "RESERVED", # 0400::/7 Formerly IPX [RFC3513]
|
||||||
'0000011': 'RESERVED', # 0600::/7
|
"0000011": "RESERVED", # 0600::/7
|
||||||
'00001': 'RESERVED', # 0800::/5
|
"00001": "RESERVED", # 0800::/5
|
||||||
'0001': 'RESERVED', # 1000::/4
|
"0001": "RESERVED", # 1000::/4
|
||||||
'001': 'GLOBAL-UNICAST', # 2000::/3 [RFC4291]
|
"001": "GLOBAL-UNICAST", # 2000::/3 [RFC4291]
|
||||||
'00100000000000010000000': 'SPECIALPURPOSE', # 2001::/23 [RFC4773]
|
"00100000000000010000000": "SPECIALPURPOSE", # 2001::/23 [RFC4773]
|
||||||
'00100000000000010000000000000000': 'TEREDO', # 2001::/32 [RFC4380]
|
"00100000000000010000000000000000": "TEREDO", # 2001::/32 [RFC4380]
|
||||||
'00100000000000010000000000000010' + '0' * 16: 'BMWG', # 2001:0002::/48 Benchmarking [RFC5180]
|
"00100000000000010000000000000010" + "0" * 16: "BMWG", # 2001:0002::/48 Benchmarking [RFC5180]
|
||||||
'0010000000000001000000000001': 'ORCHID', # 2001:0010::/28 (Temp until 2014-03-21) [RFC4843]
|
"0010000000000001000000000001": "ORCHID", # 2001:0010::/28 (Temp until 2014-03-21) [RFC4843]
|
||||||
'00100000000000010000001': 'ALLOCATED APNIC', # 2001:0200::/23
|
"00100000000000010000001": "ALLOCATED APNIC", # 2001:0200::/23
|
||||||
'00100000000000010000010': 'ALLOCATED ARIN', # 2001:0400::/23
|
"00100000000000010000010": "ALLOCATED ARIN", # 2001:0400::/23
|
||||||
'00100000000000010000011': 'ALLOCATED RIPE NCC', # 2001:0600::/23
|
"00100000000000010000011": "ALLOCATED RIPE NCC", # 2001:0600::/23
|
||||||
'00100000000000010000100': 'ALLOCATED RIPE NCC', # 2001:0800::/23
|
"00100000000000010000100": "ALLOCATED RIPE NCC", # 2001:0800::/23
|
||||||
'00100000000000010000101': 'ALLOCATED RIPE NCC', # 2001:0a00::/23
|
"00100000000000010000101": "ALLOCATED RIPE NCC", # 2001:0a00::/23
|
||||||
'00100000000000010000110': 'ALLOCATED APNIC', # 2001:0c00::/23
|
"00100000000000010000110": "ALLOCATED APNIC", # 2001:0c00::/23
|
||||||
'00100000000000010000110110111000': 'DOCUMENTATION', # 2001:0db8::/32 [RFC3849]
|
"00100000000000010000110110111000": "DOCUMENTATION", # 2001:0db8::/32 [RFC3849]
|
||||||
'00100000000000010000111': 'ALLOCATED APNIC', # 2001:0e00::/23
|
"00100000000000010000111": "ALLOCATED APNIC", # 2001:0e00::/23
|
||||||
'00100000000000010001001': 'ALLOCATED LACNIC', # 2001:1200::/23
|
"00100000000000010001001": "ALLOCATED LACNIC", # 2001:1200::/23
|
||||||
'00100000000000010001010': 'ALLOCATED RIPE NCC', # 2001:1400::/23
|
"00100000000000010001010": "ALLOCATED RIPE NCC", # 2001:1400::/23
|
||||||
'00100000000000010001011': 'ALLOCATED RIPE NCC', # 2001:1600::/23
|
"00100000000000010001011": "ALLOCATED RIPE NCC", # 2001:1600::/23
|
||||||
'00100000000000010001100': 'ALLOCATED ARIN', # 2001:1800::/23
|
"00100000000000010001100": "ALLOCATED ARIN", # 2001:1800::/23
|
||||||
'00100000000000010001101': 'ALLOCATED RIPE NCC', # 2001:1a00::/23
|
"00100000000000010001101": "ALLOCATED RIPE NCC", # 2001:1a00::/23
|
||||||
'0010000000000001000111': 'ALLOCATED RIPE NCC', # 2001:1c00::/22
|
"0010000000000001000111": "ALLOCATED RIPE NCC", # 2001:1c00::/22
|
||||||
'00100000000000010010': 'ALLOCATED RIPE NCC', # 2001:2000::/20
|
"00100000000000010010": "ALLOCATED RIPE NCC", # 2001:2000::/20
|
||||||
'001000000000000100110': 'ALLOCATED RIPE NCC', # 2001:3000::/21
|
"001000000000000100110": "ALLOCATED RIPE NCC", # 2001:3000::/21
|
||||||
'0010000000000001001110': 'ALLOCATED RIPE NCC', # 2001:3800::/22
|
"0010000000000001001110": "ALLOCATED RIPE NCC", # 2001:3800::/22
|
||||||
'0010000000000001001111': 'RESERVED', # 2001:3c00::/22 Possible future allocation to RIPE NCC
|
"0010000000000001001111": "RESERVED", # 2001:3c00::/22 Possible future allocation to RIPE NCC
|
||||||
'00100000000000010100000': 'ALLOCATED RIPE NCC', # 2001:4000::/23
|
"00100000000000010100000": "ALLOCATED RIPE NCC", # 2001:4000::/23
|
||||||
'00100000000000010100001': 'ALLOCATED AFRINIC', # 2001:4200::/23
|
"00100000000000010100001": "ALLOCATED AFRINIC", # 2001:4200::/23
|
||||||
'00100000000000010100010': 'ALLOCATED APNIC', # 2001:4400::/23
|
"00100000000000010100010": "ALLOCATED APNIC", # 2001:4400::/23
|
||||||
'00100000000000010100011': 'ALLOCATED RIPE NCC', # 2001:4600::/23
|
"00100000000000010100011": "ALLOCATED RIPE NCC", # 2001:4600::/23
|
||||||
'00100000000000010100100': 'ALLOCATED ARIN', # 2001:4800::/23
|
"00100000000000010100100": "ALLOCATED ARIN", # 2001:4800::/23
|
||||||
'00100000000000010100101': 'ALLOCATED RIPE NCC', # 2001:4a00::/23
|
"00100000000000010100101": "ALLOCATED RIPE NCC", # 2001:4a00::/23
|
||||||
'00100000000000010100110': 'ALLOCATED RIPE NCC', # 2001:4c00::/23
|
"00100000000000010100110": "ALLOCATED RIPE NCC", # 2001:4c00::/23
|
||||||
'00100000000000010101': 'ALLOCATED RIPE NCC', # 2001:5000::/20
|
"00100000000000010101": "ALLOCATED RIPE NCC", # 2001:5000::/20
|
||||||
'0010000000000001100': 'ALLOCATED APNIC', # 2001:8000::/19
|
"0010000000000001100": "ALLOCATED APNIC", # 2001:8000::/19
|
||||||
'00100000000000011010': 'ALLOCATED APNIC', # 2001:a000::/20
|
"00100000000000011010": "ALLOCATED APNIC", # 2001:a000::/20
|
||||||
'00100000000000011011': 'ALLOCATED APNIC', # 2001:b000::/20
|
"00100000000000011011": "ALLOCATED APNIC", # 2001:b000::/20
|
||||||
'0010000000000010': '6TO4', # 2002::/16 "6to4" [RFC3056]
|
"0010000000000010": "6TO4", # 2002::/16 "6to4" [RFC3056]
|
||||||
'001000000000001100': 'ALLOCATED RIPE NCC', # 2003::/18
|
"001000000000001100": "ALLOCATED RIPE NCC", # 2003::/18
|
||||||
'001001000000': 'ALLOCATED APNIC', # 2400::/12
|
"001001000000": "ALLOCATED APNIC", # 2400::/12
|
||||||
'001001100000': 'ALLOCATED ARIN', # 2600::/12
|
"001001100000": "ALLOCATED ARIN", # 2600::/12
|
||||||
'00100110000100000000000': 'ALLOCATED ARIN', # 2610::/23
|
"00100110000100000000000": "ALLOCATED ARIN", # 2610::/23
|
||||||
'00100110001000000000000': 'ALLOCATED ARIN', # 2620::/23
|
"00100110001000000000000": "ALLOCATED ARIN", # 2620::/23
|
||||||
'001010000000': 'ALLOCATED LACNIC', # 2800::/12
|
"001010000000": "ALLOCATED LACNIC", # 2800::/12
|
||||||
'001010100000': 'ALLOCATED RIPE NCC', # 2a00::/12
|
"001010100000": "ALLOCATED RIPE NCC", # 2a00::/12
|
||||||
'001011000000': 'ALLOCATED AFRINIC', # 2c00::/12
|
"001011000000": "ALLOCATED AFRINIC", # 2c00::/12
|
||||||
'00101101': 'RESERVED', # 2d00::/8
|
"00101101": "RESERVED", # 2d00::/8
|
||||||
'0010111': 'RESERVED', # 2e00::/7
|
"0010111": "RESERVED", # 2e00::/7
|
||||||
'0011': 'RESERVED', # 3000::/4
|
"0011": "RESERVED", # 3000::/4
|
||||||
'010': 'RESERVED', # 4000::/3
|
"010": "RESERVED", # 4000::/3
|
||||||
'011': 'RESERVED', # 6000::/3
|
"011": "RESERVED", # 6000::/3
|
||||||
'100': 'RESERVED', # 8000::/3
|
"100": "RESERVED", # 8000::/3
|
||||||
'101': 'RESERVED', # a000::/3
|
"101": "RESERVED", # a000::/3
|
||||||
'110': 'RESERVED', # c000::/3
|
"110": "RESERVED", # c000::/3
|
||||||
'1110': 'RESERVED', # e000::/4
|
"1110": "RESERVED", # e000::/4
|
||||||
'11110': 'RESERVED', # f000::/5
|
"11110": "RESERVED", # f000::/5
|
||||||
'111110': 'RESERVED', # f800::/6
|
"111110": "RESERVED", # f800::/6
|
||||||
'1111110': 'ULA', # fc00::/7 [RFC4193]
|
"1111110": "ULA", # fc00::/7 [RFC4193]
|
||||||
'111111100': 'RESERVED', # fe00::/9
|
"111111100": "RESERVED", # fe00::/9
|
||||||
'1111111010': 'LINKLOCAL', # fe80::/10
|
"1111111010": "LINKLOCAL", # fe80::/10
|
||||||
'1111111011': 'RESERVED', # fec0::/10 Formerly SITELOCAL [RFC4291]
|
"1111111011": "RESERVED", # fec0::/10 Formerly SITELOCAL [RFC4291]
|
||||||
'11111111': 'MULTICAST', # ff00::/8
|
"11111111": "MULTICAST", # ff00::/8
|
||||||
'1111111100000001': 'NODE-LOCAL MULTICAST', # ff01::/16
|
"1111111100000001": "NODE-LOCAL MULTICAST", # ff01::/16
|
||||||
'1111111100000010': 'LINK-LOCAL MULTICAST', # ff02::/16
|
"1111111100000010": "LINK-LOCAL MULTICAST", # ff02::/16
|
||||||
'1111111100000100': 'ADMIN-LOCAL MULTICAST', # ff04::/16
|
"1111111100000100": "ADMIN-LOCAL MULTICAST", # ff04::/16
|
||||||
'1111111100000101': 'SITE-LOCAL MULTICAST', # ff05::/16
|
"1111111100000101": "SITE-LOCAL MULTICAST", # ff05::/16
|
||||||
'1111111100001000': 'ORG-LOCAL MULTICAST', # ff08::/16
|
"1111111100001000": "ORG-LOCAL MULTICAST", # ff08::/16
|
||||||
'1111111100001110': 'GLOBAL MULTICAST', # ff0e::/16
|
"1111111100001110": "GLOBAL MULTICAST", # ff0e::/16
|
||||||
'1111111100001111': 'RESERVED MULTICAST', # ff0f::/16
|
"1111111100001111": "RESERVED MULTICAST", # ff0f::/16
|
||||||
'111111110011': 'PREFIX-BASED MULTICAST', # ff30::/12 [RFC3306]
|
"111111110011": "PREFIX-BASED MULTICAST", # ff30::/12 [RFC3306]
|
||||||
'111111110111': 'RP-EMBEDDED MULTICAST', # ff70::/12 [RFC3956]
|
"111111110111": "RP-EMBEDDED MULTICAST", # ff70::/12 [RFC3956]
|
||||||
}
|
}
|
||||||
|
|
||||||
MAX_IPV4_ADDRESS = 0xffffffff
|
MAX_IPV4_ADDRESS = 0xFFFFFFFF
|
||||||
MAX_IPV6_ADDRESS = 0xffffffffffffffffffffffffffffffff
|
MAX_IPV6_ADDRESS = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
IPV6_TEST_MAP = 0xffffffffffffffffffffffff00000000
|
IPV6_TEST_MAP = 0xFFFFFFFFFFFFFFFFFFFFFFFF00000000
|
||||||
IPV6_MAP_MASK = 0x00000000000000000000ffff00000000
|
IPV6_MAP_MASK = 0x00000000000000000000FFFF00000000
|
||||||
|
|
||||||
if sys.version_info >= (3,):
|
if sys.version_info >= (3,):
|
||||||
INT_TYPES = (int,)
|
INT_TYPES = (int,)
|
||||||
|
@ -202,7 +202,7 @@ class IPint(object):
|
||||||
elif isinstance(data, STR_TYPES):
|
elif isinstance(data, STR_TYPES):
|
||||||
# TODO: refactor me!
|
# TODO: refactor me!
|
||||||
# splitting of a string into IP and prefixlen et. al.
|
# splitting of a string into IP and prefixlen et. al.
|
||||||
x = data.split('-')
|
x = data.split("-")
|
||||||
if len(x) == 2:
|
if len(x) == 2:
|
||||||
# a.b.c.0-a.b.c.255 specification ?
|
# a.b.c.0-a.b.c.255 specification ?
|
||||||
(ip, last) = x
|
(ip, last) = x
|
||||||
|
@ -219,10 +219,10 @@ class IPint(object):
|
||||||
# make sure the broadcast is the same as the last ip
|
# make sure the broadcast is the same as the last ip
|
||||||
# otherwise it will return /16 for something like:
|
# otherwise it will return /16 for something like:
|
||||||
# 192.168.0.0-192.168.191.255
|
# 192.168.0.0-192.168.191.255
|
||||||
if IP('%s/%s' % (ip, 32 - netbits)).broadcast().int() != last:
|
if IP("%s/%s" % (ip, 32 - netbits)).broadcast().int() != last:
|
||||||
raise ValueError("the range %s is not on a network boundary." % data)
|
raise ValueError("the range %s is not on a network boundary." % data)
|
||||||
elif len(x) == 1:
|
elif len(x) == 1:
|
||||||
x = data.split('/')
|
x = data.split("/")
|
||||||
# if no prefix is given use defaults
|
# if no prefix is given use defaults
|
||||||
if len(x) == 1:
|
if len(x) == 1:
|
||||||
ip = x[0]
|
ip = x[0]
|
||||||
|
@ -231,7 +231,7 @@ class IPint(object):
|
||||||
raise ValueError("only one '/' allowed in IP Address")
|
raise ValueError("only one '/' allowed in IP Address")
|
||||||
else:
|
else:
|
||||||
(ip, prefixlen) = x
|
(ip, prefixlen) = x
|
||||||
if prefixlen.find('.') != -1:
|
if prefixlen.find(".") != -1:
|
||||||
# check if the user might have used a netmask like
|
# check if the user might have used a netmask like
|
||||||
# a.b.c.d/255.255.255.0
|
# a.b.c.d/255.255.255.0
|
||||||
(netmask, vers) = parseAddress(prefixlen)
|
(netmask, vers) = parseAddress(prefixlen)
|
||||||
|
@ -255,8 +255,7 @@ class IPint(object):
|
||||||
if make_net:
|
if make_net:
|
||||||
self.ip = self.ip & _prefixlenToNetmask(self._prefixlen, self._ipversion)
|
self.ip = self.ip & _prefixlenToNetmask(self._prefixlen, self._ipversion)
|
||||||
|
|
||||||
if not _checkNetaddrWorksWithPrefixlen(self.ip,
|
if not _checkNetaddrWorksWithPrefixlen(self.ip, self._prefixlen, self._ipversion):
|
||||||
self._prefixlen, self._ipversion):
|
|
||||||
raise ValueError("%s has invalid prefix length (%s)" % (repr(self), self._prefixlen))
|
raise ValueError("%s has invalid prefix length (%s)" % (repr(self), self._prefixlen))
|
||||||
else:
|
else:
|
||||||
raise TypeError("Unsupported data type: %s" % type(data))
|
raise TypeError("Unsupported data type: %s" % type(data))
|
||||||
|
@ -314,8 +313,7 @@ class IPint(object):
|
||||||
want == 3 -lastip 1.2.3.0-1.2.3.255
|
want == 3 -lastip 1.2.3.0-1.2.3.255
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if (self._ipversion == 4 and self._prefixlen == 32) or \
|
if (self._ipversion == 4 and self._prefixlen == 32) or (self._ipversion == 6 and self._prefixlen == 128):
|
||||||
(self._ipversion == 6 and self._prefixlen == 128):
|
|
||||||
if self.NoPrefixForSingleIp:
|
if self.NoPrefixForSingleIp:
|
||||||
want = 0
|
want = 0
|
||||||
if want is None:
|
if want is None:
|
||||||
|
@ -335,7 +333,7 @@ class IPint(object):
|
||||||
# default
|
# default
|
||||||
return "/%d" % (self._prefixlen)
|
return "/%d" % (self._prefixlen)
|
||||||
else:
|
else:
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
# We have different flavours to convert to:
|
# We have different flavours to convert to:
|
||||||
# strFullsize 127.0.0.1 2001:0658:022a:cafe:0200:c0ff:fe8d:08fa
|
# strFullsize 127.0.0.1 2001:0658:022a:cafe:0200:c0ff:fe8d:08fa
|
||||||
|
@ -357,7 +355,7 @@ class IPint(object):
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen is None and wantprefixlen is None:
|
||||||
wantprefixlen = 0
|
wantprefixlen = 0
|
||||||
ret = _intToBin(self.ip)
|
ret = _intToBin(self.ip)
|
||||||
return '0' * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen)
|
return "0" * (bits - len(ret)) + ret + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
def strCompressed(self, wantprefixlen=None):
|
def strCompressed(self, wantprefixlen=None):
|
||||||
"""Return a string representation in compressed format using '::' Notation.
|
"""Return a string representation in compressed format using '::' Notation.
|
||||||
|
@ -376,12 +374,12 @@ class IPint(object):
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
return self.strFullsize(wantprefixlen)
|
return self.strFullsize(wantprefixlen)
|
||||||
else:
|
else:
|
||||||
if self.ip >> 32 == 0xffff:
|
if self.ip >> 32 == 0xFFFF:
|
||||||
ipv4 = intToIp(self.ip & MAX_IPV4_ADDRESS, 4)
|
ipv4 = intToIp(self.ip & MAX_IPV4_ADDRESS, 4)
|
||||||
text = "::ffff:" + ipv4 + self._printPrefix(wantprefixlen)
|
text = "::ffff:" + ipv4 + self._printPrefix(wantprefixlen)
|
||||||
return text
|
return text
|
||||||
# find the longest sequence of '0'
|
# find the longest sequence of '0'
|
||||||
hextets = [int(x, 16) for x in self.strFullsize(0).split(':')]
|
hextets = [int(x, 16) for x in self.strFullsize(0).split(":")]
|
||||||
# every element of followingzeros will contain the number of zeros
|
# every element of followingzeros will contain the number of zeros
|
||||||
# following the corresponding element of hextets
|
# following the corresponding element of hextets
|
||||||
followingzeros = [0] * 8
|
followingzeros = [0] * 8
|
||||||
|
@ -392,15 +390,15 @@ class IPint(object):
|
||||||
if max(followingzeros) > 1:
|
if max(followingzeros) > 1:
|
||||||
# genererate string with the longest number of zeros cut out
|
# genererate string with the longest number of zeros cut out
|
||||||
# now we need hextets as strings
|
# now we need hextets as strings
|
||||||
hextets = [x for x in self.strNormal(0).split(':')]
|
hextets = [x for x in self.strNormal(0).split(":")]
|
||||||
while compressionpos < len(hextets) and hextets[compressionpos] == '0':
|
while compressionpos < len(hextets) and hextets[compressionpos] == "0":
|
||||||
del (hextets[compressionpos])
|
del hextets[compressionpos]
|
||||||
hextets.insert(compressionpos, '')
|
hextets.insert(compressionpos, "")
|
||||||
if compressionpos + 1 >= len(hextets):
|
if compressionpos + 1 >= len(hextets):
|
||||||
hextets.append('')
|
hextets.append("")
|
||||||
if compressionpos == 0:
|
if compressionpos == 0:
|
||||||
hextets = [''] + hextets
|
hextets = [""] + hextets
|
||||||
return ':'.join(hextets) + self._printPrefix(wantprefixlen)
|
return ":".join(hextets) + self._printPrefix(wantprefixlen)
|
||||||
else:
|
else:
|
||||||
return self.strNormal(0) + self._printPrefix(wantprefixlen)
|
return self.strNormal(0) + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
|
@ -419,7 +417,7 @@ class IPint(object):
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
ret = self.strFullsize(0)
|
ret = self.strFullsize(0)
|
||||||
elif self._ipversion == 6:
|
elif self._ipversion == 6:
|
||||||
ret = ':'.join(["%x" % x for x in [int(x, 16) for x in self.strFullsize(0).split(':')]])
|
ret = ":".join(["%x" % x for x in [int(x, 16) for x in self.strFullsize(0).split(":")]])
|
||||||
else:
|
else:
|
||||||
raise ValueError("only IPv4 and IPv6 supported")
|
raise ValueError("only IPv4 and IPv6 supported")
|
||||||
|
|
||||||
|
@ -451,7 +449,7 @@ class IPint(object):
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen is None and wantprefixlen is None:
|
||||||
wantprefixlen = 0
|
wantprefixlen = 0
|
||||||
|
|
||||||
x = '0x%x' % self.ip
|
x = "0x%x" % self.ip
|
||||||
return x + self._printPrefix(wantprefixlen)
|
return x + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
def strDec(self, wantprefixlen=None):
|
def strDec(self, wantprefixlen=None):
|
||||||
|
@ -466,7 +464,7 @@ class IPint(object):
|
||||||
if self.WantPrefixLen is None and wantprefixlen is None:
|
if self.WantPrefixLen is None and wantprefixlen is None:
|
||||||
wantprefixlen = 0
|
wantprefixlen = 0
|
||||||
|
|
||||||
x = '%d' % self.ip
|
x = "%d" % self.ip
|
||||||
return x + self._printPrefix(wantprefixlen)
|
return x + self._printPrefix(wantprefixlen)
|
||||||
|
|
||||||
def iptype(self):
|
def iptype(self):
|
||||||
|
@ -581,10 +579,8 @@ class IPint(object):
|
||||||
raise ValueError("Only adjacent networks can be added together.")
|
raise ValueError("Only adjacent networks can be added together.")
|
||||||
ret = IP(self.int(), ipversion=self._ipversion)
|
ret = IP(self.int(), ipversion=self._ipversion)
|
||||||
ret._prefixlen = self.prefixlen() - 1
|
ret._prefixlen = self.prefixlen() - 1
|
||||||
if not _checkNetaddrWorksWithPrefixlen(ret.ip, ret._prefixlen,
|
if not _checkNetaddrWorksWithPrefixlen(ret.ip, ret._prefixlen, ret._ipversion):
|
||||||
ret._ipversion):
|
raise ValueError("The resulting %s has invalid prefix length (%s)" % (repr(ret), ret._prefixlen))
|
||||||
raise ValueError("The resulting %s has invalid prefix length (%s)"
|
|
||||||
% (repr(ret), ret._prefixlen))
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def __sub__(self, other):
|
def __sub__(self, other):
|
||||||
|
@ -692,7 +688,7 @@ class IPint(object):
|
||||||
IP('10.0.0.0/24')
|
IP('10.0.0.0/24')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return ("IPint('%s')" % (self.strCompressed(1)))
|
return "IPint('%s')" % (self.strCompressed(1))
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
"""Called by comparison operations.
|
"""Called by comparison operations.
|
||||||
|
@ -777,7 +773,7 @@ class IPint(object):
|
||||||
thehash = int(-1)
|
thehash = int(-1)
|
||||||
ip = self.ip
|
ip = self.ip
|
||||||
while ip > 0:
|
while ip > 0:
|
||||||
thehash = thehash ^ (ip & 0x7fffffff)
|
thehash = thehash ^ (ip & 0x7FFFFFFF)
|
||||||
ip = ip >> 32
|
ip = ip >> 32
|
||||||
thehash = thehash ^ self._prefixlen
|
thehash = thehash ^ self._prefixlen
|
||||||
return int(thehash)
|
return int(thehash)
|
||||||
|
@ -811,17 +807,17 @@ class IP(IPint):
|
||||||
|
|
||||||
>>> IP('10.0.0.0/8').netmask()
|
>>> IP('10.0.0.0/8').netmask()
|
||||||
IP('255.0.0.0')
|
IP('255.0.0.0')
|
||||||
"""
|
"""
|
||||||
return IP(IPint.netmask(self), ipversion=self._ipversion)
|
return IP(IPint.netmask(self), ipversion=self._ipversion)
|
||||||
|
|
||||||
def _getIPv4Map(self):
|
def _getIPv4Map(self):
|
||||||
if self._ipversion != 6:
|
if self._ipversion != 6:
|
||||||
return None
|
return None
|
||||||
if (self.ip >> 32) != 0xffff:
|
if (self.ip >> 32) != 0xFFFF:
|
||||||
return None
|
return None
|
||||||
ipv4 = self.ip & MAX_IPV4_ADDRESS
|
ipv4 = self.ip & MAX_IPV4_ADDRESS
|
||||||
if self._prefixlen != 128:
|
if self._prefixlen != 128:
|
||||||
ipv4 = '%s/%s' % (ipv4, 32 - (128 - self._prefixlen))
|
ipv4 = "%s/%s" % (ipv4, 32 - (128 - self._prefixlen))
|
||||||
return IP(ipv4, ipversion=4)
|
return IP(ipv4, ipversion=4)
|
||||||
|
|
||||||
def reverseNames(self):
|
def reverseNames(self):
|
||||||
|
@ -872,7 +868,7 @@ class IP(IPint):
|
||||||
raise NotImplementedError("can't create IPv6 reverse names at sub nibble level")
|
raise NotImplementedError("can't create IPv6 reverse names at sub nibble level")
|
||||||
s = list(s)
|
s = list(s)
|
||||||
s.reverse()
|
s.reverse()
|
||||||
s = '.'.join(s)
|
s = ".".join(s)
|
||||||
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
||||||
return ["%s.ip6.arpa." % s[first_nibble_index:]]
|
return ["%s.ip6.arpa." % s[first_nibble_index:]]
|
||||||
else:
|
else:
|
||||||
|
@ -897,32 +893,34 @@ class IP(IPint):
|
||||||
|
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
s = self.strFullsize(0)
|
s = self.strFullsize(0)
|
||||||
s = s.split('.')
|
s = s.split(".")
|
||||||
s.reverse()
|
s.reverse()
|
||||||
first_byte_index = int(4 - (self._prefixlen // 8))
|
first_byte_index = int(4 - (self._prefixlen // 8))
|
||||||
if self._prefixlen % 8 != 0:
|
if self._prefixlen % 8 != 0:
|
||||||
nibblepart = "%s-%s" % (
|
nibblepart = "%s-%s" % (
|
||||||
s[3 - (self._prefixlen // 8)], intToIp(self.ip + self.len() - 1, 4).split('.')[-1])
|
s[3 - (self._prefixlen // 8)],
|
||||||
nibblepart += '.'
|
intToIp(self.ip + self.len() - 1, 4).split(".")[-1],
|
||||||
|
)
|
||||||
|
nibblepart += "."
|
||||||
else:
|
else:
|
||||||
nibblepart = ""
|
nibblepart = ""
|
||||||
|
|
||||||
s = '.'.join(s[first_byte_index:])
|
s = ".".join(s[first_byte_index:])
|
||||||
return "%s%s.in-addr.arpa." % (nibblepart, s)
|
return "%s%s.in-addr.arpa." % (nibblepart, s)
|
||||||
|
|
||||||
elif self._ipversion == 6:
|
elif self._ipversion == 6:
|
||||||
ipv4 = self._getIPv4Map()
|
ipv4 = self._getIPv4Map()
|
||||||
if ipv4 is not None:
|
if ipv4 is not None:
|
||||||
return ipv4.reverseName()
|
return ipv4.reverseName()
|
||||||
s = '%032x' % self.ip
|
s = "%032x" % self.ip
|
||||||
if self._prefixlen % 4 != 0:
|
if self._prefixlen % 4 != 0:
|
||||||
nibblepart = "%s-%x" % (s[self._prefixlen:], self.ip + self.len() - 1)
|
nibblepart = "%s-%x" % (s[self._prefixlen :], self.ip + self.len() - 1)
|
||||||
nibblepart += '.'
|
nibblepart += "."
|
||||||
else:
|
else:
|
||||||
nibblepart = ""
|
nibblepart = ""
|
||||||
s = list(s)
|
s = list(s)
|
||||||
s.reverse()
|
s.reverse()
|
||||||
s = '.'.join(s)
|
s = ".".join(s)
|
||||||
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
first_nibble_index = int(32 - (self._prefixlen // 4)) * 2
|
||||||
return "%s%s.ip6.arpa." % (nibblepart, s[first_nibble_index:])
|
return "%s%s.ip6.arpa." % (nibblepart, s[first_nibble_index:])
|
||||||
else:
|
else:
|
||||||
|
@ -937,9 +935,9 @@ class IP(IPint):
|
||||||
>>> print(IP('127.0.0.1').make_net('255.0.0.0'))
|
>>> print(IP('127.0.0.1').make_net('255.0.0.0'))
|
||||||
127.0.0.0/8
|
127.0.0.0/8
|
||||||
"""
|
"""
|
||||||
if '/' in str(netmask):
|
if "/" in str(netmask):
|
||||||
raise ValueError("invalid netmask (%s)" % netmask)
|
raise ValueError("invalid netmask (%s)" % netmask)
|
||||||
return IP('%s/%s' % (self, netmask), make_net=True)
|
return IP("%s/%s" % (self, netmask), make_net=True)
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
"""Called to implement evaluation of self[key].
|
"""Called to implement evaluation of self[key].
|
||||||
|
@ -968,7 +966,7 @@ class IP(IPint):
|
||||||
IP('10.0.0.0/8')
|
IP('10.0.0.0/8')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return ("IP('%s')" % (self.strCompressed(1)))
|
return "IP('%s')" % (self.strCompressed(1))
|
||||||
|
|
||||||
def get_mac(self):
|
def get_mac(self):
|
||||||
"""
|
"""
|
||||||
|
@ -980,15 +978,15 @@ class IP(IPint):
|
||||||
"""
|
"""
|
||||||
if self._ipversion != 6:
|
if self._ipversion != 6:
|
||||||
return None
|
return None
|
||||||
if (self.ip & 0x20000ffff000000) != 0x20000fffe000000:
|
if (self.ip & 0x20000FFFF000000) != 0x20000FFFE000000:
|
||||||
return None
|
return None
|
||||||
return '%02x:%02x:%02x:%02x:%02x:%02x' % (
|
return "%02x:%02x:%02x:%02x:%02x:%02x" % (
|
||||||
(((self.ip >> 56) & 0xff) & 0xfd),
|
(((self.ip >> 56) & 0xFF) & 0xFD),
|
||||||
(self.ip >> 48) & 0xff,
|
(self.ip >> 48) & 0xFF,
|
||||||
(self.ip >> 40) & 0xff,
|
(self.ip >> 40) & 0xFF,
|
||||||
(self.ip >> 16) & 0xff,
|
(self.ip >> 16) & 0xFF,
|
||||||
(self.ip >> 8) & 0xff,
|
(self.ip >> 8) & 0xFF,
|
||||||
self.ip & 0xff,
|
self.ip & 0xFF,
|
||||||
)
|
)
|
||||||
|
|
||||||
def v46map(self):
|
def v46map(self):
|
||||||
|
@ -1003,14 +1001,11 @@ class IP(IPint):
|
||||||
IP('192.168.1.1')
|
IP('192.168.1.1')
|
||||||
"""
|
"""
|
||||||
if self._ipversion == 4:
|
if self._ipversion == 4:
|
||||||
return IP(str(IPV6_MAP_MASK + self.ip) +
|
return IP(str(IPV6_MAP_MASK + self.ip) + "/%s" % (self._prefixlen + 96))
|
||||||
"/%s" % (self._prefixlen + 96))
|
|
||||||
else:
|
else:
|
||||||
if self.ip & IPV6_TEST_MAP == IPV6_MAP_MASK:
|
if self.ip & IPV6_TEST_MAP == IPV6_MAP_MASK:
|
||||||
return IP(str(self.ip - IPV6_MAP_MASK) +
|
return IP(str(self.ip - IPV6_MAP_MASK) + "/%s" % (self._prefixlen - 96))
|
||||||
"/%s" % (self._prefixlen - 96))
|
raise ValueError("%s cannot be converted to an IPv4 address." % repr(self))
|
||||||
raise ValueError("%s cannot be converted to an IPv4 address."
|
|
||||||
% repr(self))
|
|
||||||
|
|
||||||
|
|
||||||
class IPSet(collections.MutableSet):
|
class IPSet(collections.MutableSet):
|
||||||
|
@ -1022,7 +1017,7 @@ class IPSet(collections.MutableSet):
|
||||||
# Make sure we only accept IP objects
|
# Make sure we only accept IP objects
|
||||||
for prefix in iterable:
|
for prefix in iterable:
|
||||||
if not isinstance(prefix, IP):
|
if not isinstance(prefix, IP):
|
||||||
raise ValueError('Only IP objects can be added to an IPSet')
|
raise ValueError("Only IP objects can be added to an IPSet")
|
||||||
|
|
||||||
# Store and optimize
|
# Store and optimize
|
||||||
self.prefixes = iterable[:]
|
self.prefixes = iterable[:]
|
||||||
|
@ -1083,7 +1078,7 @@ class IPSet(collections.MutableSet):
|
||||||
return IPSet(result)
|
return IPSet(result)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s([' % self.__class__.__name__ + ', '.join(map(repr, self.prefixes)) + '])'
|
return "%s([" % self.__class__.__name__ + ", ".join(map(repr, self.prefixes)) + "])"
|
||||||
|
|
||||||
def len(self):
|
def len(self):
|
||||||
return sum(prefix.len() for prefix in self.prefixes)
|
return sum(prefix.len() for prefix in self.prefixes)
|
||||||
|
@ -1096,7 +1091,7 @@ class IPSet(collections.MutableSet):
|
||||||
# Check type
|
# Check type
|
||||||
for prefix in value:
|
for prefix in value:
|
||||||
if not isinstance(prefix, IP):
|
if not isinstance(prefix, IP):
|
||||||
raise ValueError('Only IP objects can be added to an IPSet')
|
raise ValueError("Only IP objects can be added to an IPSet")
|
||||||
|
|
||||||
# Append and optimize
|
# Append and optimize
|
||||||
self.prefixes.extend(value)
|
self.prefixes.extend(value)
|
||||||
|
@ -1114,7 +1109,7 @@ class IPSet(collections.MutableSet):
|
||||||
# Remove
|
# Remove
|
||||||
for del_prefix in value:
|
for del_prefix in value:
|
||||||
if not isinstance(del_prefix, IP):
|
if not isinstance(del_prefix, IP):
|
||||||
raise ValueError('Only IP objects can be removed from an IPSet')
|
raise ValueError("Only IP objects can be removed from an IPSet")
|
||||||
|
|
||||||
# First check if this prefix contains anything in our list
|
# First check if this prefix contains anything in our list
|
||||||
found = False
|
found = False
|
||||||
|
@ -1134,7 +1129,7 @@ class IPSet(collections.MutableSet):
|
||||||
found = False
|
found = False
|
||||||
for i in range(len(self.prefixes)):
|
for i in range(len(self.prefixes)):
|
||||||
if del_prefix in self.prefixes[i]:
|
if del_prefix in self.prefixes[i]:
|
||||||
self.prefixes[i:i + 1] = self.prefixes[i] - del_prefix
|
self.prefixes[i : i + 1] = self.prefixes[i] - del_prefix
|
||||||
break
|
break
|
||||||
|
|
||||||
self.optimize()
|
self.optimize()
|
||||||
|
@ -1279,13 +1274,13 @@ def _parseAddressIPv6(ipstr):
|
||||||
fill_pos = len(items)
|
fill_pos = len(items)
|
||||||
index += 2
|
index += 2
|
||||||
continue
|
continue
|
||||||
pos = text.find(':')
|
pos = text.find(":")
|
||||||
if pos == 0:
|
if pos == 0:
|
||||||
# Invalid IPv6, eg. '1::2:'
|
# Invalid IPv6, eg. '1::2:'
|
||||||
raise ValueError("%r: Invalid IPv6 address" % ipstr)
|
raise ValueError("%r: Invalid IPv6 address" % ipstr)
|
||||||
if pos != -1:
|
if pos != -1:
|
||||||
items.append(text[:pos])
|
items.append(text[:pos])
|
||||||
if text[pos:pos + 2] == "::":
|
if text[pos : pos + 2] == "::":
|
||||||
index += pos
|
index += pos
|
||||||
else:
|
else:
|
||||||
index += pos + 1
|
index += pos + 1
|
||||||
|
@ -1297,13 +1292,13 @@ def _parseAddressIPv6(ipstr):
|
||||||
items.append(text)
|
items.append(text)
|
||||||
break
|
break
|
||||||
|
|
||||||
if items and '.' in items[-1]:
|
if items and "." in items[-1]:
|
||||||
# IPv6 ending with IPv4 like '::ffff:192.168.0.1'
|
# IPv6 ending with IPv4 like '::ffff:192.168.0.1'
|
||||||
if (fill_pos is not None) and not (fill_pos <= len(items) - 1):
|
if (fill_pos is not None) and not (fill_pos <= len(items) - 1):
|
||||||
# Invalid IPv6: 'ffff:192.168.0.1::'
|
# Invalid IPv6: 'ffff:192.168.0.1::'
|
||||||
raise ValueError("%r: Invalid IPv6 address: '::' after IPv4" % ipstr)
|
raise ValueError("%r: Invalid IPv6 address: '::' after IPv4" % ipstr)
|
||||||
value = parseAddress(items[-1])[0]
|
value = parseAddress(items[-1])[0]
|
||||||
items = items[:-1] + ["%04x" % (value >> 16), "%04x" % (value & 0xffff)]
|
items = items[:-1] + ["%04x" % (value >> 16), "%04x" % (value & 0xFFFF)]
|
||||||
|
|
||||||
# Expand fill_pos to fill with '0'
|
# Expand fill_pos to fill with '0'
|
||||||
# ['1','2'] with fill_pos=1 => ['1', '0', '0', '0', '0', '0', '0', '2']
|
# ['1','2'] with fill_pos=1 => ['1', '0', '0', '0', '0', '0', '0', '2']
|
||||||
|
@ -1311,7 +1306,7 @@ def _parseAddressIPv6(ipstr):
|
||||||
diff = 8 - len(items)
|
diff = 8 - len(items)
|
||||||
if diff <= 0:
|
if diff <= 0:
|
||||||
raise ValueError("%r: Invalid IPv6 address: '::' is not needed" % ipstr)
|
raise ValueError("%r: Invalid IPv6 address: '::' is not needed" % ipstr)
|
||||||
items = items[:fill_pos] + ['0'] * diff + items[fill_pos:]
|
items = items[:fill_pos] + ["0"] * diff + items[fill_pos:]
|
||||||
|
|
||||||
# Here we have a list of 8 strings
|
# Here we have a list of 8 strings
|
||||||
if len(items) != 8:
|
if len(items) != 8:
|
||||||
|
@ -1324,7 +1319,7 @@ def _parseAddressIPv6(ipstr):
|
||||||
for item in items:
|
for item in items:
|
||||||
try:
|
try:
|
||||||
item = int(item, 16)
|
item = int(item, 16)
|
||||||
error = not (0 <= item <= 0xffff)
|
error = not (0 <= item <= 0xFFFF)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
error = True
|
error = True
|
||||||
if error:
|
if error:
|
||||||
|
@ -1388,7 +1383,7 @@ def parseAddress(ipstr, ipversion=0):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
intval = None
|
intval = None
|
||||||
|
|
||||||
if ipstr.startswith('0x') and hexval is not None:
|
if ipstr.startswith("0x") and hexval is not None:
|
||||||
if hexval > MAX_IPV6_ADDRESS:
|
if hexval > MAX_IPV6_ADDRESS:
|
||||||
raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, hexval))
|
raise ValueError("IP Address can't be larger than %x: %x" % (MAX_IPV6_ADDRESS, hexval))
|
||||||
if hexval <= MAX_IPV4_ADDRESS:
|
if hexval <= MAX_IPV4_ADDRESS:
|
||||||
|
@ -1396,19 +1391,19 @@ def parseAddress(ipstr, ipversion=0):
|
||||||
else:
|
else:
|
||||||
return (hexval, 6)
|
return (hexval, 6)
|
||||||
|
|
||||||
if ipstr.find(':') != -1:
|
if ipstr.find(":") != -1:
|
||||||
return (_parseAddressIPv6(ipstr), 6)
|
return (_parseAddressIPv6(ipstr), 6)
|
||||||
|
|
||||||
elif len(ipstr) == 32 and hexval is not None:
|
elif len(ipstr) == 32 and hexval is not None:
|
||||||
# assume IPv6 in pure hexadecimal notation
|
# assume IPv6 in pure hexadecimal notation
|
||||||
return (hexval, 6)
|
return (hexval, 6)
|
||||||
|
|
||||||
elif ipstr.find('.') != -1 or (intval is not None and intval < 256 and ipversion != 6):
|
elif ipstr.find(".") != -1 or (intval is not None and intval < 256 and ipversion != 6):
|
||||||
# assume IPv4 ('127' gets interpreted as '127.0.0.0')
|
# assume IPv4 ('127' gets interpreted as '127.0.0.0')
|
||||||
bytes = ipstr.split('.')
|
bytes = ipstr.split(".")
|
||||||
if len(bytes) > 4:
|
if len(bytes) > 4:
|
||||||
raise ValueError("IPv4 Address with more than 4 bytes")
|
raise ValueError("IPv4 Address with more than 4 bytes")
|
||||||
bytes += ['0'] * (4 - len(bytes))
|
bytes += ["0"] * (4 - len(bytes))
|
||||||
bytes = [int(x) for x in bytes]
|
bytes = [int(x) for x in bytes]
|
||||||
for x in bytes:
|
for x in bytes:
|
||||||
if x > 255 or x < 0:
|
if x > 255 or x < 0:
|
||||||
|
@ -1438,12 +1433,12 @@ def intToIp(ip, version):
|
||||||
if ip < 0:
|
if ip < 0:
|
||||||
raise ValueError("IPs can't be negative: %d" % (ip))
|
raise ValueError("IPs can't be negative: %d" % (ip))
|
||||||
|
|
||||||
ret = ''
|
ret = ""
|
||||||
if version == 4:
|
if version == 4:
|
||||||
if ip > MAX_IPV4_ADDRESS:
|
if ip > MAX_IPV4_ADDRESS:
|
||||||
raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, ip))
|
raise ValueError("IPv4 Address can't be larger than %x: %x" % (MAX_IPV4_ADDRESS, ip))
|
||||||
for l in xrange(4):
|
for l in xrange(4):
|
||||||
ret = str(ip & 0xff) + '.' + ret
|
ret = str(ip & 0xFF) + "." + ret
|
||||||
ip = ip >> 8
|
ip = ip >> 8
|
||||||
ret = ret[:-1]
|
ret = ret[:-1]
|
||||||
elif version == 6:
|
elif version == 6:
|
||||||
|
@ -1453,7 +1448,7 @@ def intToIp(ip, version):
|
||||||
for x in xrange(1, 33):
|
for x in xrange(1, 33):
|
||||||
ret = l[-x] + ret
|
ret = l[-x] + ret
|
||||||
if x % 4 == 0:
|
if x % 4 == 0:
|
||||||
ret = ':' + ret
|
ret = ":" + ret
|
||||||
ret = ret[1:]
|
ret = ret[1:]
|
||||||
else:
|
else:
|
||||||
raise ValueError("only IPv4 and IPv6 supported")
|
raise ValueError("only IPv4 and IPv6 supported")
|
||||||
|
@ -1494,10 +1489,24 @@ def _countFollowingZeros(l):
|
||||||
return 1 + _countFollowingZeros(l[1:])
|
return 1 + _countFollowingZeros(l[1:])
|
||||||
|
|
||||||
|
|
||||||
_BitTable = {'0': '0000', '1': '0001', '2': '0010', '3': '0011',
|
_BitTable = {
|
||||||
'4': '0100', '5': '0101', '6': '0110', '7': '0111',
|
"0": "0000",
|
||||||
'8': '1000', '9': '1001', 'a': '1010', 'b': '1011',
|
"1": "0001",
|
||||||
'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'}
|
"2": "0010",
|
||||||
|
"3": "0011",
|
||||||
|
"4": "0100",
|
||||||
|
"5": "0101",
|
||||||
|
"6": "0110",
|
||||||
|
"7": "0111",
|
||||||
|
"8": "1000",
|
||||||
|
"9": "1001",
|
||||||
|
"a": "1010",
|
||||||
|
"b": "1011",
|
||||||
|
"c": "1100",
|
||||||
|
"d": "1101",
|
||||||
|
"e": "1110",
|
||||||
|
"f": "1111",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _intToBin(val):
|
def _intToBin(val):
|
||||||
|
@ -1506,11 +1515,11 @@ def _intToBin(val):
|
||||||
if val < 0:
|
if val < 0:
|
||||||
raise ValueError("Only positive values allowed")
|
raise ValueError("Only positive values allowed")
|
||||||
s = "%x" % val
|
s = "%x" % val
|
||||||
ret = ''
|
ret = ""
|
||||||
for x in s:
|
for x in s:
|
||||||
ret += _BitTable[x]
|
ret += _BitTable[x]
|
||||||
# remove leading zeros
|
# remove leading zeros
|
||||||
while ret[0] == '0' and len(ret) > 1:
|
while ret[0] == "0" and len(ret) > 1:
|
||||||
ret = ret[1:]
|
ret = ret[1:]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -1595,7 +1604,7 @@ def _checkNetmask(netmask, masklen):
|
||||||
def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
|
def _checkNetaddrWorksWithPrefixlen(net, prefixlen, version):
|
||||||
"""Check if a base addess of a network is compatible with a prefixlen"""
|
"""Check if a base addess of a network is compatible with a prefixlen"""
|
||||||
try:
|
try:
|
||||||
return (net & _prefixlenToNetmask(prefixlen, version) == net)
|
return net & _prefixlenToNetmask(prefixlen, version) == net
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1637,8 +1646,8 @@ def _remove_subprefix(prefix, subprefix):
|
||||||
|
|
||||||
# Start cutting in half, recursively
|
# Start cutting in half, recursively
|
||||||
prefixes = [
|
prefixes = [
|
||||||
IP('%s/%d' % (prefix[0], prefix._prefixlen + 1)),
|
IP("%s/%d" % (prefix[0], prefix._prefixlen + 1)),
|
||||||
IP('%s/%d' % (prefix[int(prefix.len() / 2)], prefix._prefixlen + 1)),
|
IP("%s/%d" % (prefix[int(prefix.len() / 2)], prefix._prefixlen + 1)),
|
||||||
]
|
]
|
||||||
if subprefix in prefixes[0]:
|
if subprefix in prefixes[0]:
|
||||||
return _remove_subprefix(prefixes[0], subprefix) + IPSet([prefixes[1]])
|
return _remove_subprefix(prefixes[0], subprefix) + IPSet([prefixes[1]])
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import libvirt
|
|
||||||
import threading
|
|
||||||
import socket
|
|
||||||
import re
|
import re
|
||||||
from vrtManager import util
|
import socket
|
||||||
from vrtManager.rwlock import ReadWriteLock
|
import threading
|
||||||
|
|
||||||
|
import libvirt
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
from vrtManager import util
|
||||||
|
from vrtManager.rwlock import ReadWriteLock
|
||||||
|
|
||||||
CONN_SOCKET = 4
|
CONN_SOCKET = 4
|
||||||
CONN_TLS = 3
|
CONN_TLS = 3
|
||||||
|
@ -18,6 +19,7 @@ TCP_PORT = 16509
|
||||||
|
|
||||||
class wvmEventLoop(threading.Thread):
|
class wvmEventLoop(threading.Thread):
|
||||||
""" Event Loop Class"""
|
""" Event Loop Class"""
|
||||||
|
|
||||||
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
|
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
|
||||||
# register the default event implementation
|
# register the default event implementation
|
||||||
# of libvirt, as we do not have an existing
|
# of libvirt, as we do not have an existing
|
||||||
|
@ -25,7 +27,7 @@ class wvmEventLoop(threading.Thread):
|
||||||
libvirt.virEventRegisterDefaultImpl()
|
libvirt.virEventRegisterDefaultImpl()
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
name = 'libvirt event loop'
|
name = "libvirt event loop"
|
||||||
|
|
||||||
super(wvmEventLoop, self).__init__(group, target, name, args, kwargs)
|
super(wvmEventLoop, self).__init__(group, target, name, args, kwargs)
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ class wvmConnection(object):
|
||||||
class representing a single connection stored in the Connection Manager
|
class representing a single connection stored in the Connection Manager
|
||||||
# to-do: may also need some locking to ensure to not connect simultaniously in 2 threads
|
# to-do: may also need some locking to ensure to not connect simultaniously in 2 threads
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, host, login, passwd, conn):
|
def __init__(self, host, login, passwd, conn):
|
||||||
"""
|
"""
|
||||||
Sets all class attributes and tries to open the connection
|
Sets all class attributes and tries to open the connection
|
||||||
|
@ -86,10 +89,12 @@ class wvmConnection(object):
|
||||||
# * set keep alive interval
|
# * set keep alive interval
|
||||||
# * set connection close/fail handler
|
# * set connection close/fail handler
|
||||||
try:
|
try:
|
||||||
self.connection.setKeepAlive(connection_manager.keepalive_interval, connection_manager.keepalive_count)
|
self.connection.setKeepAlive(
|
||||||
|
connection_manager.keepalive_interval, connection_manager.keepalive_count
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
self.connection.registerCloseCallback(self.__connection_close_callback, None)
|
self.connection.registerCloseCallback(self.__connection_close_callback, None)
|
||||||
except:
|
except Exception:
|
||||||
# Temporary fix for libvirt > libvirt-0.10.2-41
|
# Temporary fix for libvirt > libvirt-0.10.2-41
|
||||||
pass
|
pass
|
||||||
except libvirtError as e:
|
except libvirtError as e:
|
||||||
|
@ -134,49 +139,49 @@ class wvmConnection(object):
|
||||||
def __connect_tcp(self):
|
def __connect_tcp(self):
|
||||||
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
|
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
|
||||||
auth = [flags, self.__libvirt_auth_credentials_callback, None]
|
auth = [flags, self.__libvirt_auth_credentials_callback, None]
|
||||||
uri = f'qemu+tcp://{self.host}/system'
|
uri = f"qemu+tcp://{self.host}/system"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.connection = libvirt.openAuth(uri, auth, 0)
|
self.connection = libvirt.openAuth(uri, auth, 0)
|
||||||
self.last_error = None
|
self.last_error = None
|
||||||
|
|
||||||
except libvirtError as e:
|
except libvirtError as e:
|
||||||
self.last_error = f'Connection Failed: {str(e)}'
|
self.last_error = f"Connection Failed: {str(e)}"
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
|
||||||
def __connect_ssh(self):
|
def __connect_ssh(self):
|
||||||
uri = 'qemu+ssh://%s@%s/system' % (self.login, self.host)
|
uri = "qemu+ssh://%s@%s/system" % (self.login, self.host)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.connection = libvirt.open(uri)
|
self.connection = libvirt.open(uri)
|
||||||
self.last_error = None
|
self.last_error = None
|
||||||
|
|
||||||
except libvirtError as e:
|
except libvirtError as e:
|
||||||
self.last_error = f'Connection Failed: {str(e)} --- ' + repr(libvirt.virGetLastError())
|
self.last_error = f"Connection Failed: {str(e)} --- " + repr(libvirt.virGetLastError())
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
|
||||||
def __connect_tls(self):
|
def __connect_tls(self):
|
||||||
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
|
flags = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE]
|
||||||
auth = [flags, self.__libvirt_auth_credentials_callback, None]
|
auth = [flags, self.__libvirt_auth_credentials_callback, None]
|
||||||
uri = 'qemu+tls://%s@%s/system' % (self.login, self.host)
|
uri = "qemu+tls://%s@%s/system" % (self.login, self.host)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.connection = libvirt.openAuth(uri, auth, 0)
|
self.connection = libvirt.openAuth(uri, auth, 0)
|
||||||
self.last_error = None
|
self.last_error = None
|
||||||
|
|
||||||
except libvirtError as e:
|
except libvirtError as e:
|
||||||
self.last_error = f'Connection Failed: {str(e)}'
|
self.last_error = f"Connection Failed: {str(e)}"
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
|
||||||
def __connect_socket(self):
|
def __connect_socket(self):
|
||||||
uri = 'qemu:///system'
|
uri = "qemu:///system"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.connection = libvirt.open(uri)
|
self.connection = libvirt.open(uri)
|
||||||
self.last_error = None
|
self.last_error = None
|
||||||
|
|
||||||
except libvirtError as e:
|
except libvirtError as e:
|
||||||
self.last_error = f'Connection Failed: {str(e)}'
|
self.last_error = f"Connection Failed: {str(e)}"
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
@ -202,23 +207,23 @@ class wvmConnection(object):
|
||||||
# unregister callback (as it is no longer valid if this instance gets deleted)
|
# unregister callback (as it is no longer valid if this instance gets deleted)
|
||||||
try:
|
try:
|
||||||
self.connection.unregisterCloseCallback()
|
self.connection.unregisterCloseCallback()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.type == CONN_TCP:
|
if self.type == CONN_TCP:
|
||||||
type_str = 'tcp'
|
type_str = "tcp"
|
||||||
elif self.type == CONN_SSH:
|
elif self.type == CONN_SSH:
|
||||||
type_str = 'ssh'
|
type_str = "ssh"
|
||||||
elif self.type == CONN_TLS:
|
elif self.type == CONN_TLS:
|
||||||
type_str = 'tls'
|
type_str = "tls"
|
||||||
else:
|
else:
|
||||||
type_str = 'invalid_type'
|
type_str = "invalid_type"
|
||||||
|
|
||||||
return f'qemu+{type_str}://{self.login}@{self.host}/system'
|
return f"qemu+{type_str}://{self.login}@{self.host}/system"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f'<wvmConnection {str(self)}>'
|
return f"<wvmConnection {str(self)}>"
|
||||||
|
|
||||||
|
|
||||||
class wvmConnectionManager(object):
|
class wvmConnectionManager(object):
|
||||||
|
@ -307,7 +312,7 @@ class wvmConnectionManager(object):
|
||||||
socket_host = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
socket_host = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
socket_host.settimeout(1)
|
socket_host.settimeout(1)
|
||||||
if conn_type == CONN_SSH:
|
if conn_type == CONN_SSH:
|
||||||
if ':' in hostname:
|
if ":" in hostname:
|
||||||
libvirt_host, PORT = hostname.split(":")
|
libvirt_host, PORT = hostname.split(":")
|
||||||
PORT = int(PORT)
|
PORT = int(PORT)
|
||||||
else:
|
else:
|
||||||
|
@ -320,7 +325,7 @@ class wvmConnectionManager(object):
|
||||||
socket_host.connect((hostname, TLS_PORT))
|
socket_host.connect((hostname, TLS_PORT))
|
||||||
if conn_type == CONN_SOCKET:
|
if conn_type == CONN_SOCKET:
|
||||||
socket_host = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
socket_host = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
socket_host.connect('/var/run/libvirt/libvirt-sock')
|
socket_host.connect("/var/run/libvirt/libvirt-sock")
|
||||||
socket_host.close()
|
socket_host.close()
|
||||||
return True
|
return True
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -328,8 +333,8 @@ class wvmConnectionManager(object):
|
||||||
|
|
||||||
|
|
||||||
connection_manager = wvmConnectionManager(
|
connection_manager = wvmConnectionManager(
|
||||||
settings.LIBVIRT_KEEPALIVE_INTERVAL if hasattr(settings, 'LIBVIRT_KEEPALIVE_INTERVAL') else 5,
|
settings.LIBVIRT_KEEPALIVE_INTERVAL if hasattr(settings, "LIBVIRT_KEEPALIVE_INTERVAL") else 5,
|
||||||
settings.LIBVIRT_KEEPALIVE_COUNT if hasattr(settings, 'LIBVIRT_KEEPALIVE_COUNT') else 5,
|
settings.LIBVIRT_KEEPALIVE_COUNT if hasattr(settings, "LIBVIRT_KEEPALIVE_COUNT") else 5,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,15 +358,16 @@ class wvmConnect(object):
|
||||||
def get_dom_cap_xml(self, arch, machine):
|
def get_dom_cap_xml(self, arch, machine):
|
||||||
""" Return domain capabilities xml"""
|
""" Return domain capabilities xml"""
|
||||||
emulatorbin = self.get_emulator(arch)
|
emulatorbin = self.get_emulator(arch)
|
||||||
virttype = 'kvm' if 'kvm' in self.get_hypervisors_domain_types()[arch] else 'qemu'
|
virttype = "kvm" if "kvm" in self.get_hypervisors_domain_types()[arch] else "qemu"
|
||||||
|
|
||||||
machine_types = self.get_machine_types(arch)
|
machine_types = self.get_machine_types(arch)
|
||||||
if not machine or machine not in machine_types:
|
if not machine or machine not in machine_types:
|
||||||
machine = 'pc' if 'pc' in machine_types else machine_types[0]
|
machine = "pc" if "pc" in machine_types else machine_types[0]
|
||||||
return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype)
|
return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype)
|
||||||
|
|
||||||
def get_capabilities(self, arch):
|
def get_capabilities(self, arch):
|
||||||
""" Host Capabilities for specified architecture """
|
""" Host Capabilities for specified architecture """
|
||||||
|
|
||||||
def guests(ctx):
|
def guests(ctx):
|
||||||
result = dict()
|
result = dict()
|
||||||
for arch_el in ctx.xpath("/capabilities/guest/arch[@name='{}']".format(arch)):
|
for arch_el in ctx.xpath("/capabilities/guest/arch[@name='{}']".format(arch)):
|
||||||
|
@ -371,11 +377,9 @@ class wvmConnect(object):
|
||||||
|
|
||||||
result["machines"] = []
|
result["machines"] = []
|
||||||
for m in arch_el.xpath("machine"):
|
for m in arch_el.xpath("machine"):
|
||||||
result["machines"].append({
|
result["machines"].append(
|
||||||
"machine": m.text,
|
{"machine": m.text, "max_cpu": m.get("maxCpus"), "canonical": m.get("canonical")}
|
||||||
"max_cpu": m.get("maxCpus"),
|
)
|
||||||
"canonical": m.get("canonical")
|
|
||||||
})
|
|
||||||
|
|
||||||
guest_el = arch_el.getparent()
|
guest_el = arch_el.getparent()
|
||||||
for f in guest_el.xpath("features"):
|
for f in guest_el.xpath("features"):
|
||||||
|
@ -400,7 +404,7 @@ class wvmConnect(object):
|
||||||
result["os_support"] = util.get_xml_path(xml, "/domainCapabilities/os/@supported")
|
result["os_support"] = util.get_xml_path(xml, "/domainCapabilities/os/@supported")
|
||||||
|
|
||||||
result["loader_support"] = util.get_xml_path(xml, "/domainCapabilities/os/loader/@supported")
|
result["loader_support"] = util.get_xml_path(xml, "/domainCapabilities/os/loader/@supported")
|
||||||
if result["loader_support"] == 'yes':
|
if result["loader_support"] == "yes":
|
||||||
result["loaders"] = self.get_os_loaders(arch, machine)
|
result["loaders"] = self.get_os_loaders(arch, machine)
|
||||||
result["loader_enums"] = self.get_os_loader_enums(arch, machine)
|
result["loader_enums"] = self.get_os_loader_enums(arch, machine)
|
||||||
|
|
||||||
|
@ -410,27 +414,29 @@ class wvmConnect(object):
|
||||||
result["cpu_custom_models"] = self.get_cpu_custom_types(arch, machine)
|
result["cpu_custom_models"] = self.get_cpu_custom_types(arch, machine)
|
||||||
|
|
||||||
result["disk_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/disk/@supported")
|
result["disk_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/disk/@supported")
|
||||||
if result["disk_support"] == 'yes':
|
if result["disk_support"] == "yes":
|
||||||
result["disk_devices"] = self.get_disk_device_types(arch, machine)
|
result["disk_devices"] = self.get_disk_device_types(arch, machine)
|
||||||
result["disk_bus"] = self.get_disk_bus_types(arch, machine)
|
result["disk_bus"] = self.get_disk_bus_types(arch, machine)
|
||||||
|
|
||||||
result["graphics_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/graphics/@supported")
|
result["graphics_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/graphics/@supported")
|
||||||
if result["graphics_support"] == 'yes':
|
if result["graphics_support"] == "yes":
|
||||||
result["graphics_types"] = self.get_graphics_types(arch, machine)
|
result["graphics_types"] = self.get_graphics_types(arch, machine)
|
||||||
|
|
||||||
result["video_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/video/@supported")
|
result["video_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/video/@supported")
|
||||||
if result["video_support"] == 'yes':
|
if result["video_support"] == "yes":
|
||||||
result["video_types"] = self.get_video_models(arch, machine)
|
result["video_types"] = self.get_video_models(arch, machine)
|
||||||
|
|
||||||
result["hostdev_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/hostdev/@supported")
|
result["hostdev_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/hostdev/@supported")
|
||||||
if result["hostdev_support"] == 'yes':
|
if result["hostdev_support"] == "yes":
|
||||||
result["hostdev_types"] = self.get_hostdev_modes(arch, machine)
|
result["hostdev_types"] = self.get_hostdev_modes(arch, machine)
|
||||||
result["hostdev_startup_policies"] = self.get_hostdev_startup_policies(arch, machine)
|
result["hostdev_startup_policies"] = self.get_hostdev_startup_policies(arch, machine)
|
||||||
result["hostdev_subsys_types"] = self.get_hostdev_subsys_types(arch, machine)
|
result["hostdev_subsys_types"] = self.get_hostdev_subsys_types(arch, machine)
|
||||||
|
|
||||||
result["features_gic_support"] = util.get_xml_path(xml, "/domainCapabilities/features/gic/@supported")
|
result["features_gic_support"] = util.get_xml_path(xml, "/domainCapabilities/features/gic/@supported")
|
||||||
result["features_genid_support"] = util.get_xml_path(xml, "/domainCapabilities/features/genid/@supported")
|
result["features_genid_support"] = util.get_xml_path(xml, "/domainCapabilities/features/genid/@supported")
|
||||||
result["features_vmcoreinfo_support"] = util.get_xml_path(xml, "/domainCapabilities/features/vmcoreinfo/@supported")
|
result["features_vmcoreinfo_support"] = util.get_xml_path(
|
||||||
|
xml, "/domainCapabilities/features/vmcoreinfo/@supported"
|
||||||
|
)
|
||||||
result["features_sev_support"] = util.get_xml_path(xml, "/domainCapabilities/features/sev/@supported")
|
result["features_sev_support"] = util.get_xml_path(xml, "/domainCapabilities/features/sev/@supported")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -510,12 +516,12 @@ class wvmConnect(object):
|
||||||
:return: Get cache available modes
|
:return: Get cache available modes
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'default': 'Default',
|
"default": "Default",
|
||||||
'none': 'Disabled',
|
"none": "Disabled",
|
||||||
'writethrough': 'Write through',
|
"writethrough": "Write through",
|
||||||
'writeback': 'Write back',
|
"writeback": "Write back",
|
||||||
'directsync': 'Direct sync', # since libvirt 0.9.5
|
"directsync": "Direct sync", # since libvirt 0.9.5
|
||||||
'unsafe': 'Unsafe', # since libvirt 0.9.7
|
"unsafe": "Unsafe", # since libvirt 0.9.7
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_io_modes(self):
|
def get_io_modes(self):
|
||||||
|
@ -523,9 +529,9 @@ class wvmConnect(object):
|
||||||
:return: available io modes
|
:return: available io modes
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'default': 'Default',
|
"default": "Default",
|
||||||
'native': 'Native',
|
"native": "Native",
|
||||||
'threads': 'Threads',
|
"threads": "Threads",
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_discard_modes(self):
|
def get_discard_modes(self):
|
||||||
|
@ -533,9 +539,9 @@ class wvmConnect(object):
|
||||||
:return: available discard modes
|
:return: available discard modes
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'default': 'Default',
|
"default": "Default",
|
||||||
'ignore': 'Ignore',
|
"ignore": "Ignore",
|
||||||
'unmap': 'Unmap',
|
"unmap": "Unmap",
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_detect_zeroes_modes(self):
|
def get_detect_zeroes_modes(self):
|
||||||
|
@ -543,21 +549,22 @@ class wvmConnect(object):
|
||||||
:return: available detect zeroes modes
|
:return: available detect zeroes modes
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'default': 'Default',
|
"default": "Default",
|
||||||
'on': 'On',
|
"on": "On",
|
||||||
'off': 'Off',
|
"off": "Off",
|
||||||
'unmap': 'Unmap',
|
"unmap": "Unmap",
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_hypervisors_domain_types(self):
|
def get_hypervisors_domain_types(self):
|
||||||
"""
|
"""
|
||||||
:return: hypervisor domain types
|
:return: hypervisor domain types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def hypervisors(ctx):
|
def hypervisors(ctx):
|
||||||
result = {}
|
result = {}
|
||||||
for arch in ctx.xpath('/capabilities/guest/arch'):
|
for arch in ctx.xpath("/capabilities/guest/arch"):
|
||||||
domain_types = arch.xpath('domain/@type')
|
domain_types = arch.xpath("domain/@type")
|
||||||
arch_name = arch.xpath('@name')[0]
|
arch_name = arch.xpath("@name")[0]
|
||||||
result[arch_name] = domain_types
|
result[arch_name] = domain_types
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -567,9 +574,10 @@ class wvmConnect(object):
|
||||||
"""
|
"""
|
||||||
:return: hypervisor and its machine types
|
:return: hypervisor and its machine types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def machines(ctx):
|
def machines(ctx):
|
||||||
result = dict()
|
result = dict()
|
||||||
for arche in ctx.xpath('/capabilities/guest/arch'):
|
for arche in ctx.xpath("/capabilities/guest/arch"):
|
||||||
arch = arche.get("name")
|
arch = arche.get("name")
|
||||||
|
|
||||||
result[arch] = self.get_machine_types(arch)
|
result[arch] = self.get_machine_types(arch)
|
||||||
|
@ -587,6 +595,7 @@ class wvmConnect(object):
|
||||||
"""
|
"""
|
||||||
:return: canonical(if exist) name of machine types
|
:return: canonical(if exist) name of machine types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def machines(ctx):
|
def machines(ctx):
|
||||||
result = list()
|
result = list()
|
||||||
canonical_name = ctx.xpath("/capabilities/guest/arch[@name='{}']/machine[@canonical]".format(arch))
|
canonical_name = ctx.xpath("/capabilities/guest/arch[@name='{}']/machine[@canonical]".format(arch))
|
||||||
|
@ -602,22 +611,24 @@ class wvmConnect(object):
|
||||||
"""
|
"""
|
||||||
:return: host emulators list
|
:return: host emulators list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def emulators(ctx):
|
def emulators(ctx):
|
||||||
result = {}
|
result = {}
|
||||||
for arch in ctx.xpath('/capabilities/guest/arch'):
|
for arch in ctx.xpath("/capabilities/guest/arch"):
|
||||||
emulator = arch.xpath('emulator')
|
emulator = arch.xpath("emulator")
|
||||||
arch_name = arch.xpath('@name')[0]
|
arch_name = arch.xpath("@name")[0]
|
||||||
result[arch_name] = emulator
|
result[arch_name] = emulator
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return util.get_xml_path(self.get_cap_xml(), func=emulators)
|
return util.get_xml_path(self.get_cap_xml(), func=emulators)
|
||||||
|
|
||||||
def get_os_loaders(self, arch='x86_64', machine='pc'):
|
def get_os_loaders(self, arch="x86_64", machine="pc"):
|
||||||
"""
|
"""
|
||||||
:param arch: architecture
|
:param arch: architecture
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available os loaders list
|
:return: available os loaders list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_os_loaders(ctx):
|
def get_os_loaders(ctx):
|
||||||
return [v.text for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/value")]
|
return [v.text for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/value")]
|
||||||
|
|
||||||
|
@ -629,6 +640,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available os loaders list
|
:return: available os loaders list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_os_loader_enums(ctx):
|
def get_os_loader_enums(ctx):
|
||||||
result = dict()
|
result = dict()
|
||||||
enums = [v for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/enum/@name")]
|
enums = [v for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/enum/@name")]
|
||||||
|
@ -645,6 +657,7 @@ class wvmConnect(object):
|
||||||
:param arch:
|
:param arch:
|
||||||
:return: available disk bus types list
|
:return: available disk bus types list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_bus_list(ctx):
|
def get_bus_list(ctx):
|
||||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='bus']/value")]
|
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='bus']/value")]
|
||||||
|
|
||||||
|
@ -657,6 +670,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available disk device type list
|
:return: available disk device type list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_device_list(ctx):
|
def get_device_list(ctx):
|
||||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='diskDevice']/value")]
|
return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='diskDevice']/value")]
|
||||||
|
|
||||||
|
@ -669,6 +683,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available graphics types
|
:return: available graphics types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_graphics_list(ctx):
|
def get_graphics_list(ctx):
|
||||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/graphics/enum[@name='type']/value")]
|
return [v.text for v in ctx.xpath("/domainCapabilities/devices/graphics/enum[@name='type']/value")]
|
||||||
|
|
||||||
|
@ -680,6 +695,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available cpu modes
|
:return: available cpu modes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_cpu_modes(ctx):
|
def get_cpu_modes(ctx):
|
||||||
return [v for v in ctx.xpath("/domainCapabilities/cpu/mode[@supported='yes']/@name")]
|
return [v for v in ctx.xpath("/domainCapabilities/cpu/mode[@supported='yes']/@name")]
|
||||||
|
|
||||||
|
@ -691,6 +707,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available graphics types
|
:return: available graphics types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_custom_list(ctx):
|
def get_custom_list(ctx):
|
||||||
usable_yes = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='yes']"
|
usable_yes = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='yes']"
|
||||||
usable_unknown = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='unknown']"
|
usable_unknown = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='unknown']"
|
||||||
|
@ -706,6 +723,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return. available nodedev modes
|
:return. available nodedev modes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_hostdev_list(ctx):
|
def get_hostdev_list(ctx):
|
||||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='mode']/value")]
|
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='mode']/value")]
|
||||||
|
|
||||||
|
@ -717,6 +735,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available hostdev modes
|
:return: available hostdev modes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_hostdev_list(ctx):
|
def get_hostdev_list(ctx):
|
||||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='startupPolicy']/value")]
|
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='startupPolicy']/value")]
|
||||||
|
|
||||||
|
@ -728,6 +747,7 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available nodedev sub system types
|
:return: available nodedev sub system types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_hostdev_list(ctx):
|
def get_hostdev_list(ctx):
|
||||||
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='subsysType']/value")]
|
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='subsysType']/value")]
|
||||||
|
|
||||||
|
@ -737,19 +757,19 @@ class wvmConnect(object):
|
||||||
"""
|
"""
|
||||||
:return: network card models
|
:return: network card models
|
||||||
"""
|
"""
|
||||||
return ['default', 'e1000', 'virtio']
|
return ["default", "e1000", "virtio"]
|
||||||
|
|
||||||
def get_image_formats(self):
|
def get_image_formats(self):
|
||||||
"""
|
"""
|
||||||
:return: available image formats
|
:return: available image formats
|
||||||
"""
|
"""
|
||||||
return ['raw', 'qcow', 'qcow2']
|
return ["raw", "qcow", "qcow2"]
|
||||||
|
|
||||||
def get_file_extensions(self):
|
def get_file_extensions(self):
|
||||||
"""
|
"""
|
||||||
:return: available image filename extensions
|
:return: available image filename extensions
|
||||||
"""
|
"""
|
||||||
return ['img', 'qcow', 'qcow2']
|
return ["img", "qcow", "qcow2"]
|
||||||
|
|
||||||
def get_video_models(self, arch, machine):
|
def get_video_models(self, arch, machine):
|
||||||
"""
|
"""
|
||||||
|
@ -757,9 +777,10 @@ class wvmConnect(object):
|
||||||
:param machine:
|
:param machine:
|
||||||
:return: available graphics video types
|
:return: available graphics video types
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_video_list(ctx):
|
def get_video_list(ctx):
|
||||||
result = []
|
result = []
|
||||||
for video_enum in ctx.xpath('/domainCapabilities/devices/video/enum'):
|
for video_enum in ctx.xpath("/domainCapabilities/devices/video/enum"):
|
||||||
if video_enum.xpath("@name")[0] == "modelType":
|
if video_enum.xpath("@name")[0] == "modelType":
|
||||||
for values in video_enum:
|
for values in video_enum:
|
||||||
result.append(values.text)
|
result.append(values.text)
|
||||||
|
@ -787,8 +808,8 @@ class wvmConnect(object):
|
||||||
|
|
||||||
def get_network_forward(self, net_name):
|
def get_network_forward(self, net_name):
|
||||||
def get_forward(doc):
|
def get_forward(doc):
|
||||||
forward_mode = util.get_xpath(doc, '/network/forward/@mode')
|
forward_mode = util.get_xpath(doc, "/network/forward/@mode")
|
||||||
return forward_mode or 'isolated'
|
return forward_mode or "isolated"
|
||||||
|
|
||||||
net = self.get_network(net_name)
|
net = self.get_network(net_name)
|
||||||
xml = net.XMLDesc(0)
|
xml = net.XMLDesc(0)
|
||||||
|
@ -825,14 +846,14 @@ class wvmConnect(object):
|
||||||
netdevice = []
|
netdevice = []
|
||||||
|
|
||||||
def get_info(doc):
|
def get_info(doc):
|
||||||
dev_type = util.get_xpath(doc, '/device/capability/@type')
|
dev_type = util.get_xpath(doc, "/device/capability/@type")
|
||||||
interface = util.get_xpath(doc, '/device/capability/interface')
|
interface = util.get_xpath(doc, "/device/capability/interface")
|
||||||
return dev_type, interface
|
return dev_type, interface
|
||||||
|
|
||||||
for dev in self.wvm.listAllDevices(0):
|
for dev in self.wvm.listAllDevices(0):
|
||||||
xml = dev.XMLDesc(0)
|
xml = dev.XMLDesc(0)
|
||||||
(dev_type, interface) = util.get_xml_path(xml, func=get_info)
|
(dev_type, interface) = util.get_xml_path(xml, func=get_info)
|
||||||
if dev_type == 'net':
|
if dev_type == "net":
|
||||||
netdevice.append(interface)
|
netdevice.append(interface)
|
||||||
return netdevice
|
return netdevice
|
||||||
|
|
||||||
|
@ -850,9 +871,9 @@ class wvmConnect(object):
|
||||||
else:
|
else:
|
||||||
vcpu = util.get_xpath(doc, "/domain/vcpu")
|
vcpu = util.get_xpath(doc, "/domain/vcpu")
|
||||||
title = util.get_xpath(doc, "/domain/title")
|
title = util.get_xpath(doc, "/domain/title")
|
||||||
title = title if title else ''
|
title = title if title else ""
|
||||||
description = util.get_xpath(doc, "/domain/description")
|
description = util.get_xpath(doc, "/domain/description")
|
||||||
description = description if description else ''
|
description = description if description else ""
|
||||||
return mem, vcpu, title, description
|
return mem, vcpu, title, description
|
||||||
|
|
||||||
for name in self.get_instances():
|
for name in self.get_instances():
|
||||||
|
@ -860,12 +881,12 @@ class wvmConnect(object):
|
||||||
xml = dom.XMLDesc(0)
|
xml = dom.XMLDesc(0)
|
||||||
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
|
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
|
||||||
vname[dom.name()] = {
|
vname[dom.name()] = {
|
||||||
'status': dom.info()[0],
|
"status": dom.info()[0],
|
||||||
'uuid': dom.UUIDString(),
|
"uuid": dom.UUIDString(),
|
||||||
'vcpu': vcpu,
|
"vcpu": vcpu,
|
||||||
'memory': mem,
|
"memory": mem,
|
||||||
'title': title,
|
"title": title,
|
||||||
'description': description,
|
"description": description,
|
||||||
}
|
}
|
||||||
return vname
|
return vname
|
||||||
|
|
||||||
|
@ -882,20 +903,20 @@ class wvmConnect(object):
|
||||||
else:
|
else:
|
||||||
vcpu = util.get_xpath(ctx, "/domain/vcpu")
|
vcpu = util.get_xpath(ctx, "/domain/vcpu")
|
||||||
title = util.get_xpath(ctx, "/domain/title")
|
title = util.get_xpath(ctx, "/domain/title")
|
||||||
title = title if title else ''
|
title = title if title else ""
|
||||||
description = util.get_xpath(ctx, "/domain/description")
|
description = util.get_xpath(ctx, "/domain/description")
|
||||||
description = description if description else ''
|
description = description if description else ""
|
||||||
return mem, vcpu, title, description
|
return mem, vcpu, title, description
|
||||||
|
|
||||||
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
|
(mem, vcpu, title, description) = util.get_xml_path(xml, func=get_info)
|
||||||
return {
|
return {
|
||||||
'name': dom.name(),
|
"name": dom.name(),
|
||||||
'status': dom.info()[0],
|
"status": dom.info()[0],
|
||||||
'uuid': dom.UUIDString(),
|
"uuid": dom.UUIDString(),
|
||||||
'vcpu': vcpu,
|
"vcpu": vcpu,
|
||||||
'memory': mem,
|
"memory": mem,
|
||||||
'title': title,
|
"title": title,
|
||||||
'description': description,
|
"description": description,
|
||||||
}
|
}
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
|
@ -931,7 +952,7 @@ class wvmConnect(object):
|
||||||
for arch, patterns in util.UEFI_ARCH_PATTERNS.items():
|
for arch, patterns in util.UEFI_ARCH_PATTERNS.items():
|
||||||
for pattern in patterns:
|
for pattern in patterns:
|
||||||
if re.match(pattern, path):
|
if re.match(pattern, path):
|
||||||
return ("UEFI %(arch)s: %(path)s" % {"arch": arch, "path": path})
|
return "UEFI %(arch)s: %(path)s" % {"arch": arch, "path": path}
|
||||||
|
|
||||||
return "Custom: %(path)s" % {"path": path}
|
return "Custom: %(path)s" % {"path": path}
|
||||||
|
|
||||||
|
@ -945,15 +966,17 @@ class wvmConnect(object):
|
||||||
"""
|
"""
|
||||||
Return True if libvirt advertises support for proper UEFI setup
|
Return True if libvirt advertises support for proper UEFI setup
|
||||||
"""
|
"""
|
||||||
return ("readonly" in loader_enums and "yes" in loader_enums.get("readonly"))
|
return "readonly" in loader_enums and "yes" in loader_enums.get("readonly")
|
||||||
|
|
||||||
def is_supports_virtio(self, arch, machine):
|
def is_supports_virtio(self, arch, machine):
|
||||||
if not self.is_qemu():
|
if not self.is_qemu():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# These _only_ support virtio so don't check the OS
|
# These _only_ support virtio so don't check the OS
|
||||||
if arch in ["aarch64", "armv7l", "ppc64", "ppc64le", "s390x", "riscv64", "riscv32"] and \
|
if arch in ["aarch64", "armv7l", "ppc64", "ppc64le", "s390x", "riscv64", "riscv32"] and machine in [
|
||||||
machine in ["virt", "pseries"]:
|
"virt",
|
||||||
|
"pseries",
|
||||||
|
]:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if arch in ["x86_64", "i686"]:
|
if arch in ["x86_64", "i686"]:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import string
|
import string
|
||||||
|
|
||||||
from vrtManager import util
|
from vrtManager import util
|
||||||
from vrtManager.connection import wvmConnect
|
from vrtManager.connection import wvmConnect
|
||||||
|
|
||||||
|
@ -12,15 +13,15 @@ def get_rbd_storage_data(stg):
|
||||||
for host in doc.xpath("/pool/source/host"):
|
for host in doc.xpath("/pool/source/host"):
|
||||||
name = host.prop("name")
|
name = host.prop("name")
|
||||||
if name:
|
if name:
|
||||||
hosts.append({'name': name, 'port': host.prop("port")})
|
hosts.append({"name": name, "port": host.prop("port")})
|
||||||
return hosts
|
return hosts
|
||||||
|
|
||||||
ceph_hosts = util.get_xml_path(xml, func=get_ceph_hosts)
|
ceph_hosts = util.get_xml_path(xml, func=get_ceph_hosts)
|
||||||
secret_uuid = util.get_xml_path(xml, "/pool/source/auth/secret/@uuid")
|
secret_uuid = util.get_xml_path(xml, "/pool/source/auth/secret/@uuid")
|
||||||
return ceph_user, secret_uuid, ceph_hosts
|
return ceph_user, secret_uuid, ceph_hosts
|
||||||
|
|
||||||
|
|
||||||
class wvmCreate(wvmConnect):
|
class wvmCreate(wvmConnect):
|
||||||
|
|
||||||
def get_storages_images(self):
|
def get_storages_images(self):
|
||||||
"""
|
"""
|
||||||
Function return all images on all storages
|
Function return all images on all storages
|
||||||
|
@ -31,10 +32,10 @@ class wvmCreate(wvmConnect):
|
||||||
stg = self.get_storage(storage)
|
stg = self.get_storage(storage)
|
||||||
try:
|
try:
|
||||||
stg.refresh(0)
|
stg.refresh(0)
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
for img in stg.listVolumes():
|
for img in stg.listVolumes():
|
||||||
if img.lower().endswith('.iso'):
|
if img.lower().endswith(".iso"):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
images.append(img)
|
images.append(img)
|
||||||
|
@ -52,11 +53,11 @@ class wvmCreate(wvmConnect):
|
||||||
size = int(size) * 1073741824
|
size = int(size) * 1073741824
|
||||||
stg = self.get_storage(storage)
|
stg = self.get_storage(storage)
|
||||||
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||||
if storage_type == 'dir':
|
if storage_type == "dir":
|
||||||
if image_format in ('qcow', 'qcow2'):
|
if image_format in ("qcow", "qcow2"):
|
||||||
name += '.' + image_format
|
name += "." + image_format
|
||||||
else:
|
else:
|
||||||
name += '.img'
|
name += ".img"
|
||||||
alloc = 0
|
alloc = 0
|
||||||
else:
|
else:
|
||||||
alloc = size
|
alloc = size
|
||||||
|
@ -91,12 +92,12 @@ class wvmCreate(wvmConnect):
|
||||||
def get_volume_type(self, path):
|
def get_volume_type(self, path):
|
||||||
vol = self.get_volume_by_path(path)
|
vol = self.get_volume_by_path(path)
|
||||||
vol_type = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
vol_type = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||||
if vol_type == 'unknown' or vol_type == 'iso':
|
if vol_type == "unknown" or vol_type == "iso":
|
||||||
return 'raw'
|
return "raw"
|
||||||
if vol_type:
|
if vol_type:
|
||||||
return vol_type
|
return vol_type
|
||||||
else:
|
else:
|
||||||
return 'raw'
|
return "raw"
|
||||||
|
|
||||||
def get_volume_path(self, volume, pool=None):
|
def get_volume_path(self, volume, pool=None):
|
||||||
if not pool:
|
if not pool:
|
||||||
|
@ -125,8 +126,8 @@ class wvmCreate(wvmConnect):
|
||||||
|
|
||||||
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||||
format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||||
if storage_type == 'dir':
|
if storage_type == "dir":
|
||||||
clone += '.img'
|
clone += ".img"
|
||||||
else:
|
else:
|
||||||
metadata = False
|
metadata = False
|
||||||
xml = f"""
|
xml = f"""
|
||||||
|
@ -159,9 +160,27 @@ class wvmCreate(wvmConnect):
|
||||||
vol = self.get_volume_by_path(path)
|
vol = self.get_volume_by_path(path)
|
||||||
vol.delete()
|
vol.delete()
|
||||||
|
|
||||||
def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, volumes,
|
def create_instance(
|
||||||
networks, nwfilter, graphics, virtio, listen_addr,
|
self,
|
||||||
video="vga", console_pass="random", mac=None, qemu_ga=True):
|
name,
|
||||||
|
memory,
|
||||||
|
vcpu,
|
||||||
|
vcpu_mode,
|
||||||
|
uuid,
|
||||||
|
arch,
|
||||||
|
machine,
|
||||||
|
firmware,
|
||||||
|
volumes,
|
||||||
|
networks,
|
||||||
|
nwfilter,
|
||||||
|
graphics,
|
||||||
|
virtio,
|
||||||
|
listen_addr,
|
||||||
|
video="vga",
|
||||||
|
console_pass="random",
|
||||||
|
mac=None,
|
||||||
|
qemu_ga=True,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Create VM function
|
Create VM function
|
||||||
"""
|
"""
|
||||||
|
@ -178,33 +197,37 @@ class wvmCreate(wvmConnect):
|
||||||
<memory unit='KiB'>{memory}</memory>
|
<memory unit='KiB'>{memory}</memory>
|
||||||
<vcpu>{vcpu}</vcpu>"""
|
<vcpu>{vcpu}</vcpu>"""
|
||||||
|
|
||||||
if dom_caps["os_support"] == 'yes':
|
if dom_caps["os_support"] == "yes":
|
||||||
xml += f"""<os>
|
xml += f"""<os>
|
||||||
<type arch='{arch}' machine='{machine}'>{caps["os_type"]}</type>"""
|
<type arch='{arch}' machine='{machine}'>{caps["os_type"]}</type>"""
|
||||||
xml += """ <boot dev='hd'/>
|
xml += """ <boot dev='hd'/>
|
||||||
<boot dev='cdrom'/>
|
<boot dev='cdrom'/>
|
||||||
<bootmenu enable='yes'/>"""
|
<bootmenu enable='yes'/>"""
|
||||||
if firmware:
|
if firmware:
|
||||||
if firmware["secure"] == 'yes':
|
if firmware["secure"] == "yes":
|
||||||
xml += """<loader readonly='%s' type='%s' secure='%s'>%s</loader>""" % (firmware["readonly"],
|
xml += """<loader readonly='%s' type='%s' secure='%s'>%s</loader>""" % (
|
||||||
firmware["type"],
|
firmware["readonly"],
|
||||||
firmware["secure"],
|
firmware["type"],
|
||||||
firmware["loader"])
|
firmware["secure"],
|
||||||
if firmware["secure"] == 'no':
|
firmware["loader"],
|
||||||
xml += """<loader readonly='%s' type='%s'>%s</loader>""" % (firmware["readonly"],
|
)
|
||||||
firmware["type"],
|
if firmware["secure"] == "no":
|
||||||
firmware["loader"])
|
xml += """<loader readonly='%s' type='%s'>%s</loader>""" % (
|
||||||
|
firmware["readonly"],
|
||||||
|
firmware["type"],
|
||||||
|
firmware["loader"],
|
||||||
|
)
|
||||||
xml += """</os>"""
|
xml += """</os>"""
|
||||||
|
|
||||||
if caps["features"]:
|
if caps["features"]:
|
||||||
xml += """<features>"""
|
xml += """<features>"""
|
||||||
if 'acpi' in caps["features"]:
|
if "acpi" in caps["features"]:
|
||||||
xml += """<acpi/>"""
|
xml += """<acpi/>"""
|
||||||
if 'apic' in caps["features"]:
|
if "apic" in caps["features"]:
|
||||||
xml += """<apic/>"""
|
xml += """<apic/>"""
|
||||||
if 'pae' in caps["features"]:
|
if "pae" in caps["features"]:
|
||||||
xml += """<pae/>"""
|
xml += """<pae/>"""
|
||||||
if firmware.get("secure", 'no') == 'yes':
|
if firmware.get("secure", "no") == "yes":
|
||||||
xml += """<smm state="on"/>"""
|
xml += """<smm state="on"/>"""
|
||||||
xml += """</features>"""
|
xml += """</features>"""
|
||||||
|
|
||||||
|
@ -235,56 +258,69 @@ class wvmCreate(wvmConnect):
|
||||||
|
|
||||||
for volume in volumes:
|
for volume in volumes:
|
||||||
|
|
||||||
disk_opts = ''
|
disk_opts = ""
|
||||||
if volume['cache_mode'] is not None and volume['cache_mode'] != 'default':
|
if volume["cache_mode"] is not None and volume["cache_mode"] != "default":
|
||||||
disk_opts += f"cache='{volume['cache_mode']}' "
|
disk_opts += f"cache='{volume['cache_mode']}' "
|
||||||
if volume['io_mode'] is not None and volume['io_mode'] != 'default':
|
if volume["io_mode"] is not None and volume["io_mode"] != "default":
|
||||||
disk_opts += f"io='{volume['io_mode']}' "
|
disk_opts += f"io='{volume['io_mode']}' "
|
||||||
if volume['discard_mode'] is not None and volume['discard_mode'] != 'default':
|
if volume["discard_mode"] is not None and volume["discard_mode"] != "default":
|
||||||
disk_opts += f"discard='{volume['discard_mode']}' "
|
disk_opts += f"discard='{volume['discard_mode']}' "
|
||||||
if volume['detect_zeroes_mode'] is not None and volume['detect_zeroes_mode'] != 'default':
|
if volume["detect_zeroes_mode"] is not None and volume["detect_zeroes_mode"] != "default":
|
||||||
disk_opts += f"detect_zeroes='{volume['detect_zeroes_mode']}' "
|
disk_opts += f"detect_zeroes='{volume['detect_zeroes_mode']}' "
|
||||||
|
|
||||||
stg = self.get_storage_by_vol_path(volume['path'])
|
stg = self.get_storage_by_vol_path(volume["path"])
|
||||||
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||||
|
|
||||||
if volume['device'] == 'cdrom': add_cd = False
|
if volume["device"] == "cdrom":
|
||||||
|
add_cd = False
|
||||||
|
|
||||||
if stg_type == 'rbd':
|
if stg_type == "rbd":
|
||||||
ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg)
|
ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg)
|
||||||
xml += """<disk type='network' device='disk'>
|
xml += """<disk type='network' device='disk'>
|
||||||
<driver name='qemu' type='%s' %s />""" % (volume['type'], disk_opts)
|
<driver name='qemu' type='%s' %s />""" % (
|
||||||
|
volume["type"],
|
||||||
|
disk_opts,
|
||||||
|
)
|
||||||
xml += """ <auth username='%s'>
|
xml += """ <auth username='%s'>
|
||||||
<secret type='ceph' uuid='%s'/>
|
<secret type='ceph' uuid='%s'/>
|
||||||
</auth>
|
</auth>
|
||||||
<source protocol='rbd' name='%s'>""" % (ceph_user, secret_uuid, volume['path'])
|
<source protocol='rbd' name='%s'>""" % (
|
||||||
|
ceph_user,
|
||||||
|
secret_uuid,
|
||||||
|
volume["path"],
|
||||||
|
)
|
||||||
if isinstance(ceph_hosts, list):
|
if isinstance(ceph_hosts, list):
|
||||||
for host in ceph_hosts:
|
for host in ceph_hosts:
|
||||||
if host.get('port'):
|
if host.get("port"):
|
||||||
xml += """
|
xml += """
|
||||||
<host name='%s' port='%s'/>""" % (host.get('name'), host.get('port'))
|
<host name='%s' port='%s'/>""" % (
|
||||||
|
host.get("name"),
|
||||||
|
host.get("port"),
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
xml += """
|
xml += """
|
||||||
<host name='%s'/>""" % host.get('name')
|
<host name='%s'/>""" % host.get(
|
||||||
|
"name"
|
||||||
|
)
|
||||||
xml += """</source>"""
|
xml += """</source>"""
|
||||||
else:
|
else:
|
||||||
xml += """<disk type='file' device='%s'>""" % volume['device']
|
xml += """<disk type='file' device='%s'>""" % volume["device"]
|
||||||
xml += """ <driver name='qemu' type='%s' %s/>""" % (volume['type'], disk_opts)
|
xml += """ <driver name='qemu' type='%s' %s/>""" % (volume["type"], disk_opts)
|
||||||
xml += f""" <source file='%s'/>""" % volume['path']
|
xml += """ <source file='%s'/>""" % volume["path"]
|
||||||
|
|
||||||
if volume.get('bus') == 'virtio':
|
if volume.get("bus") == "virtio":
|
||||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume.get('bus'))
|
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume.get("bus"))
|
||||||
elif volume.get('bus') == 'ide':
|
elif volume.get("bus") == "ide":
|
||||||
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), volume.get('bus'))
|
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), volume.get("bus"))
|
||||||
elif volume.get('bus') == 'fdc':
|
elif volume.get("bus") == "fdc":
|
||||||
xml += """<target dev='fd%s' bus='%s'/>""" % (fd_disk_letters.pop(0), volume.get('bus'))
|
xml += """<target dev='fd%s' bus='%s'/>""" % (fd_disk_letters.pop(0), volume.get("bus"))
|
||||||
elif volume.get('bus') == 'sata' or volume.get('bus') == 'scsi':
|
elif volume.get("bus") == "sata" or volume.get("bus") == "scsi":
|
||||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume.get('bus'))
|
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume.get("bus"))
|
||||||
else:
|
else:
|
||||||
xml += """<target dev='sd%s'/>""" % sd_disk_letters.pop(0)
|
xml += """<target dev='sd%s'/>""" % sd_disk_letters.pop(0)
|
||||||
xml += """</disk>"""
|
xml += """</disk>"""
|
||||||
|
|
||||||
if volume.get('bus') == 'scsi':
|
if volume.get("bus") == "scsi":
|
||||||
xml += f"""<controller type='scsi' model='{volume.get('scsi_model')}'/>"""
|
xml += f"""<controller type='scsi' model='{volume.get('scsi_model')}'/>"""
|
||||||
|
|
||||||
if add_cd:
|
if add_cd:
|
||||||
|
@ -292,17 +328,17 @@ class wvmCreate(wvmConnect):
|
||||||
<driver name='qemu' type='raw'/>
|
<driver name='qemu' type='raw'/>
|
||||||
<source file = '' />
|
<source file = '' />
|
||||||
<readonly/>"""
|
<readonly/>"""
|
||||||
if 'ide' in dom_caps['disk_bus']:
|
if "ide" in dom_caps["disk_bus"]:
|
||||||
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), 'ide')
|
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), "ide")
|
||||||
elif 'sata' in dom_caps['disk_bus']:
|
elif "sata" in dom_caps["disk_bus"]:
|
||||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'sata')
|
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), "sata")
|
||||||
elif 'scsi' in dom_caps['disk_bus']:
|
elif "scsi" in dom_caps["disk_bus"]:
|
||||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'scsi')
|
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), "scsi")
|
||||||
else:
|
else:
|
||||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), 'virtio')
|
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), "virtio")
|
||||||
xml += """</disk>"""
|
xml += """</disk>"""
|
||||||
|
|
||||||
for net in networks.split(','):
|
for net in networks.split(","):
|
||||||
xml += """<interface type='network'>"""
|
xml += """<interface type='network'>"""
|
||||||
if mac:
|
if mac:
|
||||||
xml += f"""<mac address='{mac}'/>"""
|
xml += f"""<mac address='{mac}'/>"""
|
||||||
|
@ -319,10 +355,10 @@ class wvmCreate(wvmConnect):
|
||||||
if not console_pass == "":
|
if not console_pass == "":
|
||||||
console_pass = "passwd='" + console_pass + "'"
|
console_pass = "passwd='" + console_pass + "'"
|
||||||
|
|
||||||
if 'usb' in dom_caps['disk_bus']:
|
if "usb" in dom_caps["disk_bus"]:
|
||||||
xml += """<input type='mouse' bus='{}'/>""".format('virtio' if virtio else 'usb')
|
xml += """<input type='mouse' bus='{}'/>""".format("virtio" if virtio else "usb")
|
||||||
xml += """<input type='keyboard' bus='{}'/>""".format('virtio' if virtio else 'usb')
|
xml += """<input type='keyboard' bus='{}'/>""".format("virtio" if virtio else "usb")
|
||||||
xml += """<input type='tablet' bus='{}'/>""".format('virtio' if virtio else 'usb')
|
xml += """<input type='tablet' bus='{}'/>""".format("virtio" if virtio else "usb")
|
||||||
else:
|
else:
|
||||||
xml += """<input type='mouse'/>"""
|
xml += """<input type='mouse'/>"""
|
||||||
xml += """<input type='keyboard'/>"""
|
xml += """<input type='keyboard'/>"""
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from vrtManager.connection import wvmConnect
|
from vrtManager.connection import wvmConnect
|
||||||
from vrtManager.util import get_xml_path
|
from vrtManager.util import get_xml_path
|
||||||
|
|
||||||
|
|
||||||
def cpu_version(doc):
|
def cpu_version(doc):
|
||||||
for info in doc.xpath('/sysinfo/processor/entry'):
|
for info in doc.xpath("/sysinfo/processor/entry"):
|
||||||
elem = info.xpath('@name')[0]
|
elem = info.xpath("@name")[0]
|
||||||
if elem == 'version':
|
if elem == "version":
|
||||||
return info.text
|
return info.text
|
||||||
return 'Unknown'
|
return "Unknown"
|
||||||
|
|
||||||
|
|
||||||
class wvmHostDetails(wvmConnect):
|
class wvmHostDetails(wvmConnect):
|
||||||
|
@ -19,14 +20,12 @@ class wvmHostDetails(wvmConnect):
|
||||||
all_mem = self.wvm.getInfo()[1] * 1048576
|
all_mem = self.wvm.getInfo()[1] * 1048576
|
||||||
freemem = self.wvm.getMemoryStats(-1, 0)
|
freemem = self.wvm.getMemoryStats(-1, 0)
|
||||||
if isinstance(freemem, dict):
|
if isinstance(freemem, dict):
|
||||||
free = (freemem['buffers'] +
|
free = (freemem["buffers"] + freemem["free"] + freemem["cached"]) * 1024
|
||||||
freemem['free'] +
|
|
||||||
freemem['cached']) * 1024
|
|
||||||
percent = abs(100 - ((free * 100) // all_mem))
|
percent = abs(100 - ((free * 100) // all_mem))
|
||||||
usage = (all_mem - free)
|
usage = all_mem - free
|
||||||
mem_usage = {'total': all_mem, 'usage': usage, 'percent': percent}
|
mem_usage = {"total": all_mem, "usage": usage, "percent": percent}
|
||||||
else:
|
else:
|
||||||
mem_usage = {'total': None, 'usage': None, 'percent': None}
|
mem_usage = {"total": None, "usage": None, "percent": None}
|
||||||
return mem_usage
|
return mem_usage
|
||||||
|
|
||||||
def get_cpu_usage(self):
|
def get_cpu_usage(self):
|
||||||
|
@ -38,7 +37,7 @@ class wvmHostDetails(wvmConnect):
|
||||||
cpu = self.wvm.getCPUStats(-1, 0)
|
cpu = self.wvm.getCPUStats(-1, 0)
|
||||||
if isinstance(cpu, dict):
|
if isinstance(cpu, dict):
|
||||||
for num in range(2):
|
for num in range(2):
|
||||||
idle = self.wvm.getCPUStats(-1, 0)['idle']
|
idle = self.wvm.getCPUStats(-1, 0)["idle"]
|
||||||
total = sum(self.wvm.getCPUStats(-1, 0).values())
|
total = sum(self.wvm.getCPUStats(-1, 0).values())
|
||||||
diff_idle = idle - prev_idle
|
diff_idle = idle - prev_idle
|
||||||
diff_total = total - prev_total
|
diff_total = total - prev_total
|
||||||
|
@ -51,8 +50,8 @@ class wvmHostDetails(wvmConnect):
|
||||||
if diff_usage < 0:
|
if diff_usage < 0:
|
||||||
diff_usage = 0
|
diff_usage = 0
|
||||||
else:
|
else:
|
||||||
return {'usage': None}
|
return {"usage": None}
|
||||||
return {'usage': diff_usage}
|
return {"usage": diff_usage}
|
||||||
|
|
||||||
def get_node_info(self):
|
def get_node_info(self):
|
||||||
"""
|
"""
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
from libvirt import VIR_INTERFACE_XML_INACTIVE
|
|
||||||
from vrtManager.connection import wvmConnect
|
|
||||||
from vrtManager import util
|
|
||||||
|
|
||||||
|
from libvirt import VIR_INTERFACE_XML_INACTIVE
|
||||||
|
from vrtManager import util
|
||||||
|
from vrtManager.connection import wvmConnect
|
||||||
|
|
||||||
|
|
||||||
class wvmInterfaces(wvmConnect):
|
class wvmInterfaces(wvmConnect):
|
||||||
|
@ -12,36 +12,37 @@ class wvmInterfaces(wvmConnect):
|
||||||
mac = iface.MACString()
|
mac = iface.MACString()
|
||||||
itype = util.get_xml_path(xml, "/interface/@type")
|
itype = util.get_xml_path(xml, "/interface/@type")
|
||||||
state = iface.isActive()
|
state = iface.isActive()
|
||||||
return {'name': name, 'type': itype, 'state': state, 'mac': mac}
|
return {"name": name, "type": itype, "state": state, "mac": mac}
|
||||||
|
|
||||||
def define_iface(self, xml, flag=0):
|
def define_iface(self, xml, flag=0):
|
||||||
self.wvm.interfaceDefineXML(xml, flag)
|
self.wvm.interfaceDefineXML(xml, flag)
|
||||||
|
|
||||||
def create_iface(self, name, itype, mode, netdev, ipv4_type, ipv4_addr, ipv4_gw,
|
def create_iface(
|
||||||
ipv6_type, ipv6_addr, ipv6_gw, stp, delay):
|
self, name, itype, mode, netdev, ipv4_type, ipv4_addr, ipv4_gw, ipv6_type, ipv6_addr, ipv6_gw, stp, delay
|
||||||
|
):
|
||||||
xml = f"""<interface type='{itype}' name='{name}'>
|
xml = f"""<interface type='{itype}' name='{name}'>
|
||||||
<start mode='{mode}'/>"""
|
<start mode='{mode}'/>"""
|
||||||
if ipv4_type == 'dhcp':
|
if ipv4_type == "dhcp":
|
||||||
xml += """<protocol family='ipv4'>
|
xml += """<protocol family='ipv4'>
|
||||||
<dhcp/>
|
<dhcp/>
|
||||||
</protocol>"""
|
</protocol>"""
|
||||||
if ipv4_type == 'static':
|
if ipv4_type == "static":
|
||||||
address, prefix = ipv4_addr.split('/')
|
address, prefix = ipv4_addr.split("/")
|
||||||
xml += f"""<protocol family='ipv4'>
|
xml += f"""<protocol family='ipv4'>
|
||||||
<ip address='{address}' prefix='{prefix}'/>
|
<ip address='{address}' prefix='{prefix}'/>
|
||||||
<route gateway='{ipv4_gw}'/>
|
<route gateway='{ipv4_gw}'/>
|
||||||
</protocol>"""
|
</protocol>"""
|
||||||
if ipv6_type == 'dhcp':
|
if ipv6_type == "dhcp":
|
||||||
xml += """<protocol family='ipv6'>
|
xml += """<protocol family='ipv6'>
|
||||||
<dhcp/>
|
<dhcp/>
|
||||||
</protocol>"""
|
</protocol>"""
|
||||||
if ipv6_type == 'static':
|
if ipv6_type == "static":
|
||||||
address, prefix = ipv6_addr.split('/')
|
address, prefix = ipv6_addr.split("/")
|
||||||
xml += f"""<protocol family='ipv6'>
|
xml += f"""<protocol family='ipv6'>
|
||||||
<ip address='{address}' prefix='{prefix}'/>
|
<ip address='{address}' prefix='{prefix}'/>
|
||||||
<route gateway='{ipv6_gw}'/>
|
<route gateway='{ipv6_gw}'/>
|
||||||
</protocol>"""
|
</protocol>"""
|
||||||
if itype == 'bridge':
|
if itype == "bridge":
|
||||||
xml += f"""<bridge stp='{stp}' delay='{delay}'>
|
xml += f"""<bridge stp='{stp}' delay='{delay}'>
|
||||||
<interface name='{netdev}' type='ethernet'/>
|
<interface name='{netdev}' type='ethernet'/>
|
||||||
</bridge>"""
|
</bridge>"""
|
||||||
|
@ -85,9 +86,9 @@ class wvmInterface(wvmConnect):
|
||||||
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
|
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
|
||||||
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv4']/ip/@address")
|
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv4']/ip/@address")
|
||||||
if ipaddr:
|
if ipaddr:
|
||||||
return 'static'
|
return "static"
|
||||||
else:
|
else:
|
||||||
return 'dhcp'
|
return "dhcp"
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -98,16 +99,16 @@ class wvmInterface(wvmConnect):
|
||||||
if not int_ipv4_ip or not int_ipv4_mask:
|
if not int_ipv4_ip or not int_ipv4_mask:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return int_ipv4_ip + '/' + int_ipv4_mask
|
return int_ipv4_ip + "/" + int_ipv4_mask
|
||||||
|
|
||||||
def get_ipv6_type(self):
|
def get_ipv6_type(self):
|
||||||
try:
|
try:
|
||||||
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
|
xml = self._XMLDesc(VIR_INTERFACE_XML_INACTIVE)
|
||||||
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv6']/ip/@address")
|
ipaddr = util.get_xml_path(xml, "/interface/protocol[@family='ipv6']/ip/@address")
|
||||||
if ipaddr:
|
if ipaddr:
|
||||||
return 'static'
|
return "static"
|
||||||
else:
|
else:
|
||||||
return 'dhcp'
|
return "dhcp"
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -118,15 +119,15 @@ class wvmInterface(wvmConnect):
|
||||||
if not int_ipv6_ip or not int_ipv6_mask:
|
if not int_ipv6_ip or not int_ipv6_mask:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return int_ipv6_ip + '/' + int_ipv6_mask
|
return int_ipv6_ip + "/" + int_ipv6_mask
|
||||||
|
|
||||||
def get_bridge(self):
|
def get_bridge(self):
|
||||||
bridge = None
|
bridge = None
|
||||||
if self.get_type() == 'bridge':
|
if self.get_type() == "bridge":
|
||||||
bridge = util.get_xml_path(self._XMLDesc(), "/interface/bridge/interface/@name")
|
bridge = util.get_xml_path(self._XMLDesc(), "/interface/bridge/interface/@name")
|
||||||
for iface in self.get_bridge_slave_ifaces():
|
for iface in self.get_bridge_slave_ifaces():
|
||||||
if iface.get('state') == 'up' and iface.get('speed') is not 'unknown':
|
if iface.get("state") == "up" and iface.get("speed") != "unknown":
|
||||||
bridge = iface.get('name')
|
bridge = iface.get("name")
|
||||||
return bridge
|
return bridge
|
||||||
return bridge
|
return bridge
|
||||||
else:
|
else:
|
||||||
|
@ -134,20 +135,20 @@ class wvmInterface(wvmConnect):
|
||||||
|
|
||||||
def get_bridge_slave_ifaces(self):
|
def get_bridge_slave_ifaces(self):
|
||||||
ifaces = list()
|
ifaces = list()
|
||||||
if self.get_type() == 'bridge':
|
if self.get_type() == "bridge":
|
||||||
tree = ElementTree.fromstring(self._XMLDesc())
|
tree = ElementTree.fromstring(self._XMLDesc())
|
||||||
for iface in tree.findall("./bridge/"):
|
for iface in tree.findall("./bridge/"):
|
||||||
address = state = speed = None
|
address = state = speed = None
|
||||||
name = iface.get('name')
|
name = iface.get("name")
|
||||||
if_type = iface.get('type')
|
if_type = iface.get("type")
|
||||||
link = iface.find('link')
|
link = iface.find("link")
|
||||||
if link is not None:
|
if link is not None:
|
||||||
state = link.get('state')
|
state = link.get("state")
|
||||||
speed = link.get('speed')
|
speed = link.get("speed")
|
||||||
mac = iface.find('mac')
|
mac = iface.find("mac")
|
||||||
if mac is not None:
|
if mac is not None:
|
||||||
address = mac.get('address')
|
address = mac.get("address")
|
||||||
ifaces.append({'name': name, 'type': if_type, 'state': state, 'speed': speed, 'mac': address})
|
ifaces.append({"name": name, "type": if_type, "state": state, "speed": speed, "mac": address})
|
||||||
return ifaces
|
return ifaces
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
|
from libvirt import (
|
||||||
|
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_LIVE,
|
||||||
|
VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
|
||||||
|
VIR_NETWORK_UPDATE_COMMAND_DELETE,
|
||||||
|
VIR_NETWORK_UPDATE_COMMAND_MODIFY, libvirtError)
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from libvirt import libvirtError
|
|
||||||
from libvirt import VIR_NETWORK_SECTION_IP_DHCP_HOST
|
|
||||||
from libvirt import VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_UPDATE_COMMAND_MODIFY
|
|
||||||
from libvirt import VIR_NETWORK_UPDATE_AFFECT_LIVE, VIR_NETWORK_UPDATE_AFFECT_CONFIG
|
|
||||||
from vrtManager import util
|
from vrtManager import util
|
||||||
from vrtManager.IPy import IP
|
|
||||||
from vrtManager.connection import wvmConnect
|
from vrtManager.connection import wvmConnect
|
||||||
|
from vrtManager.IPy import IP
|
||||||
|
|
||||||
|
|
||||||
def network_size(subnet, dhcp=None):
|
def network_size(subnet, dhcp=None):
|
||||||
"""
|
"""
|
||||||
|
@ -17,7 +21,7 @@ def network_size(subnet, dhcp=None):
|
||||||
if addr.version() == 4:
|
if addr.version() == 4:
|
||||||
dhcp_pool = [addr[2].strCompressed(), addr[addr.len() - 2].strCompressed()]
|
dhcp_pool = [addr[2].strCompressed(), addr[addr.len() - 2].strCompressed()]
|
||||||
if addr.version() == 6:
|
if addr.version() == 6:
|
||||||
mask = mask.lstrip('/') if '/' in mask else mask
|
mask = mask.lstrip("/") if "/" in mask else mask
|
||||||
dhcp_pool = [IP(addr[0].strCompressed() + hex(256)), IP(addr[0].strCompressed() + hex(512 - 1))]
|
dhcp_pool = [IP(addr[0].strCompressed() + hex(256)), IP(addr[0].strCompressed() + hex(512 - 1))]
|
||||||
if dhcp:
|
if dhcp:
|
||||||
return gateway, mask, dhcp_pool
|
return gateway, mask, dhcp_pool
|
||||||
|
@ -26,7 +30,6 @@ def network_size(subnet, dhcp=None):
|
||||||
|
|
||||||
|
|
||||||
class wvmNetworks(wvmConnect):
|
class wvmNetworks(wvmConnect):
|
||||||
|
|
||||||
def get_networks_info(self):
|
def get_networks_info(self):
|
||||||
get_networks = self.get_networks()
|
get_networks = self.get_networks()
|
||||||
networks = []
|
networks = []
|
||||||
|
@ -39,44 +42,55 @@ class wvmNetworks(wvmConnect):
|
||||||
net_bridge = util.get_xml_path(net.XMLDesc(0), "/network/forward/interface/@dev")
|
net_bridge = util.get_xml_path(net.XMLDesc(0), "/network/forward/interface/@dev")
|
||||||
|
|
||||||
net_forward = util.get_xml_path(net.XMLDesc(0), "/network/forward/@mode")
|
net_forward = util.get_xml_path(net.XMLDesc(0), "/network/forward/@mode")
|
||||||
networks.append({'name': network, 'status': net_status,
|
networks.append({"name": network, "status": net_status, "device": net_bridge, "forward": net_forward})
|
||||||
'device': net_bridge, 'forward': net_forward})
|
|
||||||
return networks
|
return networks
|
||||||
|
|
||||||
def define_network(self, xml):
|
def define_network(self, xml):
|
||||||
self.wvm.networkDefineXML(xml)
|
self.wvm.networkDefineXML(xml)
|
||||||
|
|
||||||
def create_network(self, name, forward,
|
def create_network(
|
||||||
ipv4, gateway, mask, dhcp4,
|
self,
|
||||||
ipv6, gateway6, prefix6, dhcp6,
|
name,
|
||||||
bridge, openvswitch, fixed=False):
|
forward,
|
||||||
|
ipv4,
|
||||||
|
gateway,
|
||||||
|
mask,
|
||||||
|
dhcp4,
|
||||||
|
ipv6,
|
||||||
|
gateway6,
|
||||||
|
prefix6,
|
||||||
|
dhcp6,
|
||||||
|
bridge,
|
||||||
|
openvswitch,
|
||||||
|
fixed=False,
|
||||||
|
):
|
||||||
xml = f"""
|
xml = f"""
|
||||||
<network>
|
<network>
|
||||||
<name>{name}</name>"""
|
<name>{name}</name>"""
|
||||||
if forward in ['nat', 'route', 'bridge']:
|
if forward in ["nat", "route", "bridge"]:
|
||||||
xml += f"""<forward mode='{forward}'/>"""
|
xml += f"""<forward mode='{forward}'/>"""
|
||||||
if forward == 'macvtap':
|
if forward == "macvtap":
|
||||||
xml += f"""<forward mode='bridge'>
|
xml += f"""<forward mode='bridge'>
|
||||||
<interface dev='{bridge}'/>
|
<interface dev='{bridge}'/>
|
||||||
</forward>"""
|
</forward>"""
|
||||||
else:
|
else:
|
||||||
xml += """<bridge """
|
xml += """<bridge """
|
||||||
if forward in ['nat', 'route', 'none']:
|
if forward in ["nat", "route", "none"]:
|
||||||
xml += """stp='on' delay='0'"""
|
xml += """stp='on' delay='0'"""
|
||||||
if forward == 'bridge':
|
if forward == "bridge":
|
||||||
xml += f"""name='{bridge}'"""
|
xml += f"""name='{bridge}'"""
|
||||||
xml += """/>"""
|
xml += """/>"""
|
||||||
if openvswitch is True:
|
if openvswitch is True:
|
||||||
xml += """<virtualport type='openvswitch'/>"""
|
xml += """<virtualport type='openvswitch'/>"""
|
||||||
if forward not in ['bridge', 'macvtap']:
|
if forward not in ["bridge", "macvtap"]:
|
||||||
if ipv4:
|
if ipv4:
|
||||||
xml += f"""<ip address='{gateway}' netmask='{mask}'>"""
|
xml += f"""<ip address='{gateway}' netmask='{mask}'>"""
|
||||||
if dhcp4:
|
if dhcp4:
|
||||||
xml += f"""<dhcp>
|
xml += f"""<dhcp>
|
||||||
<range start='{dhcp4[0]}' end='{dhcp4[1]}' />"""
|
<range start='{dhcp4[0]}' end='{dhcp4[1]}' />"""
|
||||||
if fixed:
|
if fixed:
|
||||||
fist_oct = int(dhcp4[0].strip().split('.')[3])
|
fist_oct = int(dhcp4[0].strip().split(".")[3])
|
||||||
last_oct = int(dhcp4[1].strip().split('.')[3])
|
last_oct = int(dhcp4[1].strip().split(".")[3])
|
||||||
for ip in range(fist_oct, last_oct + 1):
|
for ip in range(fist_oct, last_oct + 1):
|
||||||
xml += f"""<host mac='{util.randomMAC()}' ip='{gateway[:-2]}.{ip}' />"""
|
xml += f"""<host mac='{util.randomMAC()}' ip='{gateway[:-2]}.{ip}' />"""
|
||||||
xml += """</dhcp>"""
|
xml += """</dhcp>"""
|
||||||
|
@ -144,23 +158,23 @@ class wvmNetwork(wvmConnect):
|
||||||
if util.get_xml_path(xml, "/network/ip") is None:
|
if util.get_xml_path(xml, "/network/ip") is None:
|
||||||
return ip_networks
|
return ip_networks
|
||||||
tree = etree.fromstring(xml)
|
tree = etree.fromstring(xml)
|
||||||
ips = tree.findall('.ip')
|
ips = tree.findall(".ip")
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
address_str = ip.get('address')
|
address_str = ip.get("address")
|
||||||
netmask_str = ip.get('netmask')
|
netmask_str = ip.get("netmask")
|
||||||
prefix = ip.get('prefix')
|
prefix = ip.get("prefix")
|
||||||
family = ip.get('family', 'ipv4')
|
family = ip.get("family", "ipv4")
|
||||||
base = 32 if family == 'ipv4' else 128
|
base = 32 if family == "ipv4" else 128
|
||||||
if prefix:
|
if prefix:
|
||||||
prefix = int(prefix)
|
prefix = int(prefix)
|
||||||
binstr = ((prefix * "1") + ((base - prefix) * "0"))
|
binstr = (prefix * "1") + ((base - prefix) * "0")
|
||||||
netmask_str = str(IP(int(binstr, base=2)))
|
netmask_str = str(IP(int(binstr, base=2)))
|
||||||
|
|
||||||
if netmask_str:
|
if netmask_str:
|
||||||
netmask = IP(netmask_str)
|
netmask = IP(netmask_str)
|
||||||
gateway = IP(address_str)
|
gateway = IP(address_str)
|
||||||
network = IP(gateway.int() & netmask.int())
|
network = IP(gateway.int() & netmask.int())
|
||||||
netmask_str = netmask_str if family == 'ipv4' else str(prefix)
|
netmask_str = netmask_str if family == "ipv4" else str(prefix)
|
||||||
ret = IP(str(network) + "/" + netmask_str)
|
ret = IP(str(network) + "/" + netmask_str)
|
||||||
else:
|
else:
|
||||||
ret = IP(str(address_str))
|
ret = IP(str(address_str))
|
||||||
|
@ -178,12 +192,12 @@ class wvmNetwork(wvmConnect):
|
||||||
forward_dev = util.get_xml_path(xml, "/network/forward/@dev")
|
forward_dev = util.get_xml_path(xml, "/network/forward/@dev")
|
||||||
return [fw, forward_dev]
|
return [fw, forward_dev]
|
||||||
|
|
||||||
def get_dhcp_range(self, family='ipv4'):
|
def get_dhcp_range(self, family="ipv4"):
|
||||||
xml = self._XMLDesc(0)
|
xml = self._XMLDesc(0)
|
||||||
if family == 'ipv4':
|
if family == "ipv4":
|
||||||
dhcpstart = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@start")
|
dhcpstart = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@start")
|
||||||
dhcpend = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@end")
|
dhcpend = util.get_xml_path(xml, "/network/ip[not(@family='ipv6')]/dhcp/range[1]/@end")
|
||||||
if family == 'ipv6':
|
if family == "ipv6":
|
||||||
dhcpstart = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@start")
|
dhcpstart = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@start")
|
||||||
dhcpend = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@end")
|
dhcpend = util.get_xml_path(xml, "/network/ip[@family='ipv6']/dhcp/range[1]/@end")
|
||||||
|
|
||||||
|
@ -192,13 +206,13 @@ class wvmNetwork(wvmConnect):
|
||||||
|
|
||||||
return [IP(dhcpstart), IP(dhcpend)]
|
return [IP(dhcpstart), IP(dhcpend)]
|
||||||
|
|
||||||
def get_dhcp_range_start(self, family='ipv4'):
|
def get_dhcp_range_start(self, family="ipv4"):
|
||||||
dhcp = self.get_dhcp_range(family)
|
dhcp = self.get_dhcp_range(family)
|
||||||
if not dhcp:
|
if not dhcp:
|
||||||
return None
|
return None
|
||||||
return dhcp[0]
|
return dhcp[0]
|
||||||
|
|
||||||
def get_dhcp_range_end(self, family='ipv4'):
|
def get_dhcp_range_end(self, family="ipv4"):
|
||||||
dhcp = self.get_dhcp_range(family)
|
dhcp = self.get_dhcp_range(family)
|
||||||
if not dhcp:
|
if not dhcp:
|
||||||
return None
|
return None
|
||||||
|
@ -211,74 +225,77 @@ class wvmNetwork(wvmConnect):
|
||||||
return True
|
return True
|
||||||
return bool(util.get_xml_path(xml, "/network/ip/dhcp/bootp/@file"))
|
return bool(util.get_xml_path(xml, "/network/ip/dhcp/bootp/@file"))
|
||||||
|
|
||||||
def get_dhcp_host_addr(self, family='ipv4'):
|
def get_dhcp_host_addr(self, family="ipv4"):
|
||||||
result = list()
|
result = list()
|
||||||
tree = etree.fromstring(self._XMLDesc(0))
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
|
|
||||||
for ipdhcp in tree.findall("./ip"):
|
for ipdhcp in tree.findall("./ip"):
|
||||||
if family == 'ipv4':
|
if family == "ipv4":
|
||||||
if ipdhcp.get('family') is None:
|
if ipdhcp.get("family") is None:
|
||||||
hosts = ipdhcp.findall('./dhcp/host')
|
hosts = ipdhcp.findall("./dhcp/host")
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
host_ip = host.get('ip')
|
host_ip = host.get("ip")
|
||||||
mac = host.get('mac')
|
mac = host.get("mac")
|
||||||
name = host.get('name', '')
|
name = host.get("name", "")
|
||||||
result.append({'ip': host_ip, 'mac': mac, 'name': name})
|
result.append({"ip": host_ip, "mac": mac, "name": name})
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
if family == 'ipv6':
|
if family == "ipv6":
|
||||||
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
|
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
host_ip = host.get('ip')
|
host_ip = host.get("ip")
|
||||||
host_id = host.get('id')
|
host_id = host.get("id")
|
||||||
name = host.get('name', '')
|
name = host.get("name", "")
|
||||||
result.append({'ip': host_ip, 'id': host_id, 'name': name})
|
result.append({"ip": host_ip, "id": host_id, "name": name})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def modify_dhcp_range(self, range_start, range_end, family='ipv4'):
|
def modify_dhcp_range(self, range_start, range_end, family="ipv4"):
|
||||||
if not self.is_active():
|
if not self.is_active():
|
||||||
tree = etree.fromstring(self._XMLDesc(0))
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
if family == 'ipv4':
|
if family == "ipv4":
|
||||||
dhcp_range = tree.xpath("./ip[not(@family='ipv6')]/dhcp/range")
|
dhcp_range = tree.xpath("./ip[not(@family='ipv6')]/dhcp/range")
|
||||||
if family == 'ipv6':
|
if family == "ipv6":
|
||||||
dhcp_range = tree.xpath("./ip[@family='ipv6']/dhcp/range")
|
dhcp_range = tree.xpath("./ip[@family='ipv6']/dhcp/range")
|
||||||
dhcp_range[0].set('start', range_start)
|
dhcp_range[0].set("start", range_start)
|
||||||
dhcp_range[0].set('end', range_end)
|
dhcp_range[0].set("end", range_end)
|
||||||
self.wvm.networkDefineXML(etree.tostring(tree).decode())
|
self.wvm.networkDefineXML(etree.tostring(tree).decode())
|
||||||
|
|
||||||
def delete_fixed_address(self, ip, family='ipv4'):
|
def delete_fixed_address(self, ip, family="ipv4"):
|
||||||
tree = etree.fromstring(self._XMLDesc(0))
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
if family == 'ipv4':
|
if family == "ipv4":
|
||||||
hosts = tree.xpath("/network/ip[not(@family='ipv6')]/dhcp/host")
|
hosts = tree.xpath("/network/ip[not(@family='ipv6')]/dhcp/host")
|
||||||
parent_index = self.parent_count - 2
|
parent_index = self.parent_count - 2
|
||||||
if family == 'ipv6':
|
if family == "ipv6":
|
||||||
hosts = tree.xpath("/network/ip[@family='ipv6']/dhcp/host")
|
hosts = tree.xpath("/network/ip[@family='ipv6']/dhcp/host")
|
||||||
parent_index = self.parent_count - 1
|
parent_index = self.parent_count - 1
|
||||||
for h in hosts:
|
for h in hosts:
|
||||||
if h.get('ip') == ip:
|
if h.get("ip") == ip:
|
||||||
if family == 'ipv4':
|
if family == "ipv4":
|
||||||
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get('mac'), h.get('name'), ip)
|
new_xml = '<host mac="{}" name="{}" ip="{}"/>'.format(h.get("mac"), h.get("name"), ip)
|
||||||
if family == 'ipv6':
|
if family == "ipv6":
|
||||||
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get('id'), h.get('name'), ip)
|
new_xml = '<host id="{}" name="{}" ip="{}"/>'.format(h.get("id"), h.get("name"), ip)
|
||||||
|
|
||||||
self.update(VIR_NETWORK_UPDATE_COMMAND_DELETE, VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
self.update(
|
||||||
new_xml,
|
VIR_NETWORK_UPDATE_COMMAND_DELETE,
|
||||||
parent_index,
|
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
new_xml,
|
||||||
|
parent_index,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
def modify_fixed_address(self, name, address, mac_duid, family='ipv4'):
|
def modify_fixed_address(self, name, address, mac_duid, family="ipv4"):
|
||||||
tree = etree.fromstring(self._XMLDesc(0))
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
if family == 'ipv4':
|
if family == "ipv4":
|
||||||
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
|
new_xml = '<host mac="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
|
||||||
hosts = tree.xpath("./ip[not(@family='ipv6')]/dhcp/host")
|
hosts = tree.xpath("./ip[not(@family='ipv6')]/dhcp/host")
|
||||||
compare_var = 'mac'
|
compare_var = "mac"
|
||||||
parent_index = self.parent_count - 2
|
parent_index = self.parent_count - 2
|
||||||
if family == 'ipv6':
|
if family == "ipv6":
|
||||||
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else '', IP(address))
|
new_xml = '<host id="{}" {} ip="{}"/>'.format(mac_duid, 'name="' + name + '"' if name else "", IP(address))
|
||||||
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
|
hosts = tree.xpath("./ip[@family='ipv6']/dhcp/host")
|
||||||
compare_var = 'id'
|
compare_var = "id"
|
||||||
parent_index = self.parent_count - 1
|
parent_index = self.parent_count - 1
|
||||||
new_host_xml = etree.fromstring(new_xml)
|
new_host_xml = etree.fromstring(new_xml)
|
||||||
|
|
||||||
|
@ -288,17 +305,25 @@ class wvmNetwork(wvmConnect):
|
||||||
host = h
|
host = h
|
||||||
break
|
break
|
||||||
if host is None:
|
if host is None:
|
||||||
self.update(VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
|
self.update(
|
||||||
parent_index,
|
VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
|
||||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||||
|
new_xml,
|
||||||
|
parent_index,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# change the host
|
# change the host
|
||||||
if host.get('name') == new_host_xml.get('name') and host.get('ip') == new_host_xml.get('ip'):
|
if host.get("name") == new_host_xml.get("name") and host.get("ip") == new_host_xml.get("ip"):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.update(VIR_NETWORK_UPDATE_COMMAND_MODIFY, VIR_NETWORK_SECTION_IP_DHCP_HOST, new_xml,
|
self.update(
|
||||||
parent_index,
|
VIR_NETWORK_UPDATE_COMMAND_MODIFY,
|
||||||
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG)
|
VIR_NETWORK_SECTION_IP_DHCP_HOST,
|
||||||
|
new_xml,
|
||||||
|
parent_index,
|
||||||
|
VIR_NETWORK_UPDATE_AFFECT_LIVE | VIR_NETWORK_UPDATE_AFFECT_CONFIG,
|
||||||
|
)
|
||||||
|
|
||||||
def get_qos(self):
|
def get_qos(self):
|
||||||
qos_values = dict()
|
qos_values = dict()
|
||||||
|
@ -307,19 +332,19 @@ class wvmNetwork(wvmConnect):
|
||||||
if qos:
|
if qos:
|
||||||
qos = qos[0]
|
qos = qos[0]
|
||||||
|
|
||||||
in_qos = qos.find('inbound')
|
in_qos = qos.find("inbound")
|
||||||
if in_qos is not None:
|
if in_qos is not None:
|
||||||
in_av = in_qos.get('average')
|
in_av = in_qos.get("average")
|
||||||
in_peak = in_qos.get('peak')
|
in_peak = in_qos.get("peak")
|
||||||
in_burst = in_qos.get('burst')
|
in_burst = in_qos.get("burst")
|
||||||
qos_values['inbound'] = {'average': in_av, 'peak': in_peak, 'burst': in_burst}
|
qos_values["inbound"] = {"average": in_av, "peak": in_peak, "burst": in_burst}
|
||||||
|
|
||||||
out_qos = qos.find('outbound')
|
out_qos = qos.find("outbound")
|
||||||
if out_qos is not None:
|
if out_qos is not None:
|
||||||
out_av = out_qos.get('average')
|
out_av = out_qos.get("average")
|
||||||
out_peak = out_qos.get('peak')
|
out_peak = out_qos.get("peak")
|
||||||
out_burst = out_qos.get('burst')
|
out_burst = out_qos.get("burst")
|
||||||
qos_values['outbound'] = {'average': out_av, 'peak': out_peak, 'burst': out_burst}
|
qos_values["outbound"] = {"average": out_av, "peak": out_peak, "burst": out_burst}
|
||||||
return qos_values
|
return qos_values
|
||||||
|
|
||||||
def set_qos(self, direction, average, peak, burst):
|
def set_qos(self, direction, average, peak, burst):
|
||||||
|
@ -328,7 +353,7 @@ class wvmNetwork(wvmConnect):
|
||||||
elif direction == "outbound":
|
elif direction == "outbound":
|
||||||
xml = f"<outbound average='{average}' peak='{peak}' burst='{burst}'/>"
|
xml = f"<outbound average='{average}' peak='{peak}' burst='{burst}'/>"
|
||||||
else:
|
else:
|
||||||
raise Exception('Direction must be inbound or outbound')
|
raise Exception("Direction must be inbound or outbound")
|
||||||
|
|
||||||
tree = etree.fromstring(self._XMLDesc(0))
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
|
|
||||||
|
@ -363,7 +388,7 @@ class wvmNetwork(wvmConnect):
|
||||||
self.leases = self.net.DHCPLeases()
|
self.leases = self.net.DHCPLeases()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.leases = []
|
self.leases = []
|
||||||
raise f"Error getting {self} DHCP leases: {e}"
|
raise "Error getting {} DHCP leases: {}".format(self, e)
|
||||||
|
|
||||||
def get_dhcp_leases(self):
|
def get_dhcp_leases(self):
|
||||||
if self.leases is None:
|
if self.leases is None:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
from vrtManager.connection import wvmConnect
|
from vrtManager.connection import wvmConnect
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ class wvmNWFilters(wvmConnect):
|
||||||
nwfilter = self.get_nwfilter(name)
|
nwfilter = self.get_nwfilter(name)
|
||||||
xml = nwfilter.XMLDesc(0)
|
xml = nwfilter.XMLDesc(0)
|
||||||
uuid = nwfilter.UUIDString()
|
uuid = nwfilter.UUIDString()
|
||||||
return {'name': name, 'uuid': uuid, 'xml': xml}
|
return {"name": name, "uuid": uuid, "xml": xml}
|
||||||
|
|
||||||
def create_nwfilter(self, xml):
|
def create_nwfilter(self, xml):
|
||||||
self.wvm.nwfilterDefineXML(xml)
|
self.wvm.nwfilterDefineXML(xml)
|
||||||
|
@ -16,8 +17,8 @@ class wvmNWFilters(wvmConnect):
|
||||||
nwfilter = self.get_nwfilter(name)
|
nwfilter = self.get_nwfilter(name)
|
||||||
if nwfilter:
|
if nwfilter:
|
||||||
tree = ElementTree.fromstring(nwfilter.XMLDesc(0))
|
tree = ElementTree.fromstring(nwfilter.XMLDesc(0))
|
||||||
tree.set('name', cln_name)
|
tree.set("name", cln_name)
|
||||||
uuid = tree.find('uuid')
|
uuid = tree.find("uuid")
|
||||||
tree.remove(uuid)
|
tree.remove(uuid)
|
||||||
self.create_nwfilter(ElementTree.tostring(tree).decode())
|
self.create_nwfilter(ElementTree.tostring(tree).decode())
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ class wvmNWFilter(wvmConnect):
|
||||||
|
|
||||||
def get_xml(self):
|
def get_xml(self):
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
uuid = tree.find('uuid')
|
uuid = tree.find("uuid")
|
||||||
tree.remove(uuid)
|
tree.remove(uuid)
|
||||||
return ElementTree.tostring(tree).decode()
|
return ElementTree.tostring(tree).decode()
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ class wvmNWFilter(wvmConnect):
|
||||||
refs = []
|
refs = []
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
for ref in tree.findall("./filterref"):
|
for ref in tree.findall("./filterref"):
|
||||||
refs.append(ref.get('filter'))
|
refs.append(ref.get("filter"))
|
||||||
return refs
|
return refs
|
||||||
|
|
||||||
def get_rules(self):
|
def get_rules(self):
|
||||||
|
@ -57,10 +58,10 @@ class wvmNWFilter(wvmConnect):
|
||||||
|
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
for r in tree.findall("./rule"):
|
for r in tree.findall("./rule"):
|
||||||
rule_action = r.get('action')
|
rule_action = r.get("action")
|
||||||
rule_direction = r.get('direction')
|
rule_direction = r.get("direction")
|
||||||
rule_priority = r.get('priority')
|
rule_priority = r.get("priority")
|
||||||
rule_statematch = r.get('statematch')
|
rule_statematch = r.get("statematch")
|
||||||
|
|
||||||
rule_directives = r.find("./")
|
rule_directives = r.find("./")
|
||||||
if rule_directives is not None:
|
if rule_directives is not None:
|
||||||
|
@ -71,7 +72,7 @@ class wvmNWFilter(wvmConnect):
|
||||||
"direction": rule_direction,
|
"direction": rule_direction,
|
||||||
"priority": rule_priority,
|
"priority": rule_priority,
|
||||||
"statematch": rule_statematch,
|
"statematch": rule_statematch,
|
||||||
"directives": rule_directives
|
"directives": rule_directives,
|
||||||
}
|
}
|
||||||
|
|
||||||
rules.append(rule_info)
|
rules.append(rule_info)
|
||||||
|
@ -81,7 +82,7 @@ class wvmNWFilter(wvmConnect):
|
||||||
def delete_ref(self, name):
|
def delete_ref(self, name):
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
for ref in tree.findall("./filterref"):
|
for ref in tree.findall("./filterref"):
|
||||||
if name == ref.get('filter'):
|
if name == ref.get("filter"):
|
||||||
tree.remove(ref)
|
tree.remove(ref)
|
||||||
break
|
break
|
||||||
return ElementTree.tostring(tree).decode()
|
return ElementTree.tostring(tree).decode()
|
||||||
|
@ -89,7 +90,9 @@ class wvmNWFilter(wvmConnect):
|
||||||
def delete_rule(self, action, direction, priority):
|
def delete_rule(self, action, direction, priority):
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
|
||||||
rule_tree = tree.findall("./rule[@action='%s'][@direction='%s'][@priority='%s']" % (action, direction, priority))
|
rule_tree = tree.findall(
|
||||||
|
"./rule[@action='%s'][@direction='%s'][@priority='%s']" % (action, direction, priority)
|
||||||
|
)
|
||||||
if rule_tree:
|
if rule_tree:
|
||||||
tree.remove(rule_tree[0])
|
tree.remove(rule_tree[0])
|
||||||
|
|
||||||
|
@ -98,7 +101,7 @@ class wvmNWFilter(wvmConnect):
|
||||||
def add_ref(self, name):
|
def add_ref(self, name):
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
element = ElementTree.Element("filterref")
|
element = ElementTree.Element("filterref")
|
||||||
element.attrib['filter'] = name
|
element.attrib["filter"] = name
|
||||||
tree.append(element)
|
tree.append(element)
|
||||||
return ElementTree.tostring(tree).decode()
|
return ElementTree.tostring(tree).decode()
|
||||||
|
|
||||||
|
@ -106,19 +109,21 @@ class wvmNWFilter(wvmConnect):
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
rule = ElementTree.fromstring(xml)
|
rule = ElementTree.fromstring(xml)
|
||||||
|
|
||||||
rule_action = rule.get('action')
|
rule_action = rule.get("action")
|
||||||
rule_direction = rule.get('direction')
|
rule_direction = rule.get("direction")
|
||||||
rule_priority = rule.get('priority')
|
rule_priority = rule.get("priority")
|
||||||
rule_directives = rule.find("./")
|
rule_directives = rule.find("./")
|
||||||
rule_tree = tree.findall("./rule[@action='%s'][@direction='%s'][@priority='%s']" % (rule_action, rule_direction, rule_priority))
|
rule_tree = tree.findall(
|
||||||
|
"./rule[@action='%s'][@direction='%s'][@priority='%s']" % (rule_action, rule_direction, rule_priority)
|
||||||
|
)
|
||||||
|
|
||||||
if rule_tree:
|
if rule_tree:
|
||||||
rule_tree[0].append(rule_directives)
|
rule_tree[0].append(rule_directives)
|
||||||
else:
|
else:
|
||||||
element = ElementTree.Element("rule")
|
element = ElementTree.Element("rule")
|
||||||
element.attrib['action'] = rule_action
|
element.attrib["action"] = rule_action
|
||||||
element.attrib['direction'] = rule_direction
|
element.attrib["direction"] = rule_direction
|
||||||
element.attrib['priority'] = rule_priority
|
element.attrib["priority"] = rule_priority
|
||||||
element.append(rule_directives)
|
element.append(rule_directives)
|
||||||
tree.append(element)
|
tree.append(element)
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,9 @@ found at: http://code.activestate.com/recipes/502283-read-write-lock-class-rlock
|
||||||
|
|
||||||
# Imports
|
# Imports
|
||||||
# -------
|
# -------
|
||||||
|
|
||||||
from threading import Condition, Lock, currentThread
|
from threading import Condition, Lock, currentThread
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
|
|
||||||
# Read write lock
|
# Read write lock
|
||||||
# ---------------
|
# ---------------
|
||||||
|
|
||||||
|
@ -138,9 +136,7 @@ class ReadWriteLock(object):
|
||||||
# else also wants to upgrade, there is no way we can do
|
# else also wants to upgrade, there is no way we can do
|
||||||
# this except if one of us releases all his read locks.
|
# this except if one of us releases all his read locks.
|
||||||
# Signal this to user.
|
# Signal this to user.
|
||||||
raise ValueError(
|
raise ValueError("Inevitable dead lock, denying write lock")
|
||||||
"Inevitable dead lock, denying write lock"
|
|
||||||
)
|
|
||||||
upgradewriter = True
|
upgradewriter = True
|
||||||
self.__upgradewritercount = self.__readers.pop(me)
|
self.__upgradewritercount = self.__readers.pop(me)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from vrtManager.connection import wvmConnect
|
from vrtManager.connection import wvmConnect
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,12 +7,12 @@ class wvmSecrets(wvmConnect):
|
||||||
def create_secret(self, ephemeral, private, secret_type, data):
|
def create_secret(self, ephemeral, private, secret_type, data):
|
||||||
xml = f"""<secret ephemeral='{ephemeral}' private='{private}'>
|
xml = f"""<secret ephemeral='{ephemeral}' private='{private}'>
|
||||||
<usage type='{secret_type}'>"""
|
<usage type='{secret_type}'>"""
|
||||||
if secret_type == 'ceph':
|
if secret_type == "ceph":
|
||||||
xml += f"""<name>{data}</name>"""
|
xml += f"""<name>{data}</name>"""
|
||||||
if secret_type == 'volume':
|
if secret_type == "volume":
|
||||||
xml += f"""<volume>{data}</volume>"""
|
xml += f"""<volume>{data}</volume>"""
|
||||||
if secret_type == 'iscsi':
|
if secret_type == "iscsi":
|
||||||
xml += f"""<target>{data}</target>"""
|
xml += f"""<target>{data}</target>"""
|
||||||
xml += """</usage>
|
xml += """</usage>
|
||||||
</secret>"""
|
</secret>"""
|
||||||
self.wvm.secretDefineXML(xml)
|
self.wvm.secretDefineXML(xml)
|
||||||
|
|
|
@ -16,13 +16,7 @@ class wvmStorages(wvmConnect):
|
||||||
stg_vol = None
|
stg_vol = None
|
||||||
stg_size = stg.info()[1]
|
stg_size = stg.info()[1]
|
||||||
storages.append(
|
storages.append(
|
||||||
{
|
{"name": pool, "status": stg_status, "type": stg_type, "volumes": stg_vol, "size": stg_size}
|
||||||
"name": pool,
|
|
||||||
"status": stg_status,
|
|
||||||
"type": stg_type,
|
|
||||||
"volumes": stg_vol,
|
|
||||||
"size": stg_size
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
return storages
|
return storages
|
||||||
|
|
||||||
|
@ -103,12 +97,7 @@ class wvmStorage(wvmConnect):
|
||||||
return self.pool.name()
|
return self.pool.name()
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
status = [
|
status = ["Not running", "Initializing pool, not available", "Running normally", "Running degraded"]
|
||||||
"Not running",
|
|
||||||
"Initializing pool, not available",
|
|
||||||
"Running normally",
|
|
||||||
"Running degraded"
|
|
||||||
]
|
|
||||||
try:
|
try:
|
||||||
return status[self.pool.info()[0]]
|
return status[self.pool.info()[0]]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -217,12 +206,12 @@ class wvmStorage(wvmConnect):
|
||||||
"name": volname,
|
"name": volname,
|
||||||
"size": self.get_volume_size(volname),
|
"size": self.get_volume_size(volname),
|
||||||
"allocation": self.get_volume_allocation(volname),
|
"allocation": self.get_volume_allocation(volname),
|
||||||
"type": self.get_volume_type(volname)
|
"type": self.get_volume_type(volname),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return vol_list
|
return vol_list
|
||||||
|
|
||||||
def create_volume(self, name, size, vol_fmt='qcow2', metadata=False, disk_owner_uid=0, disk_owner_gid=0):
|
def create_volume(self, name, size, vol_fmt="qcow2", metadata=False, disk_owner_uid=0, disk_owner_gid=0):
|
||||||
size = int(size) * 1073741824
|
size = int(size) * 1073741824
|
||||||
storage_type = self.get_type()
|
storage_type = self.get_type()
|
||||||
alloc = size
|
alloc = size
|
||||||
|
@ -258,7 +247,17 @@ class wvmStorage(wvmConnect):
|
||||||
self._createXML(xml, metadata)
|
self._createXML(xml, metadata)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def clone_volume(self, name, target_file, vol_fmt=None, metadata=False, mode='0644', file_suffix='img', disk_owner_uid=0, disk_owner_gid=0):
|
def clone_volume(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
target_file,
|
||||||
|
vol_fmt=None,
|
||||||
|
metadata=False,
|
||||||
|
mode="0644",
|
||||||
|
file_suffix="img",
|
||||||
|
disk_owner_uid=0,
|
||||||
|
disk_owner_gid=0,
|
||||||
|
):
|
||||||
vol = self.get_volume(name)
|
vol = self.get_volume(name)
|
||||||
if not vol_fmt:
|
if not vol_fmt:
|
||||||
vol_fmt = self.get_volume_type(name)
|
vol_fmt = self.get_volume_type(name)
|
||||||
|
@ -266,10 +265,10 @@ class wvmStorage(wvmConnect):
|
||||||
storage_type = self.get_type()
|
storage_type = self.get_type()
|
||||||
if storage_type == "dir":
|
if storage_type == "dir":
|
||||||
if vol_fmt in ["qcow", "qcow2"]:
|
if vol_fmt in ["qcow", "qcow2"]:
|
||||||
target_file += '.' + vol_fmt
|
target_file += "." + vol_fmt
|
||||||
else:
|
else:
|
||||||
suffix = '.' + file_suffix
|
suffix = "." + file_suffix
|
||||||
target_file += suffix if len(suffix) > 1 else ''
|
target_file += suffix if len(suffix) > 1 else ""
|
||||||
|
|
||||||
xml = f"""
|
xml = f"""
|
||||||
<volume>
|
<volume>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import random
|
import random
|
||||||
import string
|
|
||||||
import re
|
import re
|
||||||
import lxml.etree as etree
|
import string
|
||||||
|
|
||||||
import libvirt
|
import libvirt
|
||||||
|
import lxml.etree as etree
|
||||||
|
|
||||||
|
|
||||||
def is_kvm_available(xml):
|
def is_kvm_available(xml):
|
||||||
|
@ -18,10 +19,8 @@ def randomMAC():
|
||||||
# qemu MAC
|
# qemu MAC
|
||||||
oui = [0x52, 0x54, 0x00]
|
oui = [0x52, 0x54, 0x00]
|
||||||
|
|
||||||
mac = oui + [random.randint(0x00, 0xff),
|
mac = oui + [random.randint(0x00, 0xFF), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]
|
||||||
random.randint(0x00, 0xff),
|
return ":".join(map(lambda x: "%02x" % x, mac))
|
||||||
random.randint(0x00, 0xff)]
|
|
||||||
return ':'.join(map(lambda x: "%02x" % x, mac))
|
|
||||||
|
|
||||||
|
|
||||||
def randomUUID():
|
def randomUUID():
|
||||||
|
@ -29,18 +28,17 @@ def randomUUID():
|
||||||
u = [random.randint(0, 255) for ignore in range(0, 16)]
|
u = [random.randint(0, 255) for ignore in range(0, 16)]
|
||||||
u[6] = (u[6] & 0x0F) | (4 << 4)
|
u[6] = (u[6] & 0x0F) | (4 << 4)
|
||||||
u[8] = (u[8] & 0x3F) | (2 << 6)
|
u[8] = (u[8] & 0x3F) | (2 << 6)
|
||||||
return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
|
return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2, "%02x" * 6]) % tuple(u)
|
||||||
"%02x" * 6]) % tuple(u)
|
|
||||||
|
|
||||||
|
|
||||||
def randomPasswd(length=12, alphabet=string.ascii_letters + string.digits):
|
def randomPasswd(length=12, alphabet=string.ascii_letters + string.digits):
|
||||||
"""Generate a random password"""
|
"""Generate a random password"""
|
||||||
return ''.join([random.choice(alphabet) for i in range(length)])
|
return "".join([random.choice(alphabet) for i in range(length)])
|
||||||
|
|
||||||
|
|
||||||
def get_max_vcpus(conn, type=None):
|
def get_max_vcpus(conn, type=None):
|
||||||
"""@param conn: libvirt connection to poll for max possible vcpus
|
"""@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:
|
if type is None:
|
||||||
type = conn.getType()
|
type = conn.getType()
|
||||||
try:
|
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('"', """)
|
||||||
str = str.replace("<", "<")
|
str = str.replace("<", "<")
|
||||||
str = str.replace(">", ">")
|
str = str.replace(">", ">")
|
||||||
return str
|
return str
|
||||||
|
@ -109,7 +107,7 @@ def get_xpath(doc, path):
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
if isinstance(ret, list):
|
if isinstance(ret, list):
|
||||||
if len(ret) >= 1:
|
if len(ret) >= 1:
|
||||||
if hasattr(ret[0], 'text'):
|
if hasattr(ret[0], "text"):
|
||||||
result = ret[0].text
|
result = ret[0].text
|
||||||
else:
|
else:
|
||||||
result = ret[0]
|
result = ret[0]
|
||||||
|
@ -146,11 +144,11 @@ def validate_uuid(val):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"UUID must be a 32-digit hexadecimal number. It may take "
|
"UUID must be a 32-digit hexadecimal number. It may take "
|
||||||
"the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or may "
|
"the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or may "
|
||||||
"omit hyphens altogether.")
|
"omit hyphens altogether."
|
||||||
|
)
|
||||||
|
|
||||||
else: # UUID had no dashes, so add them in
|
else: # UUID had no dashes, so add them in
|
||||||
val = (val[0:8] + "-" + val[8:12] + "-" + val[12:16] +
|
val = val[0:8] + "-" + val[8:12] + "-" + val[12:16] + "-" + val[16:20] + "-" + val[20:32]
|
||||||
"-" + val[16:20] + "-" + val[20:32])
|
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,7 +161,7 @@ def validate_macaddr(val):
|
||||||
|
|
||||||
form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val)
|
form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val)
|
||||||
if form is None:
|
if form is None:
|
||||||
raise ValueError(f"MAC address must be of the format AA:BB:CC:DD:EE:FF, was {val}")
|
raise ValueError("MAC address must be of the format AA:BB:CC:DD:EE:FF, was {}".format(val))
|
||||||
|
|
||||||
|
|
||||||
# Mapping of UEFI binary names to their associated architectures. We
|
# Mapping of UEFI binary names to their associated architectures. We
|
||||||
|
@ -177,7 +175,8 @@ UEFI_ARCH_PATTERNS = {
|
||||||
r".*OVMF_CODE\.fd", # RHEL
|
r".*OVMF_CODE\.fd", # RHEL
|
||||||
r".*ovmf-x64/OVMF.*\.fd", # gerd's firmware repo
|
r".*ovmf-x64/OVMF.*\.fd", # gerd's firmware repo
|
||||||
r".*ovmf-x86_64-.*", # SUSE
|
r".*ovmf-x86_64-.*", # SUSE
|
||||||
r".*ovmf.*", ".*OVMF.*", # generic attempt at a catchall
|
r".*ovmf.*",
|
||||||
|
".*OVMF.*", # generic attempt at a catchall
|
||||||
],
|
],
|
||||||
"aarch64": [
|
"aarch64": [
|
||||||
r".*AAVMF_CODE\.fd", # RHEL
|
r".*AAVMF_CODE\.fd", # RHEL
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
from django import template
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def app_active(request, app_name):
|
def app_active(request, app_name):
|
||||||
if request.resolver_match.app_name == app_name:
|
if request.resolver_match.app_name == app_name:
|
||||||
return 'active'
|
return "active"
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def view_active(request, view_name):
|
def view_active(request, view_name):
|
||||||
if request.resolver_match.view_name == view_name:
|
if request.resolver_match.view_name == view_name:
|
||||||
return 'active'
|
return "active"
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def class_active(request, pattern):
|
def class_active(request, pattern):
|
||||||
if re.search(pattern, request.path):
|
if re.search(pattern, request.path):
|
||||||
# Not sure why 'class="active"' returns class=""active""
|
# Not sure why 'class="active"' returns class=""active""
|
||||||
return 'active'
|
return "active"
|
||||||
return ''
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
|
|
|
@ -15,7 +15,7 @@ class ExceptionMiddleware:
|
||||||
if isinstance(exception, libvirtError):
|
if isinstance(exception, libvirtError):
|
||||||
messages.error(
|
messages.error(
|
||||||
request,
|
request,
|
||||||
_('libvirt Error - %(exception)s') % {'exception': exception},
|
_("libvirt Error - %(exception)s") % {"exception": exception},
|
||||||
)
|
)
|
||||||
return render(request, '500.html', status=500)
|
return render(request, "500.html", status=500)
|
||||||
# TODO: check connecting to host via VPN
|
# TODO: check connecting to host via VPN
|
||||||
|
|
|
@ -20,9 +20,7 @@ MIDDLEWARE += [
|
||||||
]
|
]
|
||||||
|
|
||||||
# DebugToolBar
|
# DebugToolBar
|
||||||
INTERNAL_IPS = (
|
INTERNAL_IPS = ("127.0.0.1",)
|
||||||
"127.0.0.1",
|
|
||||||
)
|
|
||||||
DEBUG_TOOLBAR_CONFIG = {
|
DEBUG_TOOLBAR_CONFIG = {
|
||||||
"INTERCEPT_REDIRECTS": False,
|
"INTERCEPT_REDIRECTS": False,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,102 +8,102 @@ import os
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
SECRET_KEY = ''
|
SECRET_KEY = ""
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ["*"]
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'django.contrib.auth',
|
"django.contrib.auth",
|
||||||
'django.contrib.contenttypes',
|
"django.contrib.contenttypes",
|
||||||
'django.contrib.sessions',
|
"django.contrib.sessions",
|
||||||
'django.contrib.messages',
|
"django.contrib.messages",
|
||||||
'django.contrib.staticfiles',
|
"django.contrib.staticfiles",
|
||||||
'bootstrap4',
|
"bootstrap4",
|
||||||
'django_icons',
|
"django_icons",
|
||||||
'django_otp',
|
"django_otp",
|
||||||
'django_otp.plugins.otp_totp',
|
"django_otp.plugins.otp_totp",
|
||||||
'accounts',
|
"accounts",
|
||||||
'admin',
|
"admin",
|
||||||
'appsettings',
|
"appsettings",
|
||||||
'computes',
|
"computes",
|
||||||
'console',
|
"console",
|
||||||
'datasource',
|
"datasource",
|
||||||
'networks',
|
"networks",
|
||||||
'instances',
|
"instances",
|
||||||
'interfaces',
|
"interfaces",
|
||||||
'nwfilters',
|
"nwfilters",
|
||||||
'storages',
|
"storages",
|
||||||
'secrets',
|
"secrets",
|
||||||
'logs',
|
"logs",
|
||||||
'qr_code',
|
"qr_code",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
"django.middleware.security.SecurityMiddleware",
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
"django.middleware.locale.LocaleMiddleware",
|
||||||
'django.middleware.common.CommonMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
'django_otp.middleware.OTPMiddleware',
|
"django_otp.middleware.OTPMiddleware",
|
||||||
'login_required.middleware.LoginRequiredMiddleware',
|
"login_required.middleware.LoginRequiredMiddleware",
|
||||||
'django.contrib.auth.middleware.RemoteUserMiddleware',
|
"django.contrib.auth.middleware.RemoteUserMiddleware",
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
'appsettings.middleware.AppSettingsMiddleware',
|
"appsettings.middleware.AppSettingsMiddleware",
|
||||||
'webvirtcloud.middleware.ExceptionMiddleware',
|
"webvirtcloud.middleware.ExceptionMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = 'webvirtcloud.urls'
|
ROOT_URLCONF = "webvirtcloud.urls"
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
'DIRS': [
|
"DIRS": [
|
||||||
os.path.join(BASE_DIR, 'templates'),
|
os.path.join(BASE_DIR, "templates"),
|
||||||
],
|
],
|
||||||
'APP_DIRS': True,
|
"APP_DIRS": True,
|
||||||
'OPTIONS': {
|
"OPTIONS": {
|
||||||
'context_processors': [
|
"context_processors": [
|
||||||
'django.template.context_processors.debug',
|
"django.template.context_processors.debug",
|
||||||
'django.template.context_processors.request',
|
"django.template.context_processors.request",
|
||||||
'django.contrib.auth.context_processors.auth',
|
"django.contrib.auth.context_processors.auth",
|
||||||
'django.contrib.messages.context_processors.messages',
|
"django.contrib.messages.context_processors.messages",
|
||||||
'appsettings.context_processors.app_settings',
|
"appsettings.context_processors.app_settings",
|
||||||
],
|
],
|
||||||
'libraries': {
|
"libraries": {
|
||||||
'common_tags': 'webvirtcloud.common_tags',
|
"common_tags": "webvirtcloud.common_tags",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = 'webvirtcloud.wsgi.application'
|
WSGI_APPLICATION = "webvirtcloud.wsgi.application"
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
"default": {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGIN_URL = '/accounts/login/'
|
LOGIN_URL = "/accounts/login/"
|
||||||
|
|
||||||
LOGOUT_REDIRECT_URL = '/accounts/login/'
|
LOGOUT_REDIRECT_URL = "/accounts/login/"
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
TIME_ZONE = 'UTC'
|
TIME_ZONE = "UTC"
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
|
@ -111,30 +111,27 @@ USE_L10N = True
|
||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
STATICFILES_DIRS = [
|
STATICFILES_DIRS = [
|
||||||
os.path.join(BASE_DIR, "static"),
|
os.path.join(BASE_DIR, "static"),
|
||||||
]
|
]
|
||||||
|
|
||||||
LOCALE_PATHS = [
|
LOCALE_PATHS = [
|
||||||
'locale/',
|
"locale/",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"disable_existing_loggers": False,
|
"disable_existing_loggers": False,
|
||||||
"handlers": {
|
"handlers": {
|
||||||
"mail_admins": {
|
"mail_admins": {"level": "ERROR", "class": "django.utils.log.AdminEmailHandler"}
|
||||||
"level": "ERROR",
|
|
||||||
"class": "django.utils.log.AdminEmailHandler"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"loggers": {
|
"loggers": {
|
||||||
"django.request": {
|
"django.request": {
|
||||||
"handlers": ["mail_admins"],
|
"handlers": ["mail_admins"],
|
||||||
"level": "ERROR",
|
"level": "ERROR",
|
||||||
"propagate": True
|
"propagate": True,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -147,7 +144,7 @@ LOGGING = {
|
||||||
WS_PORT = 6080
|
WS_PORT = 6080
|
||||||
|
|
||||||
# Websock host
|
# Websock host
|
||||||
WS_HOST = '0.0.0.0'
|
WS_HOST = "0.0.0.0"
|
||||||
|
|
||||||
# Websock public port - 80 or 443 if reverse-proxy, else 6080
|
# Websock public port - 80 or 443 if reverse-proxy, else 6080
|
||||||
WS_PUBLIC_PORT = 6080
|
WS_PUBLIC_PORT = 6080
|
||||||
|
@ -156,22 +153,53 @@ WS_PUBLIC_PORT = 6080
|
||||||
WS_PUBLIC_HOST = None
|
WS_PUBLIC_HOST = None
|
||||||
|
|
||||||
# Websock public path
|
# Websock public path
|
||||||
WS_PUBLIC_PATH = '/novncd/'
|
WS_PUBLIC_PATH = "/novncd/"
|
||||||
|
|
||||||
# Websock Certificate for SSL
|
# Websock Certificate for SSL
|
||||||
WS_CERT = None
|
WS_CERT = None
|
||||||
|
|
||||||
# List of console listen addresses
|
# List of console listen addresses
|
||||||
QEMU_CONSOLE_LISTEN_ADDRESSES = (
|
QEMU_CONSOLE_LISTEN_ADDRESSES = (
|
||||||
('127.0.0.1', 'Localhost'),
|
("127.0.0.1", "Localhost"),
|
||||||
('0.0.0.0', 'All interfaces'),
|
("0.0.0.0", "All interfaces"),
|
||||||
)
|
)
|
||||||
|
|
||||||
# List taken from http://qemu.weilnetz.de/qemu-doc.html#sec_005finvocation
|
# List taken from http://qemu.weilnetz.de/qemu-doc.html#sec_005finvocation
|
||||||
QEMU_KEYMAPS = ['ar', 'da', 'de', 'de-ch', 'en-gb', 'en-us', 'es', 'et', 'fi',
|
QEMU_KEYMAPS = [
|
||||||
'fo', 'fr', 'fr-be', 'fr-ca', 'fr-ch', 'hr', 'hu', 'is', 'it',
|
"ar",
|
||||||
'ja', 'lt', 'lv', 'mk', 'nl', 'nl-be', 'no', 'pl', 'pt',
|
"da",
|
||||||
'pt-br', 'ru', 'sl', 'sv', 'th', 'tr']
|
"de",
|
||||||
|
"de-ch",
|
||||||
|
"en-gb",
|
||||||
|
"en-us",
|
||||||
|
"es",
|
||||||
|
"et",
|
||||||
|
"fi",
|
||||||
|
"fo",
|
||||||
|
"fr",
|
||||||
|
"fr-be",
|
||||||
|
"fr-ca",
|
||||||
|
"fr-ch",
|
||||||
|
"hr",
|
||||||
|
"hu",
|
||||||
|
"is",
|
||||||
|
"it",
|
||||||
|
"ja",
|
||||||
|
"lt",
|
||||||
|
"lv",
|
||||||
|
"mk",
|
||||||
|
"nl",
|
||||||
|
"nl-be",
|
||||||
|
"no",
|
||||||
|
"pl",
|
||||||
|
"pt",
|
||||||
|
"pt-br",
|
||||||
|
"ru",
|
||||||
|
"sl",
|
||||||
|
"sv",
|
||||||
|
"th",
|
||||||
|
"tr",
|
||||||
|
]
|
||||||
|
|
||||||
# Keepalive interval and count for libvirt connections
|
# Keepalive interval and count for libvirt connections
|
||||||
LIBVIRT_KEEPALIVE_INTERVAL = 5
|
LIBVIRT_KEEPALIVE_INTERVAL = 5
|
||||||
|
@ -183,5 +211,4 @@ SHOW_PROFILE_EDIT_PASSWORD = True
|
||||||
|
|
||||||
OTP_ENABLED = False
|
OTP_ENABLED = False
|
||||||
|
|
||||||
LOGIN_REQUIRED_IGNORE_VIEW_NAMES = ['accounts:email_otp']
|
LOGIN_REQUIRED_IGNORE_VIEW_NAMES = ["accounts:email_otp"]
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
from django.conf import settings
|
|
||||||
from django.urls import include, path
|
|
||||||
|
|
||||||
from appsettings.views import appsettings
|
from appsettings.views import appsettings
|
||||||
from console.views import console
|
from console.views import console
|
||||||
|
from django.conf import settings
|
||||||
|
from django.urls import include, path
|
||||||
from instances.views import index
|
from instances.views import index
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', index, name='index'),
|
path("", index, name="index"),
|
||||||
path('admin/', include(('admin.urls', 'admin'), namespace='admin')),
|
path("admin/", include(("admin.urls", "admin"), namespace="admin")),
|
||||||
path('accounts/', include('accounts.urls')),
|
path("accounts/", include("accounts.urls")),
|
||||||
path('appsettings/', appsettings, name='appsettings'),
|
path("appsettings/", appsettings, name="appsettings"),
|
||||||
path('computes/', include('computes.urls')),
|
path("computes/", include("computes.urls")),
|
||||||
path('console/', console, name='console'),
|
path("console/", console, name="console"),
|
||||||
path('datasource/', include('datasource.urls')),
|
path("datasource/", include("datasource.urls")),
|
||||||
path('instances/', include('instances.urls')),
|
path("instances/", include("instances.urls")),
|
||||||
path('i18n/', include('django.conf.urls.i18n')),
|
path("i18n/", include("django.conf.urls.i18n")),
|
||||||
path('logs/', include('logs.urls')),
|
path("logs/", include("logs.urls")),
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
@ -23,7 +22,7 @@ if settings.DEBUG:
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
|
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
path('__debug__/', include(debug_toolbar.urls)),
|
path("__debug__/", include(debug_toolbar.urls)),
|
||||||
]
|
]
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -11,6 +11,6 @@ import os
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'webvirtcloud.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webvirtcloud.settings")
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
|
|
@ -16,7 +16,7 @@ exec(
|
||||||
compile(
|
compile(
|
||||||
open("/srv/webvirtcloud/venv/bin/activate", "rb").read(),
|
open("/srv/webvirtcloud/venv/bin/activate", "rb").read(),
|
||||||
"/srv/webvirtcloud/venv/bin/activate",
|
"/srv/webvirtcloud/venv/bin/activate",
|
||||||
"exec"
|
"exec",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue