mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-25 15:45:23 +00:00
Merge pull request #385 from catborise/master
black & isort linter fixes- bug fixes
This commit is contained in:
commit
9aed7c7716
63 changed files with 6874 additions and 2143 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,11 +35,11 @@ def validate_ssh_key(key):
|
||||||
return False
|
return False
|
||||||
# unpack the contents of data, from data[:4] , property of ssh key .
|
# unpack the contents of data, from data[:4] , property of ssh key .
|
||||||
try:
|
try:
|
||||||
str_len = struct.unpack('>I', data[:4])[0]
|
str_len = struct.unpack(">I", data[:4])[0]
|
||||||
except struct.error:
|
except struct.error:
|
||||||
return False
|
return False
|
||||||
# data[4:str_len] must have string which matches with the typeofkey, another ssh key property.
|
# data[4:str_len] must have string which matches with the typeofkey, another ssh key property.
|
||||||
if data[4:4 + str_len] == typeofkey:
|
if data[4 : 4 + str_len] == typeofkey:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -47,15 +47,15 @@ def validate_ssh_key(key):
|
||||||
|
|
||||||
def send_email_with_otp(user, device):
|
def send_email_with_otp(user, device):
|
||||||
send_mail(
|
send_mail(
|
||||||
_('OTP QR Code'),
|
_("OTP QR Code"),
|
||||||
_('Please view HTML version of this message.'),
|
_("Please view HTML version of this message."),
|
||||||
None,
|
None,
|
||||||
[user.email],
|
[user.email],
|
||||||
html_message=render_to_string(
|
html_message=render_to_string(
|
||||||
'accounts/email/otp.html',
|
"accounts/email/otp.html",
|
||||||
{
|
{
|
||||||
'totp_url': device.config_url,
|
"totp_url": device.config_url,
|
||||||
'user': user,
|
"user": user,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
fail_silently=False,
|
fail_silently=False,
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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())
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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,11 +7,11 @@ class wvmSecrets(wvmConnect):
|
||||||
def create_secret(self, ephemeral, private, secret_type, data):
|
def create_secret(self, ephemeral, private, secret_type, data):
|
||||||
xml = f"""<secret ephemeral='{ephemeral}' private='{private}'>
|
xml = f"""<secret ephemeral='{ephemeral}' private='{private}'>
|
||||||
<usage type='{secret_type}'>"""
|
<usage type='{secret_type}'>"""
|
||||||
if secret_type == 'ceph':
|
if secret_type == "ceph":
|
||||||
xml += f"""<name>{data}</name>"""
|
xml += f"""<name>{data}</name>"""
|
||||||
if secret_type == 'volume':
|
if secret_type == "volume":
|
||||||
xml += f"""<volume>{data}</volume>"""
|
xml += f"""<volume>{data}</volume>"""
|
||||||
if secret_type == 'iscsi':
|
if secret_type == "iscsi":
|
||||||
xml += f"""<target>{data}</target>"""
|
xml += f"""<target>{data}</target>"""
|
||||||
xml += """</usage>
|
xml += """</usage>
|
||||||
</secret>"""
|
</secret>"""
|
||||||
|
|
|
@ -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