1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-11-01 03:54:15 +00:00

Add all settings to appsettings page & Convert settings choices

This commit is contained in:
catborise 2020-05-29 00:43:26 +03:00 committed by catborise
parent 62f8ece0ef
commit 7538ddab4f
27 changed files with 454 additions and 447 deletions

View file

@ -9,8 +9,7 @@ class UserAddForm(forms.Form):
name = forms.CharField(label="Name", name = forms.CharField(label="Name",
error_messages={'required': _('No User name has been entered')}, error_messages={'required': _('No User name has been entered')},
max_length=20) max_length=20)
password = forms.CharField(required=not settings.ALLOW_EMPTY_PASSWORD, password = forms.CharField(required=not settings.ALLOW_EMPTY_PASSWORD, error_messages={'required': _('No password has been entered')},)
error_messages={'required': _('No password has been entered')},)
def clean_name(self): def clean_name(self):
name = self.cleaned_data['name'] name = self.cleaned_data['name']

View file

@ -0,0 +1,24 @@
# Generated by Django 2.2.12 on 2020-06-04 09:30
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0002_permissionset'),
]
operations = [
migrations.AlterField(
model_name='userattributes',
name='max_cpus',
field=models.IntegerField(default=2, help_text='-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]),
),
migrations.AlterField(
model_name='userattributes',
name='max_instances',
field=models.IntegerField(default=2, help_text='-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]),
),
]

View file

@ -1,4 +1,3 @@
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.db import models from django.db import models

View file

@ -68,8 +68,8 @@
<div class="modal-content"> <div class="modal-content">
<form method="post" role="form" aria-label="Edit user form">{% csrf_token %} <form method="post" role="form" aria-label="Edit user form">{% csrf_token %}
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h5 class="modal-title">{% trans "Edit user info" %}</h5> <h5 class="modal-title">{% trans "Edit user info" %}</h5>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-group row"> <div class="form-group row">
@ -133,11 +133,11 @@
{% trans "Delete" %} {% trans "Delete" %}
</button> </button>
{% if user.is_active %} {% if user.is_active %}
<button type="submit" class="float-left btn btn-warning" name="block"> <button type="submit" class="btn btn-warning mr-auto" name="block">
{% trans "Block" %} {% trans "Block" %}
</button> </button>
{% else %} {% else %}
<button type="submit" class="float-left btn btn-success" name="unblock"> <button type="submit" class="btn btn-success mr-auto" name="unblock">
{% trans "Unblock" %} {% trans "Unblock" %}
</button> </button>
{% endif %} {% endif %}

View file

@ -1,4 +1,4 @@
from django.urls import path, re_path from django.urls import path
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
from . import views from . import views

View file

@ -4,10 +4,10 @@ from django.http import HttpResponseRedirect
from django.shortcuts import render from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from accounts.forms import UserAddForm from accounts.forms import UserAddForm
from accounts.models import * from accounts.models import *
from admin.decorators import superuser_only from admin.decorators import superuser_only
from appsettings.models import AppSettings
from instances.models import Instance from instances.models import Instance
import sass import sass
@ -22,7 +22,6 @@ def profile(request):
error_messages = [] error_messages = []
# user = User.objects.get(id=request.user.id) # user = User.objects.get(id=request.user.id)
publickeys = UserSSHKey.objects.filter(user_id=request.user.id) publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
themes_list = os.listdir(settings.SCSS_DIR +"/wvc-theme") themes_list = os.listdir(settings.SCSS_DIR +"/wvc-theme")
if request.method == 'POST': if request.method == 'POST':
@ -69,20 +68,6 @@ def profile(request):
delkeypublic = UserSSHKey.objects.get(id=keyid) delkeypublic = UserSSHKey.objects.get(id=keyid)
delkeypublic.delete() delkeypublic.delete()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'change_theme' in request.POST:
theme = request.POST.get('theme_select', '')
scss_var = f"@import '{settings.SCSS_DIR}/wvc-theme/{theme}/variables';"
scss_bootswatch = f"@import '{settings.SCSS_DIR}/wvc-theme/{theme}/bootswatch';"
scss_boot = f"@import '{settings.SCSS_DIR}/bootstrap-overrides.scss';"
with open(settings.SCSS_DIR + "/wvc-main.scss", "w") as main:
main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch)
css_compressed = sass.compile(string=scss_var + "\n"+ scss_boot + "\n" + scss_bootswatch, output_style='compressed')
with open("static/" + "css/wvc-main.min.css", "w") as css:
css.write(css_compressed)
return HttpResponseRedirect(request.get_full_path())
return render(request, 'profile.html', locals()) return render(request, 'profile.html', locals())
@ -120,7 +105,7 @@ def account(request, user_id):
if 'add' in request.POST: if 'add' in request.POST:
inst_id = request.POST.get('inst_id', '') inst_id = request.POST.get('inst_id', '')
if settings.ALLOW_INSTANCE_MULTIPLE_OWNER: if AppSettings.objects.get(key="ALLOW_INSTANCE_MULTIPLE_OWNER").value == 'True':
check_inst = UserInstance.objects.filter(instance_id=int(inst_id), user_id=int(user_id)) check_inst = UserInstance.objects.filter(instance_id=int(inst_id), user_id=int(user_id))
else: else:
check_inst = UserInstance.objects.filter(instance_id=int(inst_id)) check_inst = UserInstance.objects.filter(instance_id=int(inst_id))

View file

@ -1,4 +1,4 @@
# Generated by Django 2.2.12 on 2020-05-23 15:53 # Generated by Django 2.2.12 on 2020-05-27 16:03
from django.db import migrations, models from django.db import migrations, models
@ -16,8 +16,9 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=25)), ('name', models.CharField(max_length=25)),
('key', models.CharField(max_length=50, unique=True)), ('key', models.CharField(db_index=True, max_length=50, unique=True)),
('value', models.CharField(max_length=25)), ('value', models.CharField(max_length=25)),
('choices', models.CharField(max_length=50)),
('description', models.CharField(max_length=100, null=True)), ('description', models.CharField(max_length=100, null=True)),
], ],
), ),

View file

@ -1,80 +0,0 @@
# Generated by Django 2.2.12 on 2020-05-23 12:05
from django.db import migrations
def add_default_settings(apps, schema_editor):
setting = apps.get_model("appsettings", "AppSettings")
db_alias = schema_editor.connection.alias
setting.objects.using(db_alias).bulk_create([
setting(1, "Console Type", "QEMU_CONSOLE_DEFAULT_TYPE", "vnc", "Default console type"),
setting(2, "Libvirt K.alive Intrval", "LIBVIRT_KEEPALIVE_INTERVAL", "5", "libvirt keepalive interval"),
setting(3, "Libvirt K.alive Count", "LIBVIRT_KEEPALIVE_COUNT", "5", "libvirt keepalive count"),
setting(4, "Multiple Owner for VM ", "ALLOW_INSTANCE_MULTIPLE_OWNER", "True"),
setting(5, "VM Clone Name Prefix", "CLONE_INSTANCE_DEFAULT_PREFIX", "instance"),
setting(6, "VM Clone Auto Name", "CLONE_INSTANCE_AUTO_NAME", "False"),
setting(7, "VM Clone Auto Migrate", "CLONE_INSTANCE_AUTO_MIGRATE", "False"),
setting(8, "Logs per Page", "LOGS_PER_PAGE", "100"),
setting(9, "Quota Debug", "QUOTA_DEBUG", "True"),
setting(10, "Empty Password", "ALLOW_EMPTY_PASSWORD", "True"),
setting(11, "Account View Style", "VIEW_ACCOUNTS_STYLE", "grid", "available: default (grid), list"),
setting(12, "Instance List View", "VIEW_INSTANCES_LIST_STYLE", "grouped", "available instance list style: default (grouped), nongrouped"),
setting(13, "Show Bottom Bar", "VIEW_INSTANCE_DETAIL_BOTTOM_BAR", "True", "available options: True, False"),
setting(14, "Disk Format", "INSTANCE_VOLUME_DEFAULT_FORMAT", "qcow2", "available volume format: raw, qcow2, qcow"),
setting(15, "Disk Bus", "INSTANCE_VOLUME_DEFAULT_BUS", "virtio", "available bus types: virtio, scsi, ide, usb, sata"),
setting(16, "Disk SCSI Controller", "INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER", "virtio-scsi", "SCSI Types: virtio-scsi, lsilogic"),
setting(17, "Disk Cache", "INSTANCE_VOLUME_DEFAULT_CACHE", "directsync", " Volume cache: default, directsync, none, unsafe, writeback, writethrough"),
setting(18, "Disk IO Type", "INSTANCE_VOLUME_DEFAULT_IO", "default", "Volume io mode: default, native, threads"),
setting(19, "Disk Detect Zeroes", "INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES", "default", "Volume detect zeroes mode: default, on, off, unmap"),
setting(20, "Disk Discard", "INSTANCE_VOLUME_DEFAULT_DISCARD", "default", "Volume discard mode: default, unmap, ignore"),
setting(21, "Disk Owner UID", "INSTANCE_VOLUME_DEFAULT_OWNER_UID", "0", "up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)"),
setting(22, "Disk Owner GID", "INSTANCE_VOLUME_DEFAULT_OWNER_GID", "0", "up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)"),
setting(23, "CPU Mode", "INSTANCE_CPU_DEFAULT_MODE", "host-model", "Cpu modes: no-model, host-model, host-passthrough, custom"),
setting(24, "Machine Type", "INSTANCE_MACHINE_DEFAULT_TYPE", "q35", "Chipset/Machine: pc or q35 for x86_64"),
setting(25, "Firmware Type", "INSTANCE_FIRMWARE_DEFAULT_TYPE", "BIOS", "Firmware: BIOS or UEFI for x86_64"),
setting(26, "Architecture Type", "INSTANCE_ARCH_DEFAULT_TYPE", "x86_64", "Architecture: x86_64, i686, etc"),
setting(27, "Theme", "BOOTSTRAP_THEME", "", "Bootstrap CSS & Bootswatch"),
setting(28, "Sass Path", "SASS_DIR", "", "Bootstrap SASS & Bootswatch SASS "),
])
def del_default_settings(apps, schema_editor):
setting = apps.get_model("appsettings", "AppSettings")
db_alias = schema_editor.connection.alias
setting.objects.using(db_alias).filter(id=1, key="QEMU_CONSOLE_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(id=2, key="LIBVIRT_KEEPALIVE_INTERVAL").delete()
setting.objects.using(db_alias).filter(id=3, key="LIBVIRT_KEEPALIVE_COUNT").delete()
setting.objects.using(db_alias).filter(id=4, key="ALLOW_INSTANCE_MULTIPLE_OWNER").delete()
setting.objects.using(db_alias).filter(id=5, key="CLONE_INSTANCE_DEFAULT_PREFIX").delete()
setting.objects.using(db_alias).filter(id=6, key="CLONE_INSTANCE_AUTO_NAME").delete()
setting.objects.using(db_alias).filter(id=7, key="CLONE_INSTANCE_AUTO_MIGRATE").delete()
setting.objects.using(db_alias).filter(id=8, key="LOGS_PER_PAGE").delete()
setting.objects.using(db_alias).filter(id=9, key="QUOTA_DEBUG").delete()
setting.objects.using(db_alias).filter(id=10, key="ALLOW_EMPTY_PASSWORD").delete()
setting.objects.using(db_alias).filter(id=11, key="VIEW_ACCOUNTS_STYLE").delete()
setting.objects.using(db_alias).filter(id=12, key="VIEW_INSTANCES_LIST_STYLE").delete()
setting.objects.using(db_alias).filter(id=13, key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").delete()
setting.objects.using(db_alias).filter(id=14, key="INSTANCE_VOLUME_DEFAULT_FORMAT").delete()
setting.objects.using(db_alias).filter(id=15, key="INSTANCE_VOLUME_DEFAULT_BUS").delete()
setting.objects.using(db_alias).filter(id=16, key="INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER").delete()
setting.objects.using(db_alias).filter(id=17, key="INSTANCE_VOLUME_DEFAULT_CACHE").delete()
setting.objects.using(db_alias).filter(id=18, key="INSTANCE_VOLUME_DEFAULT_IO").delete()
setting.objects.using(db_alias).filter(id=19, key="INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES").delete()
setting.objects.using(db_alias).filter(id=20, key="INSTANCE_VOLUME_DEFAULT_DISCARD").delete()
setting.objects.using(db_alias).filter(id=21, key="INSTANCE_VOLUME_DEFAULT_OWNER_UID").delete()
setting.objects.using(db_alias).filter(id=22, key="INSTANCE_VOLUME_DEFAULT_OWNER_GID").delete()
setting.objects.using(db_alias).filter(id=23, key="INSTANCE_CPU_DEFAULT_MODE").delete()
setting.objects.using(db_alias).filter(id=24, key="INSTANCE_MACHINE_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(id=25, key="INSTANCE_FIRMWARE_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(id=26, key="INSTANCE_ARCH_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(id=27, key="BOOTSTRAP_THEME").delete()
setting.objects.using(db_alias).filter(id=28, key="SASS_DIR").delete()
class Migration(migrations.Migration):
dependencies = [
('appsettings', '0001_initial'),
]
operations = [
migrations.RunPython(add_default_settings, del_default_settings),
]

View file

@ -0,0 +1,82 @@
# Generated by Django 2.2.12 on 2020-05-23 12:05
from django.db import migrations
def add_default_settings(apps, schema_editor):
setting = apps.get_model("appsettings", "AppSettings")
db_alias = schema_editor.connection.alias
setting.objects.using(db_alias).bulk_create([
setting(1, "Theme", "BOOTSTRAP_THEME", "flaty", "", "Bootstrap CSS & Bootswatch Theme"),
setting(2, "Theme SASS Path", "SASS_DIR", "dev/scss/", "", "Bootstrap SASS & Bootswatch SASS Directory"),
setting(3, "All Instances View Style", "VIEW_INSTANCES_LIST_STYLE", "grouped", "grouped,nongrouped", "All instances list style"),
setting(4, "Account View Style", "VIEW_ACCOUNTS_STYLE", "grid", "grid,list", "User accounts view style"),
setting(5, "Logs per Page", "LOGS_PER_PAGE", "100", "", "Pagination for logs"),
setting(6, "Multiple Owner for VM ", "ALLOW_INSTANCE_MULTIPLE_OWNER", "True", "True,False", "Allow to have multiple owner for instance"),
setting(7, "Quota Debug", "QUOTA_DEBUG", "True", "True,False", "Debug for user quotas"),
setting(8, "Empty Password", "ALLOW_EMPTY_PASSWORD", "True", "True,False", "Allow empty password"),
setting(9, "Disk Format", "INSTANCE_VOLUME_DEFAULT_FORMAT", "qcow2", "raw,qcow,qcow2", "Instance disk format"),
setting(10, "Disk Bus", "INSTANCE_VOLUME_DEFAULT_BUS", "virtio", "virtio,scsi,ide,usb,sata", "Instance disk bus type"),
setting(11, "Disk SCSI Controller", "INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER", "virtio-scsi", "virtio-scsi, lsilogic, virtio-blk", "SCSI controller type"),
setting(12, "Disk Cache", "INSTANCE_VOLUME_DEFAULT_CACHE", "directsync", "default,directsync,none,unsafe,writeback,writethrough", "Disk volume cache type"),
setting(13, "Disk IO Type", "INSTANCE_VOLUME_DEFAULT_IO", "default", "default,native,threads", "Volume io modes"),
setting(14, "Disk Detect Zeroes", "INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES", "default", "default,on,off,unmap", "Volume detect zeroes mode"),
setting(15, "Disk Discard", "INSTANCE_VOLUME_DEFAULT_DISCARD", "default", "default,unmap,ignore", "Volume discard mode"),
setting(16, "Disk Owner UID", "INSTANCE_VOLUME_DEFAULT_OWNER_UID", "0", "", "Owner UID: up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)"),
setting(17, "Disk Owner GID", "INSTANCE_VOLUME_DEFAULT_OWNER_GID", "0", "", "Owner GID: up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)"),
setting(18, "VM CPU Mode", "INSTANCE_CPU_DEFAULT_MODE", "host-model", "no-model,host-model,host-passthrough,custom", "Cpu modes"),
setting(19, "VM Machine Type", "INSTANCE_MACHINE_DEFAULT_TYPE", "q35", "q35,x86_64", "Chipset/Machine type"),
setting(20, "VM Firmware Type", "INSTANCE_FIRMWARE_DEFAULT_TYPE", "BIOS", "BIOS,UEFI", "Firmware type for x86_64"),
setting(21, "VM Architecture Type", "INSTANCE_ARCH_DEFAULT_TYPE", "x86_64", "x86_64,i686", "Architecture type: x86_64, i686, etc"),
setting(22, "VM Console Type", "QEMU_CONSOLE_DEFAULT_TYPE", "vnc", "vnc,spice", "Default console type"),
setting(23, "VM Clone Name Prefix", "CLONE_INSTANCE_DEFAULT_PREFIX", "instance", "True,False", "Prefix for cloned instance name"),
setting(24, "VM Clone Auto Name", "CLONE_INSTANCE_AUTO_NAME", "False", "True,False", "Generated name for cloned instance"),
setting(25, "VM Clone Auto Migrate", "CLONE_INSTANCE_AUTO_MIGRATE", "False", "True,False", "Auto migrate instance after clone"),
setting(26, "VM Bottom Bar", "VIEW_INSTANCE_DETAIL_BOTTOM_BAR", "True", "True,False", "Bottom navbar for instance details"),
setting(27, "Show Access Root Pass", "SHOW_ACCESS_ROOT_PASSWORD", "False", "True,False", "Show access root password"),
setting(28, "Show Access SSH Keys", "SHOW_ACCESS_SSH_KEYS", "False", "True,False", "Show access ssh keys"),
setting(29, "Show Profile Edit Pass", "SHOW_PROFILE_EDIT_PASSWORD", "False", "True,False", "Show profile edit password"),
])
def del_default_settings(apps, schema_editor):
setting = apps.get_model("appsettings", "AppSettings")
db_alias = schema_editor.connection.alias
setting.objects.using(db_alias).filter(key="QEMU_CONSOLE_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(key="ALLOW_INSTANCE_MULTIPLE_OWNER").delete()
setting.objects.using(db_alias).filter(key="CLONE_INSTANCE_DEFAULT_PREFIX").delete()
setting.objects.using(db_alias).filter(key="CLONE_INSTANCE_AUTO_NAME").delete()
setting.objects.using(db_alias).filter(key="CLONE_INSTANCE_AUTO_MIGRATE").delete()
setting.objects.using(db_alias).filter(key="LOGS_PER_PAGE").delete()
setting.objects.using(db_alias).filter(key="QUOTA_DEBUG").delete()
setting.objects.using(db_alias).filter(key="ALLOW_EMPTY_PASSWORD").delete()
setting.objects.using(db_alias).filter(key="VIEW_ACCOUNTS_STYLE").delete()
setting.objects.using(db_alias).filter(key="VIEW_INSTANCES_LIST_STYLE").delete()
setting.objects.using(db_alias).filter(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_FORMAT").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_BUS").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_CACHE").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_IO").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_DISCARD").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_OWNER_UID").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_VOLUME_DEFAULT_OWNER_GID").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_CPU_DEFAULT_MODE").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_MACHINE_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_FIRMWARE_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(key="INSTANCE_ARCH_DEFAULT_TYPE").delete()
setting.objects.using(db_alias).filter(key="BOOTSTRAP_THEME").delete()
setting.objects.using(db_alias).filter(key="SASS_DIR").delete()
setting.objects.using(db_alias).filter(key="SHOW_ACCESS_ROOT_PASSWORD").delete()
setting.objects.using(db_alias).filter(key="SHOW_ACCESS_SSH_KEYS").delete()
setting.objects.using(db_alias).filter(key="SHOW_PROFILE_EDIT_PASSWORD").delete()
class Migration(migrations.Migration):
dependencies = [
('appsettings', '0001_initial'),
]
operations = [
migrations.RunPython(add_default_settings, del_default_settings),
]

View file

@ -2,7 +2,12 @@ from django.db import models
class AppSettings(models.Model): class AppSettings(models.Model):
def choices_as_list(self):
return self.choices.split(',')
name = models.CharField(max_length=25, null=False) name = models.CharField(max_length=25, null=False)
key = models.CharField(max_length=50, unique=True) key = models.CharField(db_index=True, max_length=50, unique=True)
value = models.CharField(max_length=25) value = models.CharField(max_length=25)
choices = models.CharField(max_length=50)
description = models.CharField(max_length=100, null=True) description = models.CharField(max_length=100, null=True)

View file

@ -57,17 +57,25 @@
</div> </div>
</form> </form>
{% endif %} {% endif %}
<form method="post" action="" role="form" aria-label="Edit bottom bar settings form">{% csrf_token %} <h3 class="page-header">{% trans "Other Settings" %}</h3>
{% for setting in appsettings %}
<form method="post" action="" role="form" aria-label="{{setting.name}} form">{% csrf_token %}
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">{{ show_inst_bottom_bar.name }}</label> <label class="col-sm-3 col-form-label">{{ setting.name }}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<select class="form-control" name="{{ show_inst_bottom_bar.key }}" onchange="this.form.submit()"> {% if setting.choices %}
<option {% if show_inst_bottom_bar.value == 'True' %} selected {% endif %} value=True>{% trans "True" %}</option> <select class="form-control" name="{{ setting.key }}" onchange="this.form.submit()" title="{{ setting.description }}">
<option {% if show_inst_bottom_bar.value == 'False' %} selected {% endif %} value=False>{% trans "False" %}</option> {% for choice in setting.choices_as_list %}
<option {% if setting.value == choice %} selected {% endif %} value={{ choice }}>{% trans choice %}</option>
{% endfor %}
</select> </select>
{% else %}
<input class="form-control" name="{{ setting.key }}" value="{{ setting.value }}" title="{{ setting.description }}" onchange="this.form.submit()"/>
{% endif%}
</div> </div>
</div> </div>
</form> </form>
{% endfor %}
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -7,7 +7,6 @@ from django.urls import reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib import messages from django.contrib import messages
from django.conf import settings
from appsettings.models import AppSettings from appsettings.models import AppSettings
from logs.views import addlogmsg from logs.views import addlogmsg
@ -22,14 +21,33 @@ def appsettings(request):
""" """
error_messages = [] error_messages = []
show_inst_bottom_bar = AppSettings.objects.get(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR")
bootstrap_theme = AppSettings.objects.get(key="BOOTSTRAP_THEME")
sass_dir = AppSettings.objects.get(key="SASS_DIR") sass_dir = AppSettings.objects.get(key="SASS_DIR")
bootstrap_theme = AppSettings.objects.get(key="BOOTSTRAP_THEME")
try:
themes_list = os.listdir(sass_dir.value + "/wvc-theme") themes_list = os.listdir(sass_dir.value + "/wvc-theme")
except FileNotFoundError as err:
error_messages.append(err)
addlogmsg(request.user.username, "", err)
# Bootstrap settings related with filesystems, because of that they are excluded from other settings
appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name")
if request.method == 'POST': if request.method == 'POST':
if 'SASS_DIR' in request.POST:
try:
sass_dir.value = request.POST.get("SASS_DIR", "")
sass_dir.save()
msg = _(f"SASS directory path is changed. Now: {sass_dir.value}")
messages.success(request, msg)
except Exception as err:
msg = err
error_messages.append(msg)
addlogmsg(request.user.username, "", msg)
return HttpResponseRedirect(request.get_full_path())
if 'BOOTSTRAP_THEME' in request.POST: if 'BOOTSTRAP_THEME' in request.POST:
theme = request.POST.get("BOOTSTRAP_THEME", "") 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';"
@ -56,26 +74,13 @@ 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 'SASS_DIR' in request.POST: for setting in appsettings:
if setting.key in request.POST:
try: try:
sass_dir.value = request.POST.get("SASS_DIR", "") setting.value = request.POST.get(setting.key, "")
sass_dir.save() setting.save()
msg = _(f"SASS directory path is changed. Now: {sass_dir.value}") msg = _(f"{setting.name} is changed. Now: {setting.value}")
messages.success(request, msg)
except Exception as err:
msg = err
error_messages.append(msg)
addlogmsg(request.user.username, "", msg)
return HttpResponseRedirect(request.get_full_path())
if 'VIEW_INSTANCE_DETAIL_BOTTOM_BAR' in request.POST:
try:
show_inst_bottom_bar.value = request.POST.get("VIEW_INSTANCE_DETAIL_BOTTOM_BAR", "")
show_inst_bottom_bar.save()
msg = _(f"Show bottom bar setting is changed. Now: {show_inst_bottom_bar.value}")
messages.success(request, msg) messages.success(request, msg)
except Exception as err: except Exception as err:
msg = err msg = err

View file

@ -115,6 +115,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}
{% block script %} {% block script %}
<script src="{% static "js/Chart.bundle.min.js" %}"></script> <script src="{% static "js/Chart.bundle.min.js" %}"></script>

View file

@ -3,8 +3,7 @@ from django.shortcuts import render
from libvirt import libvirtError from libvirt import libvirtError
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_PORT from webvirtcloud.settings import WS_PUBLIC_PORT, WS_PUBLIC_HOST
from webvirtcloud.settings import WS_PUBLIC_HOST
def console(request): def console(request):

View file

@ -83,7 +83,7 @@
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="addFromXML"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="addFromXML">
<div class="well"> <div>
<form method="post" role="form" aria-label="Create instance with XML form">{% csrf_token %} <form method="post" role="form" aria-label="Create instance with XML form">{% csrf_token %}
<div class="col-sm-12" id="xmlheight"> <div class="col-sm-12" id="xmlheight">
<input type="hidden" name="dom_xml"/> <input type="hidden" name="dom_xml"/>

View file

@ -199,7 +199,7 @@
<div class="col-sm-6"> <div class="col-sm-6">
<select id="cache_mode" name="cache_mode" class="custom-select"> <select id="cache_mode" name="cache_mode" class="custom-select">
{% for mode, name in cache_modes %} {% for mode, name in cache_modes %}
<option value="{{ mode }}" {% ifequal mode default_cache %}selected {% endifequal %}> <option value="{{ mode }}" {% if mode == default_cache %}selected {% endif %}>
{% trans name %}</option> {% trans name %}</option>
{% endfor %} {% endfor %}
</select> </select>
@ -303,7 +303,7 @@
</div> </div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="addCustom"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="addCustom">
<div class="well"> <div>
<form method="post" role="form" aria-label="Create custom instance form">{% csrf_token %} <form method="post" role="form" aria-label="Create custom instance form">{% csrf_token %}
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">{% trans "Name" %}</label> <label class="col-sm-3 col-form-label">{% trans "Name" %}</label>
@ -423,7 +423,7 @@
<div class="col-sm-7"> <div class="col-sm-7">
<select id="cache_mode" name="cache_mode" class="form-control"> <select id="cache_mode" name="cache_mode" class="form-control">
{% for mode, name in cache_modes %} {% for mode, name in cache_modes %}
<option value="{{ mode }}" {% ifequal mode default_cache %}selected {% endifequal %}> <option value="{{ mode }}" {% if mode == default_cache %}selected {% endif %}>
{% trans name %}</option> {% trans name %}</option>
{% endfor %} {% endfor %}
</select> </select>
@ -516,7 +516,7 @@
</div> </div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="addFromTemp"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="addFromTemp">
<div class="well"> <div>
<form method="post" role="form" aria-label="Create instance from template form">{% csrf_token %} <form method="post" role="form" aria-label="Create instance from template form">{% csrf_token %}
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">{% trans "Name" %}</label> <label class="col-sm-3 col-form-label">{% trans "Name" %}</label>
@ -636,7 +636,7 @@
<div class="col-sm-7"> <div class="col-sm-7">
<select id="cache_mode" name="cache_mode" class="custom-select"> <select id="cache_mode" name="cache_mode" class="custom-select">
{% for mode, name in cache_modes %} {% for mode, name in cache_modes %}
<option value="{{ mode }}" {% ifequal mode default_cache %}selected{% endifequal %}> <option value="{{ mode }}" {% if mode == default_cache %}selected{% endif %}>
{% trans name %}</option> {% trans name %}</option>
{% endfor %} {% endfor %}
</select> </select>
@ -788,8 +788,7 @@
'{% endfor %}' + '{% endfor %}' +
'</select>' + '</select>' +
' -> ' + value + ' ' + ' -> ' + value + ' ' +
'<a class="btn-link float-right" onclick="javascript:$(\'#image-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a>' + '<a class="btn-link float-right" onclick="javascript:$(\'#image-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a></li>';
'</li>';
selected_list_html += li; selected_list_html += li;
counter++; counter++;
}); });
@ -797,7 +796,6 @@
$('#disk_list_div').addClass('d-none'); $('#disk_list_div').addClass('d-none');
} }
$('#img-list').html(selected_list_html); $('#img-list').html(selected_list_html);
} }
}); });
@ -822,7 +820,7 @@
$.each(input_value.split(','), function (index, value) { $.each(input_value.split(','), function (index, value) {
let li = '<li>eth' + counter + let li = '<li>eth' + counter +
' -> ' + value + ' ' + ' -> ' + value + ' ' +
'<a class="btn-link float-right" onclick="$(\'#network-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a></a></li>'; '<a class="btn-link float-right" onclick="$(\'#network-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a></li>';
selected_list_html += li; selected_list_html += li;
counter++; counter++;
}); });

View file

@ -8,23 +8,12 @@ from admin.decorators import superuser_only
from computes.models import Compute from computes.models import Compute
from create.models import Flavor from create.models import Flavor
from create.forms import FlavorAddForm, NewVMForm from create.forms import FlavorAddForm, NewVMForm
from appsettings.models import AppSettings
from instances.models import Instance from instances.models import Instance
from vrtManager.create import wvmCreate from vrtManager.create import wvmCreate
from vrtManager import util from vrtManager import util
from logs.views import addlogmsg from logs.views import addlogmsg
from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_CACHE
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_BUS
from webvirtcloud.settings import INSTANCE_CPU_DEFAULT_MODE
from webvirtcloud.settings import INSTANCE_MACHINE_DEFAULT_TYPE
from webvirtcloud.settings import QEMU_CONSOLE_DEFAULT_TYPE
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_IO
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DISCARD
from webvirtcloud.settings import INSTANCE_ARCH_DEFAULT_TYPE
from webvirtcloud.settings import INSTANCE_FIRMWARE_DEFAULT_TYPE
@superuser_only @superuser_only
def create_instance_select_type(request, compute_id): def create_instance_select_type(request, compute_id):
@ -40,6 +29,7 @@ def create_instance_select_type(request, compute_id):
hypervisors = list() hypervisors = list()
meta_prealloc = False meta_prealloc = False
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
appsettings = AppSettings.objects.all()
try: try:
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type) conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
@ -48,8 +38,8 @@ def create_instance_select_type(request, compute_id):
# Supported hypervisors by webvirtcloud: i686, x86_64(for now) # Supported hypervisors by webvirtcloud: i686, x86_64(for now)
supported_arch = ["x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"] supported_arch = ["x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"]
hypervisors = [hpv for hpv in all_hypervisors.keys() if hpv in supported_arch] hypervisors = [hpv for hpv in all_hypervisors.keys() if hpv in supported_arch]
default_machine = INSTANCE_MACHINE_DEFAULT_TYPE default_machine = appsettings.get(key="INSTANCE_MACHINE_DEFAULT_TYPE").value
default_arch = INSTANCE_ARCH_DEFAULT_TYPE default_arch = appsettings.get(key="INSTANCE_ARCH_DEFAULT_TYPE").value
if request.method == 'POST': if request.method == 'POST':
if 'create_xml' in request.POST: if 'create_xml' in request.POST:
@ -93,28 +83,33 @@ def create_instance(request, compute_id, arch, machine):
meta_prealloc = False meta_prealloc = False
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
flavors = Flavor.objects.filter().order_by('id') flavors = Flavor.objects.filter().order_by('id')
appsettings = AppSettings.objects.all()
try: try:
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type) conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
default_firmware = INSTANCE_FIRMWARE_DEFAULT_TYPE default_firmware = appsettings.get(key="INSTANCE_FIRMWARE_DEFAULT_TYPE").value
default_cpu_mode = INSTANCE_CPU_DEFAULT_MODE default_cpu_mode = appsettings.get(key="INSTANCE_CPU_DEFAULT_MODE").value
instances = conn.get_instances() instances = conn.get_instances()
videos = conn.get_video_models(arch, machine) videos = conn.get_video_models(arch, machine)
cache_modes = sorted(conn.get_cache_modes().items()) cache_modes = sorted(conn.get_cache_modes().items())
default_cache = INSTANCE_VOLUME_DEFAULT_CACHE.lower() default_cache = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_CACHE").value
default_io = INSTANCE_VOLUME_DEFAULT_IO.lower() default_io = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_IO").value
default_zeroes = INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES.lower() default_zeroes = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES").value
default_discard = INSTANCE_VOLUME_DEFAULT_DISCARD.lower() default_discard = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_DISCARD").value
default_disk_format = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_FORMAT").value
default_disk_owner_uid = int(appsettings.get(key="INSTANCE_VOLUME_DEFAULT_OWNER_UID").value)
default_disk_owner_gid = int(appsettings.get(key="INSTANCE_VOLUME_DEFAULT_OWNER_GID").value)
default_scsi_disk_model = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER").value
listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES
mac_auto = util.randomMAC() mac_auto = util.randomMAC()
disk_devices = conn.get_disk_device_types(arch, machine) disk_devices = conn.get_disk_device_types(arch, machine)
disk_buses = conn.get_disk_bus_types(arch, machine) disk_buses = conn.get_disk_bus_types(arch, machine)
default_bus = INSTANCE_VOLUME_DEFAULT_BUS default_bus = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_BUS").value
networks = sorted(conn.get_networks()) networks = sorted(conn.get_networks())
nwfilters = conn.get_nwfilters() nwfilters = conn.get_nwfilters()
storages = sorted(conn.get_storages(only_actives=True)) storages = sorted(conn.get_storages(only_actives=True))
default_graphics = QEMU_CONSOLE_DEFAULT_TYPE default_graphics = appsettings.get(key="QEMU_CONSOLE_DEFAULT_TYPE").value
dom_caps = conn.get_dom_capabilities(arch, machine) dom_caps = conn.get_dom_capabilities(arch, machine)
caps = conn.get_capabilities(arch) caps = conn.get_capabilities(arch)
@ -177,18 +172,29 @@ def create_instance(request, compute_id, arch, machine):
error_messages.append(error_msg) error_messages.append(error_msg)
else: else:
try: try:
path = conn.create_volume(data['storage'], path = conn.create_volume(
data['storage'],
data['name'], data['name'],
data['hdd_size'], data['hdd_size'],
metadata=meta_prealloc) default_disk_format,
meta_prealloc,
default_disk_owner_uid,
default_disk_owner_gid)
volume = dict() volume = dict()
volume['device'] = 'disk'
volume['path'] = path volume['path'] = path
volume['type'] = conn.get_volume_type(path) volume['type'] = conn.get_volume_type(path)
volume['device'] = 'disk' volume['cache_mode'] = data['cache_mode']
if data['virtio']: volume['bus'] = default_bus
volume['bus'] = INSTANCE_VOLUME_DEFAULT_BUS if volume['bus'] == 'scsi':
volume['scsi_model'] = default_scsi_disk_model
volume['discard_mode'] = default_discard
volume['detect_zeroes_mode'] = default_zeroes
volume['io_mode'] = default_io
volume_list.append(volume) volume_list.append(volume)
is_disk_created = True is_disk_created = True
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err) error_messages.append(lib_err)
elif data['template']: elif data['template']:
@ -198,16 +204,25 @@ def create_instance(request, compute_id, arch, machine):
error_msg = _("Image has already exist. Please check volumes or change instance name") error_msg = _("Image has already exist. Please check volumes or change instance name")
error_messages.append(error_msg) error_messages.append(error_msg)
else: else:
clone_path = conn.clone_from_template(data['name'], clone_path = conn.clone_from_template(
data['name'],
templ_path, templ_path,
data['storage'], data['storage'],
metadata=meta_prealloc) meta_prealloc,
default_disk_owner_uid,
default_disk_owner_gid)
volume = dict() volume = dict()
volume['path'] = clone_path volume['path'] = clone_path
volume['type'] = conn.get_volume_type(clone_path) volume['type'] = conn.get_volume_type(clone_path)
volume['device'] = 'disk' volume['device'] = 'disk'
if data['virtio']: volume['cache_mode'] = data['cache_mode']
volume['bus'] = INSTANCE_VOLUME_DEFAULT_BUS volume['bus'] = default_bus
if volume['bus'] == 'scsi':
volume['scsi_model'] = default_scsi_disk_model
volume['discard_mode'] = default_discard
volume['detect_zeroes_mode'] = default_zeroes
volume['io_mode'] = default_io
volume_list.append(volume) volume_list.append(volume)
is_disk_created = True is_disk_created = True
else: else:
@ -223,6 +238,13 @@ def create_instance(request, compute_id, arch, machine):
volume['type'] = conn.get_volume_type(path) volume['type'] = conn.get_volume_type(path)
volume['device'] = request.POST.get('device' + str(idx), '') volume['device'] = request.POST.get('device' + str(idx), '')
volume['bus'] = request.POST.get('bus' + str(idx), '') volume['bus'] = request.POST.get('bus' + str(idx), '')
if volume['bus'] == 'scsi':
volume['scsi_model'] = default_scsi_disk_model
volume['cache_mode'] = data['cache_mode']
volume['discard_mode'] = default_discard
volume['detect_zeroes_mode'] = default_zeroes
volume['io_mode'] = default_io
volume_list.append(volume) volume_list.append(volume)
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err) error_messages.append(lib_err)
@ -253,11 +275,7 @@ def create_instance(request, compute_id, arch, machine):
arch=arch, arch=arch,
machine=machine, machine=machine,
firmware=firmware, firmware=firmware,
images=volume_list, volumes=volume_list,
cache_mode=data['cache_mode'],
io_mode=default_io,
discard_mode=default_discard,
detect_zeroes_mode=default_zeroes,
networks=data['networks'], networks=data['networks'],
virtio=data['virtio'], virtio=data['virtio'],
listen_addr=data["listener_addr"], listen_addr=data["listener_addr"],
@ -269,7 +287,7 @@ def create_instance(request, compute_id, arch, machine):
qemu_ga=data['qemu_ga']) qemu_ga=data['qemu_ga'])
create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid) create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
create_instance.save() create_instance.save()
msg = _("Instance is created.") msg = _("Instance is created")
messages.success(request, msg) messages.success(request, msg)
addlogmsg(request.user.username, create_instance.name, msg) addlogmsg(request.user.username, create_instance.name, msg)
return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']])) return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']]))

View file

@ -1,12 +1,9 @@
from django.conf.urls import url from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^openstack/$', path('openstack/', views.os_index, name='ds_openstack_index'),
views.os_index, name='ds_openstack_index'), path('openstack/<version>/meta_data.json', views.os_metadata_json, name='ds_openstack_metadata'),
url(r'^openstack/(?P<version>[\w\-\.]+)/meta_data.json$', path('openstack/<version>/user_data', views.os_userdata, name='ds_openstack_userdata'),
views.os_metadata_json, name='ds_openstack_metadata'), path('vdi/<int:compute_id>/<vname>/', views.get_vdi_url, name='vdi_url'),
url(r'^openstack/(?P<version>[\w\-\.]+)/user_data$',
views.os_userdata, name='ds_openstack_userdata'),
url(r'^vdi/(?P<compute_id>[0-9]+)/(?P<vname>[\w\-\.]+)/$', views.get_vdi_url, name='vdi_url'),
] ]

View file

@ -1,3 +1,3 @@
@import 'dev/scss/wvc-theme/flatly/variables'; @import 'dev/scss//wvc-theme/flatly/variables';
@import 'dev/scss/bootstrap-overrides.scss'; @import 'dev/scss//bootstrap-overrides.scss';
@import 'dev/scss/wvc-theme/flatly/bootswatch'; @import 'dev/scss//wvc-theme/flatly/bootswatch';

View file

@ -121,7 +121,7 @@
<div role="tabpanel"> <div role="tabpanel">
<!-- Nav tabs --> <!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist" aria-label="Instance power actions"> <ul class="nav nav-tabs" role="tablist" aria-label="Instance power actions">
{% ifequal status 1 %} {% if status == 1 %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary active" href="#poweroff" aria-controls="poweroff" role="tab" data-toggle="tab"> <a class="nav-link text-secondary active" href="#poweroff" aria-controls="poweroff" role="tab" data-toggle="tab">
{% trans "Power Off" %} {% trans "Power Off" %}
@ -144,8 +144,8 @@
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% endifequal %} {% endif %}
{% ifequal status 3 %} {% if status == 3 %}
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary" href="#resume" aria-controls="resume" role="tab" data-toggle="tab"> <a class="nav-link text-secondary" href="#resume" aria-controls="resume" role="tab" data-toggle="tab">
@ -158,18 +158,18 @@
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% endifequal %} {% endif %}
{% ifequal status 5 %} {% if status == 5 %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary active" href="#boot" aria-controls="boot" role="tab" data-toggle="tab"> <a class="nav-link text-secondary active" href="#boot" aria-controls="boot" role="tab" data-toggle="tab">
{% trans "Power On" %} {% trans "Power On" %}
</a> </a>
</li> </li>
{% endifequal %} {% endif %}
</ul> </ul>
<!-- Tab panes --> <!-- Tab panes -->
<div class="tab-content"> <div class="tab-content">
{% ifequal status 1 %} {% if status == 1 %}
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="poweroff"> <div role="tabpanel" class="tab-pane tab-pane-bordered active" id="poweroff">
<p>{% trans "This action sends an ACPI shutdown signal to the instance." %}</p> <p>{% trans "This action sends an ACPI shutdown signal to the instance." %}</p>
<form action="" method="post" role="form" aria-label0="Power off instance form">{% csrf_token %} <form action="" method="post" role="form" aria-label0="Power off instance form">{% csrf_token %}
@ -200,8 +200,8 @@
</form> </form>
</div> </div>
{% endif %} {% endif %}
{% endifequal %} {% endif %}
{% ifequal status 3 %} {% if status == 3 %}
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resume"> <div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resume">
<p>{% trans "This action restore the instance after suspend." %}</p> <p>{% trans "This action restore the instance after suspend." %}</p>
@ -226,8 +226,8 @@
</form> </form>
</div> </div>
{% endif %} {% endif %}
{% endifequal %} {% endif %}
{% ifequal status 5 %} {% if status == 5 %}
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="boot"> <div role="tabpanel" class="tab-pane tab-pane-bordered active" id="boot">
<p>{% trans "Click on Boot button to start this instance." %}</p> <p>{% trans "Click on Boot button to start this instance." %}</p>
<form action="" method="post" role="form" aria-label="Start instance form">{% csrf_token %} <form action="" method="post" role="form" aria-label="Start instance form">{% csrf_token %}
@ -240,7 +240,7 @@
<div class="clearfix"></div> <div class="clearfix"></div>
</form> </form>
</div> </div>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -253,33 +253,33 @@
{% trans "Console" %} {% trans "Console" %}
</a> </a>
</li> </li>
{% if show_access_root_password %} {% if show_access_root_password == 'True' %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary" href="#rootpasswd" aria-controls="rootpasswd" role="tab" data-toggle="tab"> <a class="nav-link text-secondary" href="#rootpasswd" aria-controls="rootpasswd" role="tab" data-toggle="tab">
{% trans "Root Password" %} {% trans "Root Password" %}
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% if show_access_ssh_keys %} {% if show_access_ssh_keys == 'True' %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary" href="#sshkeys" aria-controls="sshkeys" role="tab" data-toggle="tab"> <a class="nav-link text-secondary" href="#sshkeys" aria-controls="sshkeys" role="tab" data-toggle="tab">
{% trans "SSH Keys" %} {% trans "SSH Keys" %}
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% ifequal status 1 %} {% if status == 1 %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-secondary" href="#vdiconsole" aria-controls="vdiconsole" role="tab" data-toggle="tab"> <a class="nav-link text-secondary" href="#vdiconsole" aria-controls="vdiconsole" role="tab" data-toggle="tab">
{% trans "VDI" %} {% trans "VDI" %}
</a> </a>
</li> </li>
{% endifequal %} {% endif %}
</ul> </ul>
<!-- Tab panes --> <!-- Tab panes -->
<div class="tab-content"> <div class="tab-content">
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="vnconsole"> <div role="tabpanel" class="tab-pane tab-pane-bordered active" id="vnconsole">
<p>{% trans "This action opens a new window with a VNC connection to the console of the instance." %}</p> <p>{% trans "This action opens a new window with a VNC connection to the console of the instance." %}</p>
{% ifequal status 1 %} {% if status == 1 %}
<!-- Split button --> <!-- Split button -->
<div class="btn-group float-right"> <div class="btn-group float-right">
<button type="button" id="consoleBtnGroup" class="btn btn-lg btn-success" onclick="open_console('lite')">{% trans 'Console' %}</button> <button type="button" id="consoleBtnGroup" class="btn btn-lg btn-success" onclick="open_console('lite')">{% trans 'Console' %}</button>
@ -293,10 +293,10 @@
</div> </div>
{% else %} {% else %}
<button class="btn btn-lg btn-success float-right disabled">{% trans "Console" %}</button> <button class="btn btn-lg btn-success float-right disabled">{% trans "Console" %}</button>
{% endifequal %} {% endif %}
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
{% if show_access_root_password %} {% if show_access_root_password == 'True' %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="rootpasswd"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="rootpasswd">
<p>{% trans "You need shut down your instance and enter a new root password." %}</p> <p>{% trans "You need shut down your instance and enter a new root password." %}</p>
<form class="form-inline" method="post" role="form" aria-label="Add root password to instance form">{% csrf_token %} <form class="form-inline" method="post" role="form" aria-label="Add root password to instance form">{% csrf_token %}
@ -305,22 +305,22 @@
<input type="text" class="form-control-lg" name="passwd" placeholder="{% trans "Enter Password" %}" maxlength="24"> <input type="text" class="form-control-lg" name="passwd" placeholder="{% trans "Enter Password" %}" maxlength="24">
</div> </div>
</div> </div>
{% ifequal status 5 %} {% if status == 5 %}
<input type="submit" class="btn btn-lg btn-success float-right" name="rootpasswd" value="{% trans "Reset Root Password" %}"> <input type="submit" class="btn btn-lg btn-success float-right" name="rootpasswd" value="{% trans "Reset Root Password" %}">
{% else %} {% else %}
<button class="btn btn-lg btn-success float-right disabled">{% trans "Reset Root Password" %}</button> <button class="btn btn-lg btn-success float-right disabled">{% trans "Reset Root Password" %}</button>
{% endifequal %} {% endif %}
</form> </form>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
{% endif %} {% endif %}
{% if show_access_ssh_keys %} {% if show_access_ssh_keys == 'True' %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="sshkeys"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="sshkeys">
<p>{% trans "You need shut down your instance and choose your public key." %}</p> <p>{% trans "You need shut down your instance and choose your public key." %}</p>
<form class="form-inline" method="post" role="form" aria-label="Add public key to instance form">{% csrf_token %} <form class="form-inline" method="post" role="form" aria-label="Add public key to instance form">{% csrf_token %}
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-12"> <div class="col-sm-12">
<select name="sshkeyid" class="form-control keyselect"> <select name="sshkeyid" class="form-control-lg keyselect">
{% if publickeys %} {% if publickeys %}
{% for key in publickeys %} {% for key in publickeys %}
<option value="{{ key.id }}">{{ key.keyname }}</option> <option value="{{ key.id }}">{{ key.keyname }}</option>
@ -331,16 +331,16 @@
</select> </select>
</div> </div>
</div> </div>
{% ifequal status 5 %} {% if status == 5 %}
<input type="submit" class="btn btn-lg btn-success float-right" name="addpublickey" value="{% trans "Add Public Key" %}"> <input type="submit" class="btn btn-lg btn-success float-right" name="addpublickey" value="{% trans "Add Public Key" %}">
{% else %} {% else %}
<button class="btn btn-lg btn-success float-right disabled">{% trans "Add Public Key" %}</button> <button class="btn btn-lg btn-success float-right disabled">{% trans "Add Public Key" %}</button>
{% endifequal %} {% endif %}
</form> </form>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
{% endif %} {% endif %}
{% ifequal status 1 %} {% if status == 1 %}
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="vdiconsole"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="vdiconsole">
<p>{% trans "This action opens a remote viewer with a connection to the console of the instance." %}</p> <p>{% trans "This action opens a remote viewer with a connection to the console of the instance." %}</p>
<div class="input-group"> <div class="input-group">
@ -351,7 +351,7 @@
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -408,11 +408,11 @@
</div> </div>
</div> </div>
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-lg btn-success float-right" name="resizevm_cpu">{% trans "Resize" %}</button> <button type="submit" class="btn btn-lg btn-success float-right" name="resizevm_cpu">{% trans "Resize" %}</button>
{% else %} {% else %}
<button class="btn btn-lg btn-success float-right disabled">{% trans "Resize" %}</button> <button class="btn btn-lg btn-success float-right disabled">{% trans "Resize" %}</button>
{% endifequal %} {% endif %}
</form> </form>
<div class="clearfix"></div> <div class="clearfix"></div>
{% else %} {% else %}
@ -493,11 +493,11 @@
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-lg btn-success float-right" name="resizevm_disk">{% trans "Resize" %}</button> <button type="submit" class="btn btn-lg btn-success float-right" name="resizevm_disk">{% trans "Resize" %}</button>
{% else %} {% else %}
<button class="btn btn-lg btn-success float-right disabled">{% trans "Resize" %}</button> <button class="btn btn-lg btn-success float-right disabled">{% trans "Resize" %}</button>
{% endifequal %} {% endif %}
</form> </form>
{% else %} {% else %}
{% trans "You don't have permission for resizing instance" %} {% trans "You don't have permission for resizing instance" %}
@ -526,7 +526,7 @@
<!-- Tab panes --> <!-- Tab panes -->
<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">
{% ifequal status 5 %} {% if 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 droplet and how large the disk is." %}</p>
<form class="form-inline" method="post" role="form" aria-label="Create snapshot form">{% csrf_token %} <form class="form-inline" method="post" role="form" aria-label="Create snapshot form">{% csrf_token %}
<div class="form-group row"> <div class="form-group row">
@ -534,16 +534,16 @@
<input type="text" class="form-control form-control-lg" name="name" placeholder="{% trans "Enter Snapshot Name" %}" maxlength="14"> <input type="text" class="form-control form-control-lg" name="name" placeholder="{% trans "Enter Snapshot Name" %}" maxlength="14">
</div> </div>
</div> </div>
{% ifequal status 5 %} {% if status == 5 %}
<input type="submit" class="btn btn-lg btn-success float-right" name="snapshot" value="{% trans "Take Snapshot" %}"> <input type="submit" class="btn btn-lg btn-success float-right" name="snapshot" value="{% trans "Take Snapshot" %}">
{% else %} {% else %}
<button class="btn btn-lg btn-success float-right disabled">{% trans "Take Snapshot" %}</button> <button class="btn btn-lg btn-success float-right disabled">{% trans "Take Snapshot" %}</button>
{% endifequal %} {% endif %}
</form> </form>
<div class="clearfix"></div> <div class="clearfix"></div>
{% else %} {% else %}
<p>{% trans "To take a snapshot please Power Off the instance." %}</p> <p>{% trans "To take a snapshot please Power Off the instance." %}</p>
{% endifequal %} {% endif %}
</div> </div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="managesnapshot"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="managesnapshot">
{% if snapshots %} {% if snapshots %}
@ -563,7 +563,7 @@
<td style="width:30px;"> <td style="width:30px;">
<form action="" method="post" role="form" aria-label="Restore snapshot form">{% csrf_token %} <form action="" method="post" role="form" aria-label="Restore snapshot form">{% csrf_token %}
<input type="hidden" name="name" value="{{ snap.name }}"> <input type="hidden" name="name" value="{{ snap.name }}">
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-sm btn-secondary" name="revert_snapshot" title="{% trans 'Revert to this Snapshot' %}" onclick="return confirm('Are you sure?')"> <button type="submit" class="btn btn-sm btn-secondary" name="revert_snapshot" title="{% trans 'Revert to this Snapshot' %}" onclick="return confirm('Are you sure?')">
<span class="fa fa-download"></span> <span class="fa fa-download"></span>
</button> </button>
@ -572,7 +572,7 @@
title="{% trans "To restore snapshots you need Power Off the instance." %}"> title="{% trans "To restore snapshots you need Power Off the instance." %}">
<span class="fa fa-download"></span> <span class="fa fa-download"></span>
</button> </button>
{% endifequal %} {% endif %}
</form> </form>
</td> </td>
<td style="width:30px;"> <td style="width:30px;">
@ -668,11 +668,11 @@
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-12 text-center"> <div class="col-sm-12 text-center">
<p>{% trans "Autostart your instance when host server is power on " %} <p>{% trans "Autostart your instance when host server is power on " %}
{% ifequal autostart 0 %} {% if autostart == 0 %}
<input type="submit" class="btn btn-success" name="set_autostart" value="{% trans "Enable" %}"> <input type="submit" class="btn btn-success" name="set_autostart" value="{% trans "Enable" %}">
{% else %} {% else %}
<input type="submit" class="btn btn-danger" name="unset_autostart" value="{% trans "Disable" %}"> <input type="submit" class="btn btn-danger" name="unset_autostart" value="{% trans "Disable" %}">
{% endifequal %} {% endif %}
</p> </p>
</div> </div>
</div> </div>
@ -681,23 +681,23 @@
<form action="" method="post" role="form" aria-label="Enable/disable instance boot order form">{% csrf_token %} <form action="" method="post" role="form" aria-label="Enable/disable instance boot order form">{% csrf_token %}
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-12 text-center"> <div class="col-sm-12 text-center">
{% ifequal status 5 %} {% if status == 5 %}
<p>{% trans "Enable Boot Menu for your instance when it starts up " %} <p>{% trans "Enable Boot Menu for your instance when it starts up " %}
{% ifequal bootmenu 0 %} {% if bootmenu == 0 %}
<input type="submit" class="btn btn-success" name="set_bootmenu" title="{% trans 'Show boot menu' %}" value="{% trans "Enable" %}"> <input type="submit" class="btn btn-success" name="set_bootmenu" title="{% trans 'Show boot menu' %}" value="{% trans "Enable" %}">
{% else %} {% else %}
<input type="submit" class="btn btn-danger" name="unset_bootmenu" title="{% trans 'Hide boot menu' %}" value="{% trans "Disable" %}"> <input type="submit" class="btn btn-danger" name="unset_bootmenu" title="{% trans 'Hide boot menu' %}" value="{% trans "Disable" %}">
{% endifequal %} {% endif %}
{% else %} {% else %}
{% ifequal bootmenu 0 %} {% if bootmenu == 0 %}
<p>**** {% trans "Please shutdown instance to modify boot menu" %} ****</p> <p>**** {% trans "Please shutdown instance to modify boot menu" %} ****</p>
{% endifequal %} {% endif %}
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</form> </form>
{% ifequal bootmenu 1 %} {% if bootmenu == 1 %}
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<div class="col-sm-6 bg-light rounded shadow-sm"> <div class="col-sm-6 bg-light rounded shadow-sm">
{% for idx, val in boot_order.items %} {% for idx, val in boot_order.items %}
@ -734,7 +734,7 @@
</div> </div>
</div> </div>
</form> </form>
{% endifequal %} {% endif %}
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="disks"> <div role="tabpanel" class="tab-pane tab-pane-bordered" id="disks">
@ -866,7 +866,7 @@
<input type="hidden" name="storage" value="{{ disk.storage }}"> <input type="hidden" name="storage" value="{{ disk.storage }}">
<input type="hidden" name="name" value="{{ disk.image }}"> <input type="hidden" name="name" value="{{ disk.image }}">
{% include 'edit_instance_volume.html' with id=forloop.counter0 %} {% include 'edit_instance_volume.html' with id=forloop.counter0 %}
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-sm btn-secondary" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume?" %}')"> <button type="submit" class="btn btn-sm btn-secondary" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume?" %}')">
<i class="fa fa-eject"></i> <i class="fa fa-eject"></i>
</button> </button>
@ -880,9 +880,8 @@
<button class="btn btn-sm btn-secondary disabled" name="delete_vol" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure? This may lead data corruption!" %}')"> <button class="btn btn-sm btn-secondary disabled" name="delete_vol" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure? This may lead data corruption!" %}')">
<i class="fa fa-trash"></i> <i class="fa fa-trash"></i>
</button> </button>
{% endifequal %} {% endif %}
</form> </form>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -957,10 +956,10 @@
<input class="form-control" type="text" value="{{ network.nic }}" readonly/> <input class="form-control" type="text" value="{{ network.nic }}" readonly/>
<select class="form-control" name="net-source-{{ forloop.counter0 }}"> <select class="form-control" name="net-source-{{ forloop.counter0 }}">
{% for c_net in networks_host %} {% for c_net in networks_host %}
<option value="net:{{ c_net }}" {% ifequal c_net network.nic %} selected {% endifequal %}>{% trans 'Network' %} {{ c_net }}</option> <option value="net:{{ c_net }}" {% if c_net == network.nic %} selected {% endif %}>{% trans 'Network' %} {{ c_net }}</option>
{% endfor %} {% endfor %}
{% for c_iface in interfaces_host %} {% for c_iface in interfaces_host %}
<option value="iface:{{ c_iface }}" {% ifequal c_iface network.nic %} selected {% endifequal %}>{% trans 'Interface' %} {{ c_iface }}</option> <option value="iface:{{ c_iface }}" {% if c_iface == network.nic %} selected {% endif %}>{% trans 'Interface' %} {{ c_iface }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -972,7 +971,7 @@
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}"> <select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
<option value="">{% trans "None" %}</option> <option value="">{% trans "None" %}</option>
{% for c_filters in nwfilters_host %} {% for c_filters in nwfilters_host %}
<option value="{{ c_filters }}" {% ifequal c_filters network.filterref %} selected {% endifequal %}>{{ c_filters }}</option> <option value="{{ c_filters }}" {% if c_filters == network.filterref %} selected {% endif %}>{{ c_filters }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -983,7 +982,7 @@
<input class="form-control" type="text" value="{{ network.model }}" readonly/> <input class="form-control" type="text" value="{{ network.model }}" readonly/>
<select class="form-control" name="net-model-{{ forloop.counter0 }}"> <select class="form-control" name="net-model-{{ forloop.counter0 }}">
{% for model in net_models_host %} {% for model in net_models_host %}
<option value="{{ model }}" {% ifequal model network.model %} selected {% endifequal %}>{{ model }}</option> <option value="{{ model }}" {% if model == network.model %} selected {% endif %}>{{ model }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -992,7 +991,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-secondary" data-dismiss="modal">{% trans 'Close' %}</button> <button class="btn btn-secondary" data-dismiss="modal">{% trans 'Close' %}</button>
<button class="btn btn-success" name="change_network" title="{% trans "Apply Network Changes" %}">{% trans "Apply" %}</button> <button class="btn btn-success" name="change_network" title="{% trans "Apply network changes" %}">{% trans "Apply" %}</button>
</div> </div>
</div> </div>
</div> </div>
@ -1116,7 +1115,7 @@
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-6 offset-3"> <div class="col-sm-6 offset-3">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input class="custom-control-input" type="checkbox" name="live_migrate" value="true" id="vm_live_migrate" {% ifnotequal status 5 %}checked{% else %}disabled{% endifnotequal %}> <input class="custom-control-input" type="checkbox" name="live_migrate" value="true" id="vm_live_migrate" {% if status != 5 %}checked{% else %}disabled{% endif %}>
<label class="custom-control-label" for="vm_live_migrate">{% trans "Live migration" %}</label> <label class="custom-control-label" for="vm_live_migrate">{% trans "Live migration" %}</label>
</div> </div>
</div> </div>
@ -1140,7 +1139,7 @@
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-6 offset-3"> <div class="col-sm-6 offset-3">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input class="custom-control-input" type="checkbox" name="offline_migrate" value="true" id="offline_migrate" {% ifequal status 5 %}checked{% else %}disabled{% endifequal %}> <input class="custom-control-input" type="checkbox" name="offline_migrate" value="true" id="offline_migrate" {% if status == 5 %}checked{% else %}disabled{% endif %}>
<label class="custom-control-label" for="offline_migrate">{% trans "Offline migration" %}</label> <label class="custom-control-label" for="offline_migrate">{% trans "Offline migration" %}</label>
</div> </div>
</div> </div>
@ -1148,7 +1147,7 @@
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-6 offset-3"> <div class="col-sm-6 offset-3">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input class="custom-control-input" type="checkbox" name="postcopy" value="true" id="postcopy" {% ifnotequal status 1 %}disabled{% endifnotequal %}> <input class="custom-control-input" type="checkbox" name="postcopy" value="true" id="postcopy" {% if status != 1 %}disabled{% endif %}>
<label class="custom-control-label" for="postcopy">{% trans "Post copy" %}</label> <label class="custom-control-label" for="postcopy">{% trans "Post copy" %}</label>
</div> </div>
</div> </div>
@ -1156,7 +1155,7 @@
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-6 offset-3"> <div class="col-sm-6 offset-3">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input class="custom-control-input" type="checkbox" name="autoconverge" value="true" id="autoconverge" {% ifnotequal status 1 %}disabled{% endifnotequal %}> <input class="custom-control-input" type="checkbox" name="autoconverge" value="true" id="autoconverge" {% if status != 1 %}disabled{% endif %}>
<label class="custom-control-label" for="autoconverge" title="{% trans 'Forces CPU convergence during live migration' %}">{% trans "Auto converge" %}</label> <label class="custom-control-label" for="autoconverge" title="{% trans 'Forces CPU convergence during live migration' %}">{% trans "Auto converge" %}</label>
</div> </div>
</div> </div>
@ -1164,7 +1163,7 @@
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-6 offset-3"> <div class="col-sm-6 offset-3">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input class="custom-control-input" type="checkbox" name="compress" value="true" id="compress" {% ifnotequal status 1 %}disabled{% endifnotequal %}> <input class="custom-control-input" type="checkbox" name="compress" value="true" id="compress" {% if status != 1 %}disabled{% endif %}>
<label class="custom-control-label" for="compress" title="{% trans 'Compress instance memory for fast migration' %}">{% trans "Compressed" %}</label> <label class="custom-control-label" for="compress" title="{% trans 'Compress instance memory for fast migration' %}">{% trans "Compressed" %}</label>
</div> </div>
</div> </div>
@ -1183,7 +1182,7 @@
<div class="col-sm-12" id="xmlheight"> <div class="col-sm-12" id="xmlheight">
<textarea id="editor">{{ inst_xml }}</textarea> <textarea id="editor">{{ inst_xml }}</textarea>
</div> </div>
{% ifequal status 5 %} {% if status == 5 %}
<input type="hidden" name="inst_xml"> <input type="hidden" name="inst_xml">
<button type="submit" class="btn btn-lg btn-success float-right" name="change_xml"> <button type="submit" class="btn btn-lg btn-success float-right" name="change_xml">
{% trans "Change" %} {% trans "Change" %}
@ -1192,7 +1191,7 @@
<button class="btn btn-lg btn-success float-right disabled"> <button class="btn btn-lg btn-success float-right disabled">
{% trans "Change" %} {% trans "Change" %}
</button> </button>
{% endifequal %} {% endif %}
</form> </form>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
@ -1241,11 +1240,11 @@
</select> </select>
<div class="input-group-append"> <div class="input-group-append">
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-success " name="set_console_type">{% trans "Set" %}</button> <button type="submit" class="btn btn-success " name="set_console_type">{% trans "Set" %}</button>
{% else %} {% else %}
<button class="btn btn-success disabled" name="set_console_type">{% trans "Set" %}</button> <button class="btn btn-success disabled" name="set_console_type">{% trans "Set" %}</button>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -1264,11 +1263,11 @@
{% endfor %} {% endfor %}
</select> </select>
<div class="input-group-append"> <div class="input-group-append">
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-success " name="set_console_listen_address">{% trans "Set" %}</button> <button type="submit" class="btn btn-success " name="set_console_listen_address">{% trans "Set" %}</button>
{% else %} {% else %}
<button class="btn btn-success disabled" name="set_console_listen_address">{% trans "Set" %}</button> <button class="btn btn-success disabled" name="set_console_listen_address">{% trans "Set" %}</button>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -1302,11 +1301,11 @@
{% if console_passwd %} {% if console_passwd %}
<a href="#" name="console_show" class="btn btn-md btn-primary" onclick="show_console()">{% trans "Show" %}</a> <a href="#" name="console_show" class="btn btn-md btn-primary" onclick="show_console()">{% trans "Show" %}</a>
{% endif %} {% endif %}
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-success" name="set_console_passwd">{% trans "Set" %}</button> <button type="submit" class="btn btn-success" name="set_console_passwd">{% trans "Set" %}</button>
{% else %} {% else %}
<button class="btn btn-success disabled" name="set_console_passwd">{% trans "Set" %}</button> <button class="btn btn-success disabled" name="set_console_passwd">{% trans "Set" %}</button>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -1334,11 +1333,11 @@
</select> </select>
<div class="input-group-append"> <div class="input-group-append">
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-success" name="set_console_keymap">{% trans "Set" %}</button> <button type="submit" class="btn btn-success" name="set_console_keymap">{% trans "Set" %}</button>
{% else %} {% else %}
<button class="btn btn-success disabled" name="set_console_keymap">{% trans "Set" %}</button> <button class="btn btn-success disabled" name="set_console_keymap">{% trans "Set" %}</button>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -1410,14 +1409,14 @@
<div class="col-sm-6"> <div class="col-sm-6">
<div class="input-group"> <div class="input-group">
<input id="disk_name-{{ disk.dev }}" type="text" class="form-control" name="disk-{{ disk.dev }}" value="{{ disk.image }}"/> <input id="disk_name-{{ disk.dev }}" type="text" class="form-control" name="disk-{{ disk.dev }}" value="{{ disk.image }}"/>
{% ifequal disk.format 'qcow2' %} {% if disk.format == 'qcow2' %}
<div class="input-group-append"> <div class="input-group-append">
<span class="input-group-text" >{% trans 'Metadata' %}</span> <span class="input-group-text" >{% trans 'Metadata' %}</span>
<div class="input-group-text"> <div class="input-group-text">
<input type="checkbox" name="meta-{{ disk.dev }}" value="true"> <input type="checkbox" name="meta-{{ disk.dev }}" value="true">
</div> </div>
</div> </div>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
@ -1439,11 +1438,11 @@
<textarea name="clone-description" class="form-control"></textarea> <textarea name="clone-description" class="form-control"></textarea>
</div> </div>
</div> </div>
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-lg btn-success float-right" name="clone" onclick="showPleaseWaitDialog();">{% trans "Clone" %}</button> <button type="submit" class="btn btn-lg btn-success float-right" name="clone" onclick="showPleaseWaitDialog();">{% trans "Clone" %}</button>
{% else %} {% else %}
<button class="btn btn-lg btn-success float-right disabled" name="clone">{% trans "Clone" %}</button> <button class="btn btn-lg btn-success float-right disabled" name="clone">{% trans "Clone" %}</button>
{% endifequal %} {% endif %}
</form> </form>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
@ -1475,11 +1474,11 @@
</div> </div>
<div class="form-group row"> <div class="form-group row">
<div class="offset-3 col-sm-6"> <div class="offset-3 col-sm-6">
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-block btn-success" name="change_options">{% trans "Change" %}</button> <button type="submit" class="btn btn-block btn-success" name="change_options">{% trans "Change" %}</button>
{% else %} {% else %}
<button class="btn btn-block btn-success disabled" name="change_options">{% trans "Change" %}</button> <button class="btn btn-block btn-success disabled" name="change_options">{% trans "Change" %}</button>
{% endifequal %} {% endif %}
</div> </div>
</div> </div>
</form> </form>
@ -1497,11 +1496,11 @@
{% endfor %} {% endfor %}
</select> </select>
<span class="input-group-btn"> <span class="input-group-btn">
{% ifequal status 5 %} {% if status == 5 %}
<button type="submit" class="btn btn-success" name="set_video_model">{% trans "Set" %}</button> <button type="submit" class="btn btn-success" name="set_video_model">{% trans "Set" %}</button>
{% else %} {% else %}
<button class="btn btn-success disabled" name="set_video_model">{% trans "Set" %}</button> <button class="btn btn-success disabled" name="set_video_model">{% trans "Set" %}</button>
{% endifequal %} {% endif %}
</span> </span>
</div> </div>
</div> </div>
@ -1669,10 +1668,9 @@
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="destroy"> <div role="tabpanel" class="tab-pane tab-pane-bordered active" id="destroy">
<p>{% trans "Delete storage for instance?" %}</p> <p>{% trans "Delete storage for instance?" %}</p>
{% if request.user.is_superuser or userinstance.is_delete %} {% if request.user.is_superuser or userinstance.is_delete %}
{% ifequal status 3 %} {% if status == 3 %}
<button class="btn btn-lg btn-success disabled float-right" name="delete">{% trans "Destroy" %}</button> <button class="btn btn-lg btn-success disabled float-right" name="delete">{% trans "Destroy" %}</button>
{% else %} {% else %}
<form class="form" method="post" role="form" id="delete_form">{% csrf_token %} <form class="form" method="post" role="form" id="delete_form">{% csrf_token %}
<div class="ml-3 form-row"> <div class="ml-3 form-row">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
@ -1690,7 +1688,7 @@
{% endif %} {% endif %}
<button type="submit" class="btn btn-lg btn-success float-right" name="delete">{% trans "Destroy" %}</button> <button type="submit" class="btn btn-lg btn-success float-right" name="delete">{% trans "Destroy" %}</button>
</form> </form>
{% endifequal %} {% endif %}
{% else %} {% else %}
<button class="btn btn-lg btn-success disabled float-right" name="delete">{% trans "Destroy" %}</button> <button class="btn btn-lg btn-success disabled float-right" name="delete">{% trans "Destroy" %}</button>
{% endif %} {% endif %}

View file

@ -13,9 +13,9 @@ from django.shortcuts import render, get_object_or_404
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from computes.models import Compute from computes.models import Compute
from instances.models import Instance from instances.models import Instance
from appsettings.models import AppSettings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from accounts.models import UserInstance, UserSSHKey from accounts.models import UserInstance, UserSSHKey
from appsettings.models import AppSettings
from vrtManager.hostdetails import wvmHostDetails from vrtManager.hostdetails import wvmHostDetails
from vrtManager.instance import wvmInstance, wvmInstances from vrtManager.instance import wvmInstance, wvmInstances
from vrtManager.connection import connection_manager from vrtManager.connection import connection_manager
@ -64,7 +64,7 @@ def allinstances(request):
error_messages.append(lib_err) error_messages.append(lib_err)
addlogmsg(request.user.username, request.POST.get("name", "instance"), lib_err) addlogmsg(request.user.username, request.POST.get("name", "instance"), lib_err)
view_style = settings.VIEW_INSTANCES_LIST_STYLE view_style = AppSettings.objects.get(key="VIEW_INSTANCES_LIST_STYLE").value
return render(request, 'allinstances.html', locals()) return render(request, 'allinstances.html', locals())
@ -111,10 +111,11 @@ def instance(request, compute_id, vname):
computes_count = computes.count() computes_count = computes.count()
users = User.objects.all().order_by('username') users = User.objects.all().order_by('username')
publickeys = UserSSHKey.objects.filter(user_id=request.user.id) publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
appsettings = AppSettings.objects.all()
keymaps = settings.QEMU_KEYMAPS keymaps = settings.QEMU_KEYMAPS
console_types = settings.QEMU_CONSOLE_TYPES console_types = appsettings.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list
console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES
bottom_bar = AppSettings.objects.get(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").value bottom_bar = appsettings.get(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").value
try: try:
userinstance = UserInstance.objects.get(instance__compute_id=compute_id, userinstance = UserInstance.objects.get(instance__compute_id=compute_id,
instance__name=vname, instance__name=vname,
@ -144,7 +145,7 @@ def instance(request, compute_id, vname):
return int(float(size_str)) return int(float(size_str))
def get_clone_free_names(size=10): def get_clone_free_names(size=10):
prefix = settings.CLONE_INSTANCE_DEFAULT_PREFIX prefix = appsettings.get(key="CLONE_INSTANCE_DEFAULT_PREFIX").value
free_names = [] free_names = []
existing_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)] existing_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)]
index = 1 index = 1
@ -179,21 +180,22 @@ def instance(request, compute_id, vname):
disk_size += int(disk['size']) >> 30 disk_size += int(disk['size']) >> 30
if ua.max_instances > 0 and instance > ua.max_instances: if ua.max_instances > 0 and instance > ua.max_instances:
quota_debug = appsettings.get(key="QUOTA_DEBUG").value
msg = "instance" msg = "instance"
if settings.QUOTA_DEBUG: if quota_debug:
msg += " (%s > %s)" % (instance, ua.max_instances) msg += f" ({instance} > {ua.max_instances})"
if ua.max_cpus > 0 and cpu > ua.max_cpus: if ua.max_cpus > 0 and cpu > ua.max_cpus:
msg = "cpu" msg = "cpu"
if settings.QUOTA_DEBUG: if quota_debug:
msg += " (%s > %s)" % (cpu, ua.max_cpus) msg += f" ({cpu} > {ua.max_cpus})"
if ua.max_memory > 0 and memory > ua.max_memory: if ua.max_memory > 0 and memory > ua.max_memory:
msg = "memory" msg = "memory"
if settings.QUOTA_DEBUG: if quota_debug:
msg += " (%s > %s)" % (memory, ua.max_memory) msg += f" ({memory} > {ua.max_memory})"
if ua.max_disk_size > 0 and disk_size > ua.max_disk_size: if ua.max_disk_size > 0 and disk_size > ua.max_disk_size:
msg = "disk" msg = "disk"
if settings.QUOTA_DEBUG: if quota_debug:
msg += " (%s > %s)" % (disk_size, ua.max_disk_size) msg += f" ({disk_size} > {ua.max_disk_size})"
return msg return msg
def get_new_disk_dev(media, disks, bus): def get_new_disk_dev(media, disks, bus):
@ -314,18 +316,21 @@ def instance(request, compute_id, vname):
io_modes = sorted(conn.get_io_modes().items()) io_modes = sorted(conn.get_io_modes().items())
discard_modes = sorted(conn.get_discard_modes().items()) discard_modes = sorted(conn.get_discard_modes().items())
detect_zeroes_modes = sorted(conn.get_detect_zeroes_modes().items()) detect_zeroes_modes = sorted(conn.get_detect_zeroes_modes().items())
default_io = settings.INSTANCE_VOLUME_DEFAULT_IO default_bus = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_BUS").value
default_discard = settings.INSTANCE_VOLUME_DEFAULT_DISCARD default_io = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_IO").value
default_zeroes = settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES default_discard = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_DISCARD").value
default_cache = settings.INSTANCE_VOLUME_DEFAULT_CACHE default_zeroes = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES").value
default_format = settings.INSTANCE_VOLUME_DEFAULT_FORMAT default_cache = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_CACHE").value
default_owner = settings.INSTANCE_VOLUME_DEFAULT_OWNER default_format = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_FORMAT").value
default_disk_owner_uid = int(appsettings.get(key="INSTANCE_VOLUME_DEFAULT_OWNER_UID").value)
default_disk_owner_gid = int(appsettings.get(key="INSTANCE_VOLUME_DEFAULT_OWNER_GID").value)
formats = conn.get_image_formats() formats = conn.get_image_formats()
show_access_root_password = settings.SHOW_ACCESS_ROOT_PASSWORD show_access_root_password = appsettings.get(key="SHOW_ACCESS_ROOT_PASSWORD").value
show_access_ssh_keys = settings.SHOW_ACCESS_SSH_KEYS show_access_ssh_keys = appsettings.get(key="SHOW_ACCESS_SSH_KEYS").value
clone_instance_auto_name = settings.CLONE_INSTANCE_AUTO_NAME clone_instance_auto_name = appsettings.get(key="CLONE_INSTANCE_AUTO_NAME").value
default_bus = settings.INSTANCE_VOLUME_DEFAULT_BUS
try: try:
instance = Instance.objects.get(compute_id=compute_id, name=vname) instance = Instance.objects.get(compute_id=compute_id, name=vname)
@ -520,7 +525,7 @@ def instance(request, compute_id, vname):
error_messages.append(msg) error_messages.append(msg)
else: else:
conn.resize_disk(disks_new) conn.resize_disk(disks_new)
msg = _("Resize") msg = _("Disk resize")
addlogmsg(request.user.username, instance.name, msg) addlogmsg(request.user.username, instance.name, msg)
messages.success(request, msg) messages.success(request, msg)
return HttpResponseRedirect(request.get_full_path() + '#resize') return HttpResponseRedirect(request.get_full_path() + '#resize')
@ -539,9 +544,9 @@ def instance(request, compute_id, vname):
cache = request.POST.get('cache', default_cache) cache = request.POST.get('cache', default_cache)
target_dev = get_new_disk_dev(media, disks, bus) target_dev = get_new_disk_dev(media, disks, bus)
source = conn_create.create_volume(storage, name, size, format, meta_prealloc, default_owner) source = conn_create.create_volume(storage, name, size, format, meta_prealloc, default_disk_owner_uid, default_disk_owner_gid)
conn.attach_disk(target_dev, source, target_bus=bus, driver_type=format, cache_mode=cache) conn.attach_disk(target_dev, source, target_bus=bus, driver_type=format, cache_mode=cache)
msg = _('Attach new disk {} ({})'.format(name, format)) msg = _(f"Attach new disk {name} ({format})")
addlogmsg(request.user.username, instance.name, msg) addlogmsg(request.user.username, instance.name, msg)
return HttpResponseRedirect(request.get_full_path() + '#disks') return HttpResponseRedirect(request.get_full_path() + '#disks')
@ -810,8 +815,11 @@ def instance(request, compute_id, vname):
if 'set_console_type' in request.POST: if 'set_console_type' in request.POST:
console_type = request.POST.get('console_type', '') console_type = request.POST.get('console_type', '')
conn.set_console_type(console_type)
msg = _("Set VNC type") msg = _("Set VNC type")
if console_type in console_types:
conn.set_console_type(console_type)
else:
msg = _("Console type not supported")
addlogmsg(request.user.username, instance.name, msg) addlogmsg(request.user.username, instance.name, msg)
return HttpResponseRedirect(request.get_full_path() + '#vncsettings') return HttpResponseRedirect(request.get_full_path() + '#vncsettings')
@ -943,13 +951,13 @@ def instance(request, compute_id, vname):
if 'add_owner' in request.POST: if 'add_owner' in request.POST:
user_id = int(request.POST.get('user_id', '')) user_id = int(request.POST.get('user_id', ''))
if settings.ALLOW_INSTANCE_MULTIPLE_OWNER: if appsettings.get(key="ALLOW_INSTANCE_MULTIPLE_OWNER").value == 'True':
check_inst = UserInstance.objects.filter(instance=instance, user_id=user_id) check_inst = UserInstance.objects.filter(instance=instance, user_id=user_id)
else: else:
check_inst = UserInstance.objects.filter(instance=instance) check_inst = UserInstance.objects.filter(instance=instance)
if check_inst: if check_inst:
msg = _("Owner already added") msg = _("One owner is allowed and owner already added")
error_messages.append(msg) error_messages.append(msg)
else: else:
add_user_inst = UserInstance(instance=instance, user_id=user_id) add_user_inst = UserInstance(instance=instance, user_id=user_id)
@ -975,10 +983,13 @@ def instance(request, compute_id, vname):
quota_msg = check_user_quota(1, vcpu, memory, disk_sum) quota_msg = check_user_quota(1, vcpu, memory, disk_sum)
check_instance = Instance.objects.filter(name=clone_data['name']) check_instance = Instance.objects.filter(name=clone_data['name'])
clone_data['disk_owner_uid'] = default_disk_owner_uid
clone_data['disk_owner_gid'] = default_disk_owner_gid
for post in request.POST: for post in request.POST:
clone_data[post] = request.POST.get(post, '').strip() clone_data[post] = request.POST.get(post, '').strip()
if clone_instance_auto_name and not clone_data['name']: if clone_instance_auto_name == 'True' and not clone_data['name']:
auto_vname = clone_free_names[0] auto_vname = clone_free_names[0]
clone_data['name'] = auto_vname clone_data['name'] = auto_vname
clone_data['clone-net-mac-0'] = _get_dhcp_mac_address(auto_vname) clone_data['clone-net-mac-0'] = _get_dhcp_mac_address(auto_vname)
@ -1016,7 +1027,8 @@ def instance(request, compute_id, vname):
msg = _("Clone of '%s'" % instance.name) msg = _("Clone of '%s'" % instance.name)
addlogmsg(request.user.username, new_instance.name, msg) addlogmsg(request.user.username, new_instance.name, msg)
if settings.CLONE_INSTANCE_AUTO_MIGRATE:
if appsettings.get(key="CLONE_INSTANCE_AUTO_MIGRATE").value == 'True':
new_compute = Compute.objects.order_by('?').first() new_compute = Compute.objects.order_by('?').first()
migrate_instance(new_compute, new_instance, xml_del=True, offline=True) migrate_instance(new_compute, new_instance, xml_del=True, offline=True)
return HttpResponseRedirect( return HttpResponseRedirect(
@ -1326,7 +1338,7 @@ def random_mac_address(request):
def guess_clone_name(request): def guess_clone_name(request):
dhcp_file = '/srv/webvirtcloud/dhcpd.conf' dhcp_file = '/srv/webvirtcloud/dhcpd.conf'
prefix = settings.CLONE_INSTANCE_DEFAULT_PREFIX prefix = appsettings.get(key="CLONE_INSTANCE_DEFAULT_PREFIX").value
if os.path.isfile(dhcp_file): if os.path.isfile(dhcp_file):
instance_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)] instance_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)]
with open(dhcp_file, 'r') as f: with open(dhcp_file, 'r') as f:

View file

@ -6,6 +6,7 @@ from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
from admin.decorators import superuser_only from admin.decorators import superuser_only
from appsettings.models import AppSettings
from instances.models import Instance from instances.models import Instance
from logs.models import Logs from logs.models import Logs

View file

@ -4,6 +4,7 @@ from django.http import HttpResponseRedirect, HttpResponse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.urls import reverse from django.urls import reverse
from computes.models import Compute from computes.models import Compute
from appsettings.models import AppSettings
from storages.forms import AddStgPool, AddImage, CloneImage from storages.forms import AddStgPool, AddImage, CloneImage
from vrtManager.storage import wvmStorage, wvmStorages from vrtManager.storage import wvmStorage, wvmStorages
from libvirt import libvirtError from libvirt import libvirtError
@ -143,8 +144,12 @@ def storage(request, compute_id, pool):
if data['meta_prealloc'] and data['format'] == 'qcow2': if data['meta_prealloc'] and data['format'] == 'qcow2':
meta_prealloc = True meta_prealloc = True
try: try:
name = conn.create_volume(data['name'], data['size'], data['format'], meta_prealloc) disk_owner = AppSettings.objects.filter(key__startswith="INSTANCE_VOLUME_DEFAULT_OWNER")
messages.success(request, _("Image file {} is created successfully".format(name))) disk_owner_uid = int(disk_owner.get(key="INSTANCE_VOLUME_DEFAULT_OWNER_UID").value)
disk_owner_gid = int(disk_owner.get(key="INSTANCE_VOLUME_DEFAULT_OWNER_GID").value)
name = conn.create_volume(data['name'], data['size'], data['format'], meta_prealloc, disk_owner_uid, disk_owner_gid)
messages.success(request, _(f"Image file {name} is created successfully"))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err) error_messages.append(lib_err)

View file

@ -1,9 +1,6 @@
import string import string
from vrtManager import util from vrtManager import util
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as DEFAULT_OWNER
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_FORMAT
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER
def get_rbd_storage_data(stg): def get_rbd_storage_data(stg):
@ -23,7 +20,6 @@ def get_rbd_storage_data(stg):
class wvmCreate(wvmConnect): class wvmCreate(wvmConnect):
image_format = INSTANCE_VOLUME_DEFAULT_FORMAT
def get_storages_images(self): def get_storages_images(self):
""" """
@ -52,7 +48,7 @@ class wvmCreate(wvmConnect):
"""Get guest capabilities""" """Get guest capabilities"""
return util.get_xml_path(self.get_cap_xml(), "/capabilities/host/cpu/arch") return util.get_xml_path(self.get_cap_xml(), "/capabilities/host/cpu/arch")
def create_volume(self, storage, name, size, image_format=image_format, metadata=False, owner=DEFAULT_OWNER): def create_volume(self, storage, name, size, image_format, metadata=False, disk_owner_uid=0, disk_owner_gid=0):
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")
@ -65,16 +61,16 @@ class wvmCreate(wvmConnect):
else: else:
alloc = size alloc = size
metadata = False metadata = False
xml = """ xml = f"""
<volume> <volume>
<name>%s</name> <name>{name}</name>
<capacity>%s</capacity> <capacity>{size}</capacity>
<allocation>%s</allocation> <allocation>{alloc}</allocation>
<target> <target>
<format type='%s'/> <format type='{image_format}'/>
<permissions> <permissions>
<owner>%s</owner> <owner>{disk_owner_uid}</owner>
<group>%s</group> <group>{disk_owner_gid}</group>
<mode>0644</mode> <mode>0644</mode>
<label>virt_image_t</label> <label>virt_image_t</label>
</permissions> </permissions>
@ -83,7 +79,7 @@ class wvmCreate(wvmConnect):
<lazy_refcounts/> <lazy_refcounts/>
</features> </features>
</target> </target>
</volume>""" % (name, size, alloc, image_format, owner['uid'], owner['guid']) </volume>"""
stg.createXML(xml, metadata) stg.createXML(xml, metadata)
try: try:
stg.refresh(0) stg.refresh(0)
@ -120,7 +116,7 @@ class wvmCreate(wvmConnect):
vol = self.get_volume_by_path(vol_path) vol = self.get_volume_by_path(vol_path)
return vol.storagePoolLookupByVolume() return vol.storagePoolLookupByVolume()
def clone_from_template(self, clone, template, storage=None, metadata=False, owner=DEFAULT_OWNER): def clone_from_template(self, clone, template, storage=None, metadata=False, disk_owner_uid=0, disk_owner_gid=0):
vol = self.get_volume_by_path(template) vol = self.get_volume_by_path(template)
if not storage: if not storage:
stg = vol.storagePoolLookupByVolume() stg = vol.storagePoolLookupByVolume()
@ -133,16 +129,16 @@ class wvmCreate(wvmConnect):
clone += '.img' clone += '.img'
else: else:
metadata = False metadata = False
xml = """ xml = f"""
<volume> <volume>
<name>%s</name> <name>{clone}</name>
<capacity>0</capacity> <capacity>0</capacity>
<allocation>0</allocation> <allocation>0</allocation>
<target> <target>
<format type='%s'/> <format type='{format}'/>
<permissions> <permissions>
<owner>%s</owner> <owner>{disk_owner_uid}</owner>
<group>%s</group> <group>{disk_owner_gid}</group>
<mode>0644</mode> <mode>0644</mode>
<label>virt_image_t</label> <label>virt_image_t</label>
</permissions> </permissions>
@ -151,7 +147,7 @@ class wvmCreate(wvmConnect):
<lazy_refcounts/> <lazy_refcounts/>
</features> </features>
</target> </target>
</volume>""" % (clone, format, owner['uid'], owner['guid']) </volume>"""
stg.createXMLFrom(xml, vol, metadata) stg.createXMLFrom(xml, vol, metadata)
clone_vol = stg.storageVolLookupByName(clone) clone_vol = stg.storageVolLookupByName(clone)
return clone_vol.path() return clone_vol.path()
@ -163,11 +159,9 @@ 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, images, def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, volumes,
networks, nwfilter, graphics, virtio, listen_addr, networks, nwfilter, graphics, virtio, listen_addr,
video="vga", console_pass="random", mac=None, video="vga", console_pass="random", mac=None, qemu_ga=True):
cache_mode=None, io_mode=None, discard_mode=None, detect_zeroes_mode=None,
qemu_ga=True):
""" """
Create VM function Create VM function
""" """
@ -176,17 +170,17 @@ class wvmCreate(wvmConnect):
memory = int(memory) * 1024 memory = int(memory) * 1024
xml = """ xml = f"""
<domain type='%s'> <domain type='{dom_caps["domain"]}'>
<name>%s</name> <name>{name}</name>
<description>None</description> <description>None</description>
<uuid>%s</uuid> <uuid>{uuid}</uuid>
<memory unit='KiB'>%s</memory> <memory unit='KiB'>{memory}</memory>
<vcpu>%s</vcpu>""" % (dom_caps["domain"], name, uuid, memory, vcpu) <vcpu>{vcpu}</vcpu>"""
if dom_caps["os_support"] == 'yes': if dom_caps["os_support"] == 'yes':
xml += """<os> xml += f"""<os>
<type arch='%s' machine='%s'>%s</type>""" % (arch, machine, caps["os_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'/>"""
@ -221,8 +215,8 @@ class wvmCreate(wvmConnect):
elif vcpu_mode == "": elif vcpu_mode == "":
pass pass
else: else:
xml += """<cpu mode='custom' match='exact' check='none'> xml += f"""<cpu mode='custom' match='exact' check='none'>
<model fallback='allow'>%s</model>""" % vcpu_mode <model fallback='allow'>{vcpu_mode}</model>"""
xml += """</cpu>""" xml += """</cpu>"""
xml += """ xml += """
@ -239,17 +233,18 @@ class wvmCreate(wvmConnect):
sd_disk_letters = list(string.ascii_lowercase) sd_disk_letters = list(string.ascii_lowercase)
add_cd = True add_cd = True
disk_opts = '' for volume in volumes:
if cache_mode is not None and cache_mode != 'default':
disk_opts += "cache='%s' " % cache_mode disk_opts = ''
if io_mode is not None and io_mode != 'default': if volume['cache_mode'] is not None and volume['cache_mode'] != 'default':
disk_opts += "io='%s' " % io_mode disk_opts += f"cache='{volume['cache_mode']}' "
if discard_mode is not None and discard_mode != 'default': if volume['io_mode'] is not None and volume['io_mode'] != 'default':
disk_opts += "discard='%s' " % discard_mode disk_opts += f"io='{volume['io_mode']}' "
if detect_zeroes_mode is not None and detect_zeroes_mode != 'default': if volume['discard_mode'] is not None and volume['discard_mode'] != 'default':
disk_opts += "detect_zeroes='%s' " % detect_zeroes_mode disk_opts += f"discard='{volume['discard_mode']}' "
if volume['detect_zeroes_mode'] is not None and volume['detect_zeroes_mode'] != 'default':
disk_opts += f"detect_zeroes='{volume['detect_zeroes_mode']}' "
for volume in images:
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")
@ -275,7 +270,7 @@ class wvmCreate(wvmConnect):
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 += """ <source file='%s'/>""" % volume['path'] xml += f""" <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'))
@ -304,15 +299,15 @@ class wvmCreate(wvmConnect):
xml += """</disk>""" xml += """</disk>"""
if volume.get('bus') == 'scsi': if volume.get('bus') == 'scsi':
xml += """<controller type='scsi' model='%s'/>""" % INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER xml += f"""<controller type='scsi' model='{volume.get('scsi_model')}'/>"""
for net in networks.split(','): for net in networks.split(','):
xml += """<interface type='network'>""" xml += """<interface type='network'>"""
if mac: if mac:
xml += """<mac address='%s'/>""" % mac xml += f"""<mac address='{mac}'/>"""
xml += """<source network='%s'/>""" % net xml += f"""<source network='{net}'/>"""
if nwfilter: if nwfilter:
xml += """<filterref filter='%s'/>""" % nwfilter xml += f"""<filterref filter='{nwfilter}'/>"""
if virtio: if virtio:
xml += """<model type='virtio'/>""" xml += """<model type='virtio'/>"""
xml += """</interface>""" xml += """</interface>"""
@ -332,18 +327,18 @@ class wvmCreate(wvmConnect):
xml += """<input type='keyboard'/>""" xml += """<input type='keyboard'/>"""
xml += """<input type='tablet'/>""" xml += """<input type='tablet'/>"""
xml += """ xml += f"""
<graphics type='%s' port='-1' autoport='yes' %s listen='%s'/> <graphics type='{graphics}' port='-1' autoport='yes' {console_pass} listen='{listen_addr}'/>
<console type='pty'/> """ % (graphics, console_pass, listen_addr) <console type='pty'/> """
if qemu_ga and virtio: if qemu_ga and virtio:
xml += """ <channel type='unix'> xml += """ <channel type='unix'>
<target type='virtio' name='org.qemu.guest_agent.0'/> <target type='virtio' name='org.qemu.guest_agent.0'/>
</channel>""" </channel>"""
xml += """ <video> xml += f""" <video>
<model type='%s'/> <model type='{video}'/>
</video> </video>
</devices> </devices>
</domain>""" % video </domain>"""
self._defineXML(xml) self._defineXML(xml)

View file

@ -22,8 +22,6 @@ from collections import OrderedDict
from vrtManager import util from vrtManager import util
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from vrtManager.storage import wvmStorage, wvmStorages from vrtManager.storage import wvmStorage, wvmStorages
from webvirtcloud.settings import QEMU_CONSOLE_TYPES
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as OWNER
class wvmInstances(wvmConnect): class wvmInstances(wvmConnect):
@ -909,7 +907,7 @@ class wvmInstance(wvmConnect):
current_type = self.get_console_type() current_type = self.get_console_type()
if current_type == console_type: if current_type == console_type:
return True return True
if console_type == '' or console_type not in QEMU_CONSOLE_TYPES: if console_type == '':
return False return False
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE) xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
root = ElementTree.fromstring(xml) root = ElementTree.fromstring(xml)
@ -1203,8 +1201,8 @@ class wvmInstance(wvmConnect):
<target> <target>
<format type='{vol_format}'/> <format type='{vol_format}'/>
<permissions> <permissions>
<owner>{OWNER['uid']}</owner> <owner>{clone_data['disk_owner_uid']}</owner>
<group>{OWNER['guid']}</group> <group>{clone_data['disk_owner_gid']}</group>
<mode>0644</mode> <mode>0644</mode>
<label>virt_image_t</label> <label>virt_image_t</label>
</permissions> </permissions>

View file

@ -1,6 +1,5 @@
from vrtManager import util from vrtManager import util
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as OWNER
class wvmStorages(wvmConnect): class wvmStorages(wvmConnect):
@ -210,7 +209,7 @@ class wvmStorage(wvmConnect):
) )
return vol_list return vol_list
def create_volume(self, name, size, vol_fmt='qcow2', metadata=False, owner=OWNER): 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
@ -230,8 +229,8 @@ class wvmStorage(wvmConnect):
<target> <target>
<format type='{vol_fmt}'/> <format type='{vol_fmt}'/>
<permissions> <permissions>
<owner>{owner['uid']}</owner> <owner>{disk_owner_uid}</owner>
<group>{owner['guid']}</group> <group>{disk_owner_gid}</group>
<mode>0644</mode> <mode>0644</mode>
<label>virt_image_t</label> <label>virt_image_t</label>
</permissions>""" </permissions>"""
@ -246,7 +245,7 @@ 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', owner=OWNER): 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)
@ -267,8 +266,8 @@ class wvmStorage(wvmConnect):
<target> <target>
<format type='{vol_fmt}'/> <format type='{vol_fmt}'/>
<permissions> <permissions>
<owner>{owner['uid']}</owner> <owner>{disk_owner_uid}</owner>
<group>{owner['guid']}</group> <group>{disk_owner_gid}</group>
<mode>{mode}</mode> <mode>{mode}</mode>
<label>virt_image_t</label> <label>virt_image_t</label>
</permissions>""" </permissions>"""

View file

@ -174,52 +174,10 @@ LIBVIRT_KEEPALIVE_INTERVAL = 5
LIBVIRT_KEEPALIVE_COUNT = 5 LIBVIRT_KEEPALIVE_COUNT = 5
ALLOW_INSTANCE_MULTIPLE_OWNER = True ALLOW_INSTANCE_MULTIPLE_OWNER = True
ALLOW_EMPTY_PASSWORD = False
NEW_USER_DEFAULT_INSTANCES = [] NEW_USER_DEFAULT_INSTANCES = []
CLONE_INSTANCE_DEFAULT_PREFIX = 'instance' CLONE_INSTANCE_DEFAULT_PREFIX = 'instance'
CLONE_INSTANCE_AUTO_NAME = False CLONE_INSTANCE_AUTO_NAME = False
CLONE_INSTANCE_AUTO_MIGRATE = False CLONE_INSTANCE_AUTO_MIGRATE = False
LOGS_PER_PAGE = 100 LOGS_PER_PAGE = 100
QUOTA_DEBUG = True
ALLOW_EMPTY_PASSWORD = True
SHOW_ACCESS_ROOT_PASSWORD = False
SHOW_ACCESS_SSH_KEYS = False
# available list style: default (grouped), nongrouped
VIEW_INSTANCES_LIST_STYLE = 'grouped'
# available volume format: raw, qcow2, qcow
INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2'
# available bus types: virtio, scsi, ide, usb, sata
INSTANCE_VOLUME_DEFAULT_BUS = 'virtio'
#SCSI types: virtio-scsi, lsilogic
INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER = 'virtio-scsi'
# Volume cache: default, directsync, none, unsafe, writeback, writethrough
INSTANCE_VOLUME_DEFAULT_CACHE = 'directsync'
# Volume io mode: default, native, threads
INSTANCE_VOLUME_DEFAULT_IO = 'default'
# Volume detect zeroes mode: default, on, off, unmap
INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES = 'default'
# Volume discard mode: default, unmap, ignore
INSTANCE_VOLUME_DEFAULT_DISCARD = 'default'
# up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)
INSTANCE_VOLUME_DEFAULT_OWNER = {'uid': 0, 'guid': 0}
# Cpu modes: host-model, host-passthrough, custom
INSTANCE_CPU_DEFAULT_MODE = 'host-model'
# Chipset/Machine: pc or q35 for x86_64
INSTANCE_MACHINE_DEFAULT_TYPE = 'q35'
# Firmware: BIOS or UEFI for x86_64
INSTANCE_FIRMWARE_DEFAULT_TYPE = 'BIOS'
# Architecture: x86_64, i686, etc
INSTANCE_ARCH_DEFAULT_TYPE = 'x86_64'