mirror of
https://github.com/retspen/webvirtcloud
synced 2024-10-31 19:44:16 +00:00
Add all settings to appsettings page & Convert settings choices
This commit is contained in:
parent
62f8ece0ef
commit
7538ddab4f
27 changed files with 454 additions and 447 deletions
|
@ -9,8 +9,7 @@ class UserAddForm(forms.Form):
|
|||
name = forms.CharField(label="Name",
|
||||
error_messages={'required': _('No User name has been entered')},
|
||||
max_length=20)
|
||||
password = forms.CharField(required=not settings.ALLOW_EMPTY_PASSWORD,
|
||||
error_messages={'required': _('No password has been entered')},)
|
||||
password = forms.CharField(required=not settings.ALLOW_EMPTY_PASSWORD, error_messages={'required': _('No password has been entered')},)
|
||||
|
||||
def clean_name(self):
|
||||
name = self.cleaned_data['name']
|
||||
|
|
24
accounts/migrations/0003_auto_20200604_0930.py
Normal file
24
accounts/migrations/0003_auto_20200604_0930.py
Normal 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)]),
|
||||
),
|
||||
]
|
|
@ -1,4 +1,3 @@
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.db import models
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
<div class="modal-content">
|
||||
<form method="post" role="form" aria-label="Edit user form">{% csrf_token %}
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h5 class="modal-title">{% trans "Edit user info" %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group row">
|
||||
|
@ -133,11 +133,11 @@
|
|||
{% trans "Delete" %}
|
||||
</button>
|
||||
{% 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" %}
|
||||
</button>
|
||||
{% 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" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
|
|
@ -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 . import views
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@ from django.http import HttpResponseRedirect
|
|||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from accounts.forms import UserAddForm
|
||||
from accounts.models import *
|
||||
from admin.decorators import superuser_only
|
||||
from appsettings.models import AppSettings
|
||||
from instances.models import Instance
|
||||
|
||||
import sass
|
||||
|
@ -22,7 +22,6 @@ def profile(request):
|
|||
error_messages = []
|
||||
# user = User.objects.get(id=request.user.id)
|
||||
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
|
||||
|
||||
themes_list = os.listdir(settings.SCSS_DIR +"/wvc-theme")
|
||||
|
||||
if request.method == 'POST':
|
||||
|
@ -69,20 +68,6 @@ def profile(request):
|
|||
delkeypublic = UserSSHKey.objects.get(id=keyid)
|
||||
delkeypublic.delete()
|
||||
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())
|
||||
|
||||
|
||||
|
@ -119,8 +104,8 @@ def account(request, user_id):
|
|||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'add' in request.POST:
|
||||
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))
|
||||
else:
|
||||
check_inst = UserInstance.objects.filter(instance_id=int(inst_id))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -16,8 +16,9 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('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)),
|
||||
('choices', models.CharField(max_length=50)),
|
||||
('description', models.CharField(max_length=100, null=True)),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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),
|
||||
]
|
82
appsettings/migrations/0002_auto_20200527_1603.py
Normal file
82
appsettings/migrations/0002_auto_20200527_1603.py
Normal 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),
|
||||
]
|
|
@ -2,7 +2,12 @@ from django.db import models
|
|||
|
||||
|
||||
class AppSettings(models.Model):
|
||||
|
||||
def choices_as_list(self):
|
||||
return self.choices.split(',')
|
||||
|
||||
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)
|
||||
description=models.CharField(max_length=100, null=True)
|
||||
choices = models.CharField(max_length=50)
|
||||
description = models.CharField(max_length=100, null=True)
|
||||
|
|
|
@ -57,17 +57,25 @@
|
|||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
<form method="post" action="" role="form" aria-label="Edit bottom bar settings form">{% csrf_token %}
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{{ show_inst_bottom_bar.name }}</label>
|
||||
<div class="col-sm-6">
|
||||
<select class="form-control" name="{{ show_inst_bottom_bar.key }}" onchange="this.form.submit()">
|
||||
<option {% if show_inst_bottom_bar.value == 'True' %} selected {% endif %} value=True>{% trans "True" %}</option>
|
||||
<option {% if show_inst_bottom_bar.value == 'False' %} selected {% endif %} value=False>{% trans "False" %}</option>
|
||||
</select>
|
||||
<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">
|
||||
<label class="col-sm-3 col-form-label">{{ setting.name }}</label>
|
||||
<div class="col-sm-6">
|
||||
{% if setting.choices %}
|
||||
<select class="form-control" name="{{ setting.key }}" onchange="this.form.submit()" title="{{ setting.description }}">
|
||||
{% for choice in setting.choices_as_list %}
|
||||
<option {% if setting.value == choice %} selected {% endif %} value={{ choice }}>{% trans choice %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input class="form-control" name="{{ setting.key }}" value="{{ setting.value }}" title="{{ setting.description }}" onchange="this.form.submit()"/>
|
||||
{% endif%}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,7 +7,6 @@ from django.urls import reverse
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
from django.conf import settings
|
||||
|
||||
from appsettings.models import AppSettings
|
||||
from logs.views import addlogmsg
|
||||
|
@ -22,14 +21,33 @@ def appsettings(request):
|
|||
"""
|
||||
error_messages = []
|
||||
|
||||
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")
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
themes_list = os.listdir(sass_dir.value + "/wvc-theme")
|
||||
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 request.method == 'POST':
|
||||
if 'BOOTSTRAP_THEME' in request.POST:
|
||||
theme = request.POST.get("BOOTSTRAP_THEME", "")
|
||||
scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';"
|
||||
|
@ -56,33 +74,20 @@ def appsettings(request):
|
|||
addlogmsg(request.user.username, "", msg)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'SASS_DIR' in request.POST:
|
||||
try:
|
||||
sass_dir.value = request.POST.get("SASS_DIR", "")
|
||||
sass_dir.save()
|
||||
for setting in appsettings:
|
||||
if setting.key in request.POST:
|
||||
try:
|
||||
setting.value = request.POST.get(setting.key, "")
|
||||
setting.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 '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)
|
||||
except Exception as err:
|
||||
msg = err
|
||||
error_messages.append(msg)
|
||||
|
||||
addlogmsg(request.user.username, "", msg)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
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())
|
||||
|
||||
return render(request, 'appsettings.html', locals())
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<dt class="col-3">{% trans "Version" %}</dt>
|
||||
<dd class="col-9">
|
||||
<span class="badge bg-secondary text-light">{% trans 'Qemu' %} </span>
|
||||
<span class="badge bg-primary text-light">{{ version }}</span>
|
||||
<span class="badge bg-primary text-light">{{ version }}</span>
|
||||
<span class="badge bg-secondary text-light">{% trans 'Libvirt' %} </span>
|
||||
<span class="badge bg-primary text-light">{{ lib_version }}</span>
|
||||
</dd>
|
||||
|
@ -115,6 +115,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script src="{% static "js/Chart.bundle.min.js" %}"></script>
|
||||
|
|
|
@ -3,8 +3,7 @@ from django.shortcuts import render
|
|||
from libvirt import libvirtError
|
||||
from instances.models import Instance
|
||||
from vrtManager.instance import wvmInstance
|
||||
from webvirtcloud.settings import WS_PUBLIC_PORT
|
||||
from webvirtcloud.settings import WS_PUBLIC_HOST
|
||||
from webvirtcloud.settings import WS_PUBLIC_PORT, WS_PUBLIC_HOST
|
||||
|
||||
|
||||
def console(request):
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<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 %}
|
||||
<div class="col-sm-12" id="xmlheight">
|
||||
<input type="hidden" name="dom_xml"/>
|
||||
|
|
|
@ -199,7 +199,7 @@
|
|||
<div class="col-sm-6">
|
||||
<select id="cache_mode" name="cache_mode" class="custom-select">
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
@ -303,7 +303,7 @@
|
|||
</div>
|
||||
|
||||
<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 %}
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Name" %}</label>
|
||||
|
@ -423,7 +423,7 @@
|
|||
<div class="col-sm-7">
|
||||
<select id="cache_mode" name="cache_mode" class="form-control">
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
@ -516,7 +516,7 @@
|
|||
</div>
|
||||
|
||||
<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 %}
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Name" %}</label>
|
||||
|
@ -636,7 +636,7 @@
|
|||
<div class="col-sm-7">
|
||||
<select id="cache_mode" name="cache_mode" class="custom-select">
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
@ -788,8 +788,7 @@
|
|||
'{% endfor %}' +
|
||||
'</select>' +
|
||||
' -> ' + value + ' ' +
|
||||
'<a class="btn-link float-right" onclick="javascript:$(\'#image-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a>' +
|
||||
'</li>';
|
||||
'<a class="btn-link float-right" onclick="javascript:$(\'#image-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a></li>';
|
||||
selected_list_html += li;
|
||||
counter++;
|
||||
});
|
||||
|
@ -797,7 +796,6 @@
|
|||
$('#disk_list_div').addClass('d-none');
|
||||
}
|
||||
$('#img-list').html(selected_list_html);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -822,7 +820,7 @@
|
|||
$.each(input_value.split(','), function (index, value) {
|
||||
let li = '<li>eth' + counter +
|
||||
' -> ' + 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;
|
||||
counter++;
|
||||
});
|
||||
|
|
108
create/views.py
108
create/views.py
|
@ -8,23 +8,12 @@ from admin.decorators import superuser_only
|
|||
from computes.models import Compute
|
||||
from create.models import Flavor
|
||||
from create.forms import FlavorAddForm, NewVMForm
|
||||
from appsettings.models import AppSettings
|
||||
from instances.models import Instance
|
||||
from vrtManager.create import wvmCreate
|
||||
from vrtManager import util
|
||||
from logs.views import addlogmsg
|
||||
|
||||
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
|
||||
def create_instance_select_type(request, compute_id):
|
||||
|
@ -40,6 +29,7 @@ def create_instance_select_type(request, compute_id):
|
|||
hypervisors = list()
|
||||
meta_prealloc = False
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
appsettings = AppSettings.objects.all()
|
||||
|
||||
try:
|
||||
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_arch = ["x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"]
|
||||
hypervisors = [hpv for hpv in all_hypervisors.keys() if hpv in supported_arch]
|
||||
default_machine = INSTANCE_MACHINE_DEFAULT_TYPE
|
||||
default_arch = INSTANCE_ARCH_DEFAULT_TYPE
|
||||
default_machine = appsettings.get(key="INSTANCE_MACHINE_DEFAULT_TYPE").value
|
||||
default_arch = appsettings.get(key="INSTANCE_ARCH_DEFAULT_TYPE").value
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'create_xml' in request.POST:
|
||||
|
@ -93,28 +83,33 @@ def create_instance(request, compute_id, arch, machine):
|
|||
meta_prealloc = False
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
flavors = Flavor.objects.filter().order_by('id')
|
||||
appsettings = AppSettings.objects.all()
|
||||
|
||||
try:
|
||||
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
|
||||
|
||||
default_firmware = INSTANCE_FIRMWARE_DEFAULT_TYPE
|
||||
default_cpu_mode = INSTANCE_CPU_DEFAULT_MODE
|
||||
default_firmware = appsettings.get(key="INSTANCE_FIRMWARE_DEFAULT_TYPE").value
|
||||
default_cpu_mode = appsettings.get(key="INSTANCE_CPU_DEFAULT_MODE").value
|
||||
instances = conn.get_instances()
|
||||
videos = conn.get_video_models(arch, machine)
|
||||
cache_modes = sorted(conn.get_cache_modes().items())
|
||||
default_cache = INSTANCE_VOLUME_DEFAULT_CACHE.lower()
|
||||
default_io = INSTANCE_VOLUME_DEFAULT_IO.lower()
|
||||
default_zeroes = INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES.lower()
|
||||
default_discard = INSTANCE_VOLUME_DEFAULT_DISCARD.lower()
|
||||
default_cache = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_CACHE").value
|
||||
default_io = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_IO").value
|
||||
default_zeroes = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES").value
|
||||
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
|
||||
mac_auto = util.randomMAC()
|
||||
disk_devices = conn.get_disk_device_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())
|
||||
nwfilters = conn.get_nwfilters()
|
||||
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)
|
||||
caps = conn.get_capabilities(arch)
|
||||
|
@ -177,18 +172,29 @@ def create_instance(request, compute_id, arch, machine):
|
|||
error_messages.append(error_msg)
|
||||
else:
|
||||
try:
|
||||
path = conn.create_volume(data['storage'],
|
||||
data['name'],
|
||||
data['hdd_size'],
|
||||
metadata=meta_prealloc)
|
||||
path = conn.create_volume(
|
||||
data['storage'],
|
||||
data['name'],
|
||||
data['hdd_size'],
|
||||
default_disk_format,
|
||||
meta_prealloc,
|
||||
default_disk_owner_uid,
|
||||
default_disk_owner_gid)
|
||||
volume = dict()
|
||||
volume['device'] = 'disk'
|
||||
volume['path'] = path
|
||||
volume['type'] = conn.get_volume_type(path)
|
||||
volume['device'] = 'disk'
|
||||
if data['virtio']:
|
||||
volume['bus'] = INSTANCE_VOLUME_DEFAULT_BUS
|
||||
volume['cache_mode'] = data['cache_mode']
|
||||
volume['bus'] = default_bus
|
||||
if volume['bus'] == 'scsi':
|
||||
volume['scsi_model'] = default_scsi_disk_model
|
||||
volume['discard_mode'] = default_discard
|
||||
volume['detect_zeroes_mode'] = default_zeroes
|
||||
volume['io_mode'] = default_io
|
||||
|
||||
volume_list.append(volume)
|
||||
is_disk_created = True
|
||||
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
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_messages.append(error_msg)
|
||||
else:
|
||||
clone_path = conn.clone_from_template(data['name'],
|
||||
templ_path,
|
||||
data['storage'],
|
||||
metadata=meta_prealloc)
|
||||
clone_path = conn.clone_from_template(
|
||||
data['name'],
|
||||
templ_path,
|
||||
data['storage'],
|
||||
meta_prealloc,
|
||||
default_disk_owner_uid,
|
||||
default_disk_owner_gid)
|
||||
volume = dict()
|
||||
volume['path'] = clone_path
|
||||
volume['type'] = conn.get_volume_type(clone_path)
|
||||
volume['device'] = 'disk'
|
||||
if data['virtio']:
|
||||
volume['bus'] = INSTANCE_VOLUME_DEFAULT_BUS
|
||||
volume['cache_mode'] = data['cache_mode']
|
||||
volume['bus'] = default_bus
|
||||
if volume['bus'] == 'scsi':
|
||||
volume['scsi_model'] = default_scsi_disk_model
|
||||
volume['discard_mode'] = default_discard
|
||||
volume['detect_zeroes_mode'] = default_zeroes
|
||||
volume['io_mode'] = default_io
|
||||
|
||||
volume_list.append(volume)
|
||||
is_disk_created = True
|
||||
else:
|
||||
|
@ -223,6 +238,13 @@ def create_instance(request, compute_id, arch, machine):
|
|||
volume['type'] = conn.get_volume_type(path)
|
||||
volume['device'] = request.POST.get('device' + str(idx), '')
|
||||
volume['bus'] = request.POST.get('bus' + str(idx), '')
|
||||
if volume['bus'] == 'scsi':
|
||||
volume['scsi_model'] = default_scsi_disk_model
|
||||
volume['cache_mode'] = data['cache_mode']
|
||||
volume['discard_mode'] = default_discard
|
||||
volume['detect_zeroes_mode'] = default_zeroes
|
||||
volume['io_mode'] = default_io
|
||||
|
||||
volume_list.append(volume)
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
@ -253,23 +275,19 @@ def create_instance(request, compute_id, arch, machine):
|
|||
arch=arch,
|
||||
machine=machine,
|
||||
firmware=firmware,
|
||||
images=volume_list,
|
||||
cache_mode=data['cache_mode'],
|
||||
io_mode=default_io,
|
||||
discard_mode=default_discard,
|
||||
detect_zeroes_mode=default_zeroes,
|
||||
networks=data['networks'],
|
||||
volumes=volume_list,
|
||||
networks=data['networks'],
|
||||
virtio=data['virtio'],
|
||||
listen_addr=data["listener_addr"],
|
||||
listen_addr=data["listener_addr"],
|
||||
nwfilter=data["nwfilter"],
|
||||
graphics=data["graphics"],
|
||||
graphics=data["graphics"],
|
||||
video=data["video"],
|
||||
console_pass=data["console_pass"],
|
||||
console_pass=data["console_pass"],
|
||||
mac=data['mac'],
|
||||
qemu_ga=data['qemu_ga'])
|
||||
create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
|
||||
create_instance.save()
|
||||
msg = _("Instance is created.")
|
||||
msg = _("Instance is created")
|
||||
messages.success(request, msg)
|
||||
addlogmsg(request.user.username, create_instance.name, msg)
|
||||
return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']]))
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
from django.conf.urls import url
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^openstack/$',
|
||||
views.os_index, name='ds_openstack_index'),
|
||||
url(r'^openstack/(?P<version>[\w\-\.]+)/meta_data.json$',
|
||||
views.os_metadata_json, name='ds_openstack_metadata'),
|
||||
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'),
|
||||
path('openstack/', views.os_index, name='ds_openstack_index'),
|
||||
path('openstack/<version>/meta_data.json', views.os_metadata_json, name='ds_openstack_metadata'),
|
||||
path('openstack/<version>/user_data', views.os_userdata, name='ds_openstack_userdata'),
|
||||
path('vdi/<int:compute_id>/<vname>/', views.get_vdi_url, name='vdi_url'),
|
||||
]
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@import 'dev/scss/wvc-theme/flatly/variables';
|
||||
@import 'dev/scss/bootstrap-overrides.scss';
|
||||
@import 'dev/scss/wvc-theme/flatly/bootswatch';
|
||||
@import 'dev/scss//wvc-theme/flatly/variables';
|
||||
@import 'dev/scss//bootstrap-overrides.scss';
|
||||
@import 'dev/scss//wvc-theme/flatly/bootswatch';
|
|
@ -121,7 +121,7 @@
|
|||
<div role="tabpanel">
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs" role="tablist" aria-label="Instance power actions">
|
||||
{% ifequal status 1 %}
|
||||
{% if status == 1 %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-secondary active" href="#poweroff" aria-controls="poweroff" role="tab" data-toggle="tab">
|
||||
{% trans "Power Off" %}
|
||||
|
@ -144,8 +144,8 @@
|
|||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endifequal %}
|
||||
{% ifequal status 3 %}
|
||||
{% endif %}
|
||||
{% if status == 3 %}
|
||||
{% if request.user.is_superuser %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-secondary" href="#resume" aria-controls="resume" role="tab" data-toggle="tab">
|
||||
|
@ -158,18 +158,18 @@
|
|||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endifequal %}
|
||||
{% ifequal status 5 %}
|
||||
{% endif %}
|
||||
{% if status == 5 %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-secondary active" href="#boot" aria-controls="boot" role="tab" data-toggle="tab">
|
||||
{% trans "Power On" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
{% ifequal status 1 %}
|
||||
{% if status == 1 %}
|
||||
<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>
|
||||
<form action="" method="post" role="form" aria-label0="Power off instance form">{% csrf_token %}
|
||||
|
@ -200,8 +200,8 @@
|
|||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endifequal %}
|
||||
{% ifequal status 3 %}
|
||||
{% endif %}
|
||||
{% if status == 3 %}
|
||||
{% if request.user.is_superuser %}
|
||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="resume">
|
||||
<p>{% trans "This action restore the instance after suspend." %}</p>
|
||||
|
@ -226,8 +226,8 @@
|
|||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endifequal %}
|
||||
{% ifequal status 5 %}
|
||||
{% endif %}
|
||||
{% if status == 5 %}
|
||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="boot">
|
||||
<p>{% trans "Click on Boot button to start this instance." %}</p>
|
||||
<form action="" method="post" role="form" aria-label="Start instance form">{% csrf_token %}
|
||||
|
@ -240,7 +240,7 @@
|
|||
<div class="clearfix"></div>
|
||||
</form>
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -253,33 +253,33 @@
|
|||
{% trans "Console" %}
|
||||
</a>
|
||||
</li>
|
||||
{% if show_access_root_password %}
|
||||
{% if show_access_root_password == 'True' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-secondary" href="#rootpasswd" aria-controls="rootpasswd" role="tab" data-toggle="tab">
|
||||
{% trans "Root Password" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if show_access_ssh_keys %}
|
||||
{% if show_access_ssh_keys == 'True' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-secondary" href="#sshkeys" aria-controls="sshkeys" role="tab" data-toggle="tab">
|
||||
{% trans "SSH Keys" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% ifequal status 1 %}
|
||||
{% if status == 1 %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-secondary" href="#vdiconsole" aria-controls="vdiconsole" role="tab" data-toggle="tab">
|
||||
{% trans "VDI" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<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>
|
||||
{% ifequal status 1 %}
|
||||
{% if status == 1 %}
|
||||
<!-- Split button -->
|
||||
<div class="btn-group float-right">
|
||||
<button type="button" id="consoleBtnGroup" class="btn btn-lg btn-success" onclick="open_console('lite')">{% trans 'Console' %}</button>
|
||||
|
@ -293,10 +293,10 @@
|
|||
</div>
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success float-right disabled">{% trans "Console" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% if show_access_root_password %}
|
||||
{% if show_access_root_password == 'True' %}
|
||||
<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>
|
||||
<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">
|
||||
</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" %}">
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success float-right disabled">{% trans "Reset Root Password" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if show_access_ssh_keys %}
|
||||
{% if show_access_ssh_keys == 'True' %}
|
||||
<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>
|
||||
<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="col-sm-12">
|
||||
<select name="sshkeyid" class="form-control keyselect">
|
||||
<select name="sshkeyid" class="form-control-lg keyselect">
|
||||
{% if publickeys %}
|
||||
{% for key in publickeys %}
|
||||
<option value="{{ key.id }}">{{ key.keyname }}</option>
|
||||
|
@ -331,16 +331,16 @@
|
|||
</select>
|
||||
</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" %}">
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success float-right disabled">{% trans "Add Public Key" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% ifequal status 1 %}
|
||||
{% if status == 1 %}
|
||||
<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>
|
||||
<div class="input-group">
|
||||
|
@ -351,7 +351,7 @@
|
|||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -408,11 +408,11 @@
|
|||
</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>
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success float-right disabled">{% trans "Resize" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="clearfix"></div>
|
||||
{% else %}
|
||||
|
@ -493,11 +493,11 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% ifequal status 5 %}
|
||||
{% if status == 5 %}
|
||||
<button type="submit" class="btn btn-lg btn-success float-right" name="resizevm_disk">{% trans "Resize" %}</button>
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success float-right disabled">{% trans "Resize" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
{% else %}
|
||||
{% trans "You don't have permission for resizing instance" %}
|
||||
|
@ -526,7 +526,7 @@
|
|||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<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>
|
||||
<form class="form-inline" method="post" role="form" aria-label="Create snapshot form">{% csrf_token %}
|
||||
<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">
|
||||
</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" %}">
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success float-right disabled">{% trans "Take Snapshot" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="clearfix"></div>
|
||||
{% else %}
|
||||
<p>{% trans "To take a snapshot please Power Off the instance." %}</p>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="managesnapshot">
|
||||
{% if snapshots %}
|
||||
|
@ -563,7 +563,7 @@
|
|||
<td style="width:30px;">
|
||||
<form action="" method="post" role="form" aria-label="Restore snapshot form">{% csrf_token %}
|
||||
<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?')">
|
||||
<span class="fa fa-download"></span>
|
||||
</button>
|
||||
|
@ -572,7 +572,7 @@
|
|||
title="{% trans "To restore snapshots you need Power Off the instance." %}">
|
||||
<span class="fa fa-download"></span>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
</td>
|
||||
<td style="width:30px;">
|
||||
|
@ -668,11 +668,11 @@
|
|||
<div class="form-group row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<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" %}">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-danger" name="unset_autostart" value="{% trans "Disable" %}">
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -681,23 +681,23 @@
|
|||
<form action="" method="post" role="form" aria-label="Enable/disable instance boot order form">{% csrf_token %}
|
||||
<div class="form-group row">
|
||||
<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 " %}
|
||||
{% ifequal bootmenu 0 %}
|
||||
{% if bootmenu == 0 %}
|
||||
<input type="submit" class="btn btn-success" name="set_bootmenu" title="{% trans 'Show boot menu' %}" value="{% trans "Enable" %}">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-danger" name="unset_bootmenu" title="{% trans 'Hide boot menu' %}" value="{% trans "Disable" %}">
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% ifequal bootmenu 0 %}
|
||||
{% if bootmenu == 0 %}
|
||||
<p>**** {% trans "Please shutdown instance to modify boot menu" %} ****</p>
|
||||
{% endifequal %}
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% ifequal bootmenu 1 %}
|
||||
{% if bootmenu == 1 %}
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="col-sm-6 bg-light rounded shadow-sm">
|
||||
{% for idx, val in boot_order.items %}
|
||||
|
@ -734,7 +734,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<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="name" value="{{ disk.image }}">
|
||||
{% 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?" %}')">
|
||||
<i class="fa fa-eject"></i>
|
||||
</button>
|
||||
|
@ -880,16 +880,15 @@
|
|||
<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>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="network">
|
||||
|
@ -957,10 +956,10 @@
|
|||
<input class="form-control" type="text" value="{{ network.nic }}" readonly/>
|
||||
<select class="form-control" name="net-source-{{ forloop.counter0 }}">
|
||||
{% 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 %}
|
||||
{% 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 %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -972,7 +971,7 @@
|
|||
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% 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 %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -983,7 +982,7 @@
|
|||
<input class="form-control" type="text" value="{{ network.model }}" readonly/>
|
||||
<select class="form-control" name="net-model-{{ forloop.counter0 }}">
|
||||
{% 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 %}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -992,7 +991,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
<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>
|
||||
|
@ -1116,7 +1115,7 @@
|
|||
<div class="form-group row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1140,7 +1139,7 @@
|
|||
<div class="form-group row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1148,7 +1147,7 @@
|
|||
<div class="form-group row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1156,7 +1155,7 @@
|
|||
<div class="form-group row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1164,7 +1163,7 @@
|
|||
<div class="form-group row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1183,7 +1182,7 @@
|
|||
<div class="col-sm-12" id="xmlheight">
|
||||
<textarea id="editor">{{ inst_xml }}</textarea>
|
||||
</div>
|
||||
{% ifequal status 5 %}
|
||||
{% if status == 5 %}
|
||||
<input type="hidden" name="inst_xml">
|
||||
<button type="submit" class="btn btn-lg btn-success float-right" name="change_xml">
|
||||
{% trans "Change" %}
|
||||
|
@ -1192,7 +1191,7 @@
|
|||
<button class="btn btn-lg btn-success float-right disabled">
|
||||
{% trans "Change" %}
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
@ -1241,11 +1240,11 @@
|
|||
</select>
|
||||
|
||||
<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>
|
||||
{% else %}
|
||||
<button class="btn btn-success disabled" name="set_console_type">{% trans "Set" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1264,11 +1263,11 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
<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>
|
||||
{% else %}
|
||||
<button class="btn btn-success disabled" name="set_console_listen_address">{% trans "Set" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1302,11 +1301,11 @@
|
|||
{% if console_passwd %}
|
||||
<a href="#" name="console_show" class="btn btn-md btn-primary" onclick="show_console()">{% trans "Show" %}</a>
|
||||
{% endif %}
|
||||
{% ifequal status 5 %}
|
||||
{% if status == 5 %}
|
||||
<button type="submit" class="btn btn-success" name="set_console_passwd">{% trans "Set" %}</button>
|
||||
{% else %}
|
||||
<button class="btn btn-success disabled" name="set_console_passwd">{% trans "Set" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1334,11 +1333,11 @@
|
|||
</select>
|
||||
|
||||
<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>
|
||||
{% else %}
|
||||
<button class="btn btn-success disabled" name="set_console_keymap">{% trans "Set" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1410,14 +1409,14 @@
|
|||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<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">
|
||||
<span class="input-group-text" >{% trans 'Metadata' %}</span>
|
||||
<div class="input-group-text">
|
||||
<input type="checkbox" name="meta-{{ disk.dev }}" value="true">
|
||||
</div>
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1439,11 +1438,11 @@
|
|||
<textarea name="clone-description" class="form-control"></textarea>
|
||||
</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>
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success float-right disabled" name="clone">{% trans "Clone" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
@ -1475,11 +1474,11 @@
|
|||
</div>
|
||||
<div class="form-group row">
|
||||
<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>
|
||||
{% else %}
|
||||
<button class="btn btn-block btn-success disabled" name="change_options">{% trans "Change" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -1497,11 +1496,11 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
<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>
|
||||
{% else %}
|
||||
<button class="btn btn-success disabled" name="set_video_model">{% trans "Set" %}</button>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1669,10 +1668,9 @@
|
|||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="destroy">
|
||||
<p>{% trans "Delete storage for instance?" %}</p>
|
||||
{% 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>
|
||||
{% else %}
|
||||
|
||||
<form class="form" method="post" role="form" id="delete_form">{% csrf_token %}
|
||||
<div class="ml-3 form-row">
|
||||
<div class="custom-control custom-switch">
|
||||
|
@ -1690,7 +1688,7 @@
|
|||
{% endif %}
|
||||
<button type="submit" class="btn btn-lg btn-success float-right" name="delete">{% trans "Destroy" %}</button>
|
||||
</form>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success disabled float-right" name="delete">{% trans "Destroy" %}</button>
|
||||
{% endif %}
|
||||
|
|
|
@ -13,9 +13,9 @@ from django.shortcuts import render, get_object_or_404
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from computes.models import Compute
|
||||
from instances.models import Instance
|
||||
from appsettings.models import AppSettings
|
||||
from django.contrib.auth.models import User
|
||||
from accounts.models import UserInstance, UserSSHKey
|
||||
from appsettings.models import AppSettings
|
||||
from vrtManager.hostdetails import wvmHostDetails
|
||||
from vrtManager.instance import wvmInstance, wvmInstances
|
||||
from vrtManager.connection import connection_manager
|
||||
|
@ -64,7 +64,7 @@ def allinstances(request):
|
|||
error_messages.append(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())
|
||||
|
||||
|
@ -111,10 +111,11 @@ def instance(request, compute_id, vname):
|
|||
computes_count = computes.count()
|
||||
users = User.objects.all().order_by('username')
|
||||
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
|
||||
appsettings = AppSettings.objects.all()
|
||||
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
|
||||
bottom_bar = AppSettings.objects.get(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").value
|
||||
bottom_bar = appsettings.get(key="VIEW_INSTANCE_DETAIL_BOTTOM_BAR").value
|
||||
try:
|
||||
userinstance = UserInstance.objects.get(instance__compute_id=compute_id,
|
||||
instance__name=vname,
|
||||
|
@ -144,7 +145,7 @@ def instance(request, compute_id, vname):
|
|||
return int(float(size_str))
|
||||
|
||||
def get_clone_free_names(size=10):
|
||||
prefix = settings.CLONE_INSTANCE_DEFAULT_PREFIX
|
||||
prefix = appsettings.get(key="CLONE_INSTANCE_DEFAULT_PREFIX").value
|
||||
free_names = []
|
||||
existing_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)]
|
||||
index = 1
|
||||
|
@ -179,21 +180,22 @@ def instance(request, compute_id, vname):
|
|||
disk_size += int(disk['size']) >> 30
|
||||
|
||||
if ua.max_instances > 0 and instance > ua.max_instances:
|
||||
quota_debug = appsettings.get(key="QUOTA_DEBUG").value
|
||||
msg = "instance"
|
||||
if settings.QUOTA_DEBUG:
|
||||
msg += " (%s > %s)" % (instance, ua.max_instances)
|
||||
if quota_debug:
|
||||
msg += f" ({instance} > {ua.max_instances})"
|
||||
if ua.max_cpus > 0 and cpu > ua.max_cpus:
|
||||
msg = "cpu"
|
||||
if settings.QUOTA_DEBUG:
|
||||
msg += " (%s > %s)" % (cpu, ua.max_cpus)
|
||||
if quota_debug:
|
||||
msg += f" ({cpu} > {ua.max_cpus})"
|
||||
if ua.max_memory > 0 and memory > ua.max_memory:
|
||||
msg = "memory"
|
||||
if settings.QUOTA_DEBUG:
|
||||
msg += " (%s > %s)" % (memory, ua.max_memory)
|
||||
if quota_debug:
|
||||
msg += f" ({memory} > {ua.max_memory})"
|
||||
if ua.max_disk_size > 0 and disk_size > ua.max_disk_size:
|
||||
msg = "disk"
|
||||
if settings.QUOTA_DEBUG:
|
||||
msg += " (%s > %s)" % (disk_size, ua.max_disk_size)
|
||||
if quota_debug:
|
||||
msg += f" ({disk_size} > {ua.max_disk_size})"
|
||||
return msg
|
||||
|
||||
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())
|
||||
discard_modes = sorted(conn.get_discard_modes().items())
|
||||
detect_zeroes_modes = sorted(conn.get_detect_zeroes_modes().items())
|
||||
default_io = settings.INSTANCE_VOLUME_DEFAULT_IO
|
||||
default_discard = settings.INSTANCE_VOLUME_DEFAULT_DISCARD
|
||||
default_zeroes = settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES
|
||||
default_cache = settings.INSTANCE_VOLUME_DEFAULT_CACHE
|
||||
default_format = settings.INSTANCE_VOLUME_DEFAULT_FORMAT
|
||||
default_owner = settings.INSTANCE_VOLUME_DEFAULT_OWNER
|
||||
default_bus = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_BUS").value
|
||||
default_io = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_IO").value
|
||||
default_discard = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_DISCARD").value
|
||||
default_zeroes = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES").value
|
||||
default_cache = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_CACHE").value
|
||||
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()
|
||||
|
||||
show_access_root_password = settings.SHOW_ACCESS_ROOT_PASSWORD
|
||||
show_access_ssh_keys = settings.SHOW_ACCESS_SSH_KEYS
|
||||
clone_instance_auto_name = settings.CLONE_INSTANCE_AUTO_NAME
|
||||
default_bus = settings.INSTANCE_VOLUME_DEFAULT_BUS
|
||||
show_access_root_password = appsettings.get(key="SHOW_ACCESS_ROOT_PASSWORD").value
|
||||
show_access_ssh_keys = appsettings.get(key="SHOW_ACCESS_SSH_KEYS").value
|
||||
clone_instance_auto_name = appsettings.get(key="CLONE_INSTANCE_AUTO_NAME").value
|
||||
|
||||
|
||||
try:
|
||||
instance = Instance.objects.get(compute_id=compute_id, name=vname)
|
||||
|
@ -520,7 +525,7 @@ def instance(request, compute_id, vname):
|
|||
error_messages.append(msg)
|
||||
else:
|
||||
conn.resize_disk(disks_new)
|
||||
msg = _("Resize")
|
||||
msg = _("Disk resize")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
messages.success(request, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
||||
|
@ -539,9 +544,9 @@ def instance(request, compute_id, vname):
|
|||
cache = request.POST.get('cache', default_cache)
|
||||
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)
|
||||
msg = _('Attach new disk {} ({})'.format(name, format))
|
||||
msg = _(f"Attach new disk {name} ({format})")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
||||
|
@ -810,8 +815,11 @@ def instance(request, compute_id, vname):
|
|||
|
||||
if 'set_console_type' in request.POST:
|
||||
console_type = request.POST.get('console_type', '')
|
||||
conn.set_console_type(console_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)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#vncsettings')
|
||||
|
||||
|
@ -943,13 +951,13 @@ def instance(request, compute_id, vname):
|
|||
if 'add_owner' in request.POST:
|
||||
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)
|
||||
else:
|
||||
check_inst = UserInstance.objects.filter(instance=instance)
|
||||
|
||||
if check_inst:
|
||||
msg = _("Owner already added")
|
||||
msg = _("One owner is allowed and owner already added")
|
||||
error_messages.append(msg)
|
||||
else:
|
||||
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)
|
||||
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:
|
||||
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]
|
||||
clone_data['name'] = 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)
|
||||
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()
|
||||
migrate_instance(new_compute, new_instance, xml_del=True, offline=True)
|
||||
return HttpResponseRedirect(
|
||||
|
@ -1326,7 +1338,7 @@ def random_mac_address(request):
|
|||
|
||||
def guess_clone_name(request):
|
||||
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):
|
||||
instance_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)]
|
||||
with open(dhcp_file, 'r') as f:
|
||||
|
|
|
@ -6,6 +6,7 @@ from django.shortcuts import render
|
|||
from django.urls import reverse
|
||||
|
||||
from admin.decorators import superuser_only
|
||||
from appsettings.models import AppSettings
|
||||
from instances.models import Instance
|
||||
from logs.models import Logs
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.http import HttpResponseRedirect, HttpResponse
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from computes.models import Compute
|
||||
from appsettings.models import AppSettings
|
||||
from storages.forms import AddStgPool, AddImage, CloneImage
|
||||
from vrtManager.storage import wvmStorage, wvmStorages
|
||||
from libvirt import libvirtError
|
||||
|
@ -143,8 +144,12 @@ def storage(request, compute_id, pool):
|
|||
if data['meta_prealloc'] and data['format'] == 'qcow2':
|
||||
meta_prealloc = True
|
||||
try:
|
||||
name = conn.create_volume(data['name'], data['size'], data['format'], meta_prealloc)
|
||||
messages.success(request, _("Image file {} is created successfully".format(name)))
|
||||
disk_owner = AppSettings.objects.filter(key__startswith="INSTANCE_VOLUME_DEFAULT_OWNER")
|
||||
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())
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import string
|
||||
from vrtManager import util
|
||||
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):
|
||||
|
@ -23,7 +20,6 @@ def get_rbd_storage_data(stg):
|
|||
|
||||
|
||||
class wvmCreate(wvmConnect):
|
||||
image_format = INSTANCE_VOLUME_DEFAULT_FORMAT
|
||||
|
||||
def get_storages_images(self):
|
||||
"""
|
||||
|
@ -52,7 +48,7 @@ class wvmCreate(wvmConnect):
|
|||
"""Get guest capabilities"""
|
||||
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
|
||||
stg = self.get_storage(storage)
|
||||
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||
|
@ -65,16 +61,16 @@ class wvmCreate(wvmConnect):
|
|||
else:
|
||||
alloc = size
|
||||
metadata = False
|
||||
xml = """
|
||||
xml = f"""
|
||||
<volume>
|
||||
<name>%s</name>
|
||||
<capacity>%s</capacity>
|
||||
<allocation>%s</allocation>
|
||||
<name>{name}</name>
|
||||
<capacity>{size}</capacity>
|
||||
<allocation>{alloc}</allocation>
|
||||
<target>
|
||||
<format type='%s'/>
|
||||
<format type='{image_format}'/>
|
||||
<permissions>
|
||||
<owner>%s</owner>
|
||||
<group>%s</group>
|
||||
<owner>{disk_owner_uid}</owner>
|
||||
<group>{disk_owner_gid}</group>
|
||||
<mode>0644</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>
|
||||
|
@ -83,7 +79,7 @@ class wvmCreate(wvmConnect):
|
|||
<lazy_refcounts/>
|
||||
</features>
|
||||
</target>
|
||||
</volume>""" % (name, size, alloc, image_format, owner['uid'], owner['guid'])
|
||||
</volume>"""
|
||||
stg.createXML(xml, metadata)
|
||||
try:
|
||||
stg.refresh(0)
|
||||
|
@ -120,7 +116,7 @@ class wvmCreate(wvmConnect):
|
|||
vol = self.get_volume_by_path(vol_path)
|
||||
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)
|
||||
if not storage:
|
||||
stg = vol.storagePoolLookupByVolume()
|
||||
|
@ -133,16 +129,16 @@ class wvmCreate(wvmConnect):
|
|||
clone += '.img'
|
||||
else:
|
||||
metadata = False
|
||||
xml = """
|
||||
xml = f"""
|
||||
<volume>
|
||||
<name>%s</name>
|
||||
<name>{clone}</name>
|
||||
<capacity>0</capacity>
|
||||
<allocation>0</allocation>
|
||||
<target>
|
||||
<format type='%s'/>
|
||||
<format type='{format}'/>
|
||||
<permissions>
|
||||
<owner>%s</owner>
|
||||
<group>%s</group>
|
||||
<owner>{disk_owner_uid}</owner>
|
||||
<group>{disk_owner_gid}</group>
|
||||
<mode>0644</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>
|
||||
|
@ -151,7 +147,7 @@ class wvmCreate(wvmConnect):
|
|||
<lazy_refcounts/>
|
||||
</features>
|
||||
</target>
|
||||
</volume>""" % (clone, format, owner['uid'], owner['guid'])
|
||||
</volume>"""
|
||||
stg.createXMLFrom(xml, vol, metadata)
|
||||
clone_vol = stg.storageVolLookupByName(clone)
|
||||
return clone_vol.path()
|
||||
|
@ -163,11 +159,9 @@ class wvmCreate(wvmConnect):
|
|||
vol = self.get_volume_by_path(path)
|
||||
vol.delete()
|
||||
|
||||
def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, images,
|
||||
def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, volumes,
|
||||
networks, nwfilter, graphics, virtio, listen_addr,
|
||||
video="vga", console_pass="random", mac=None,
|
||||
cache_mode=None, io_mode=None, discard_mode=None, detect_zeroes_mode=None,
|
||||
qemu_ga=True):
|
||||
video="vga", console_pass="random", mac=None, qemu_ga=True):
|
||||
"""
|
||||
Create VM function
|
||||
"""
|
||||
|
@ -176,17 +170,17 @@ class wvmCreate(wvmConnect):
|
|||
|
||||
memory = int(memory) * 1024
|
||||
|
||||
xml = """
|
||||
<domain type='%s'>
|
||||
<name>%s</name>
|
||||
xml = f"""
|
||||
<domain type='{dom_caps["domain"]}'>
|
||||
<name>{name}</name>
|
||||
<description>None</description>
|
||||
<uuid>%s</uuid>
|
||||
<memory unit='KiB'>%s</memory>
|
||||
<vcpu>%s</vcpu>""" % (dom_caps["domain"], name, uuid, memory, vcpu)
|
||||
<uuid>{uuid}</uuid>
|
||||
<memory unit='KiB'>{memory}</memory>
|
||||
<vcpu>{vcpu}</vcpu>"""
|
||||
|
||||
if dom_caps["os_support"] == 'yes':
|
||||
xml += """<os>
|
||||
<type arch='%s' machine='%s'>%s</type>""" % (arch, machine, caps["os_type"])
|
||||
xml += f"""<os>
|
||||
<type arch='{arch}' machine='{machine}'>{caps["os_type"]}</type>"""
|
||||
xml += """ <boot dev='hd'/>
|
||||
<boot dev='cdrom'/>
|
||||
<bootmenu enable='yes'/>"""
|
||||
|
@ -221,8 +215,8 @@ class wvmCreate(wvmConnect):
|
|||
elif vcpu_mode == "":
|
||||
pass
|
||||
else:
|
||||
xml += """<cpu mode='custom' match='exact' check='none'>
|
||||
<model fallback='allow'>%s</model>""" % vcpu_mode
|
||||
xml += f"""<cpu mode='custom' match='exact' check='none'>
|
||||
<model fallback='allow'>{vcpu_mode}</model>"""
|
||||
xml += """</cpu>"""
|
||||
|
||||
xml += """
|
||||
|
@ -239,17 +233,18 @@ class wvmCreate(wvmConnect):
|
|||
sd_disk_letters = list(string.ascii_lowercase)
|
||||
add_cd = True
|
||||
|
||||
disk_opts = ''
|
||||
if cache_mode is not None and cache_mode != 'default':
|
||||
disk_opts += "cache='%s' " % cache_mode
|
||||
if io_mode is not None and io_mode != 'default':
|
||||
disk_opts += "io='%s' " % io_mode
|
||||
if discard_mode is not None and discard_mode != 'default':
|
||||
disk_opts += "discard='%s' " % discard_mode
|
||||
if detect_zeroes_mode is not None and detect_zeroes_mode != 'default':
|
||||
disk_opts += "detect_zeroes='%s' " % detect_zeroes_mode
|
||||
for volume in volumes:
|
||||
|
||||
disk_opts = ''
|
||||
if volume['cache_mode'] is not None and volume['cache_mode'] != 'default':
|
||||
disk_opts += f"cache='{volume['cache_mode']}' "
|
||||
if volume['io_mode'] is not None and volume['io_mode'] != 'default':
|
||||
disk_opts += f"io='{volume['io_mode']}' "
|
||||
if volume['discard_mode'] is not None and volume['discard_mode'] != 'default':
|
||||
disk_opts += f"discard='{volume['discard_mode']}' "
|
||||
if volume['detect_zeroes_mode'] is not None and volume['detect_zeroes_mode'] != 'default':
|
||||
disk_opts += f"detect_zeroes='{volume['detect_zeroes_mode']}' "
|
||||
|
||||
for volume in images:
|
||||
stg = self.get_storage_by_vol_path(volume['path'])
|
||||
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||
|
||||
|
@ -275,7 +270,7 @@ class wvmCreate(wvmConnect):
|
|||
else:
|
||||
xml += """<disk type='file' device='%s'>""" % volume['device']
|
||||
xml += """ <driver name='qemu' type='%s' %s/>""" % (volume['type'], disk_opts)
|
||||
xml += """ <source file='%s'/>""" % volume['path']
|
||||
xml += f""" <source file='%s'/>""" % volume['path']
|
||||
|
||||
if volume.get('bus') == 'virtio':
|
||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume.get('bus'))
|
||||
|
@ -304,15 +299,15 @@ class wvmCreate(wvmConnect):
|
|||
xml += """</disk>"""
|
||||
|
||||
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(','):
|
||||
xml += """<interface type='network'>"""
|
||||
if mac:
|
||||
xml += """<mac address='%s'/>""" % mac
|
||||
xml += """<source network='%s'/>""" % net
|
||||
xml += f"""<mac address='{mac}'/>"""
|
||||
xml += f"""<source network='{net}'/>"""
|
||||
if nwfilter:
|
||||
xml += """<filterref filter='%s'/>""" % nwfilter
|
||||
xml += f"""<filterref filter='{nwfilter}'/>"""
|
||||
if virtio:
|
||||
xml += """<model type='virtio'/>"""
|
||||
xml += """</interface>"""
|
||||
|
@ -332,18 +327,18 @@ class wvmCreate(wvmConnect):
|
|||
xml += """<input type='keyboard'/>"""
|
||||
xml += """<input type='tablet'/>"""
|
||||
|
||||
xml += """
|
||||
<graphics type='%s' port='-1' autoport='yes' %s listen='%s'/>
|
||||
<console type='pty'/> """ % (graphics, console_pass, listen_addr)
|
||||
xml += f"""
|
||||
<graphics type='{graphics}' port='-1' autoport='yes' {console_pass} listen='{listen_addr}'/>
|
||||
<console type='pty'/> """
|
||||
|
||||
if qemu_ga and virtio:
|
||||
xml += """ <channel type='unix'>
|
||||
<target type='virtio' name='org.qemu.guest_agent.0'/>
|
||||
</channel>"""
|
||||
|
||||
xml += """ <video>
|
||||
<model type='%s'/>
|
||||
xml += f""" <video>
|
||||
<model type='{video}'/>
|
||||
</video>
|
||||
</devices>
|
||||
</domain>""" % video
|
||||
</domain>"""
|
||||
self._defineXML(xml)
|
||||
|
|
|
@ -22,8 +22,6 @@ from collections import OrderedDict
|
|||
from vrtManager import util
|
||||
from vrtManager.connection import wvmConnect
|
||||
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):
|
||||
|
@ -909,7 +907,7 @@ class wvmInstance(wvmConnect):
|
|||
current_type = self.get_console_type()
|
||||
if current_type == console_type:
|
||||
return True
|
||||
if console_type == '' or console_type not in QEMU_CONSOLE_TYPES:
|
||||
if console_type == '':
|
||||
return False
|
||||
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||
root = ElementTree.fromstring(xml)
|
||||
|
@ -1203,8 +1201,8 @@ class wvmInstance(wvmConnect):
|
|||
<target>
|
||||
<format type='{vol_format}'/>
|
||||
<permissions>
|
||||
<owner>{OWNER['uid']}</owner>
|
||||
<group>{OWNER['guid']}</group>
|
||||
<owner>{clone_data['disk_owner_uid']}</owner>
|
||||
<group>{clone_data['disk_owner_gid']}</group>
|
||||
<mode>0644</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from vrtManager import util
|
||||
from vrtManager.connection import wvmConnect
|
||||
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as OWNER
|
||||
|
||||
|
||||
class wvmStorages(wvmConnect):
|
||||
|
@ -210,7 +209,7 @@ class wvmStorage(wvmConnect):
|
|||
)
|
||||
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
|
||||
storage_type = self.get_type()
|
||||
alloc = size
|
||||
|
@ -230,8 +229,8 @@ class wvmStorage(wvmConnect):
|
|||
<target>
|
||||
<format type='{vol_fmt}'/>
|
||||
<permissions>
|
||||
<owner>{owner['uid']}</owner>
|
||||
<group>{owner['guid']}</group>
|
||||
<owner>{disk_owner_uid}</owner>
|
||||
<group>{disk_owner_gid}</group>
|
||||
<mode>0644</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>"""
|
||||
|
@ -246,7 +245,7 @@ class wvmStorage(wvmConnect):
|
|||
self._createXML(xml, metadata)
|
||||
return name
|
||||
|
||||
def clone_volume(self, name, target_file, vol_fmt=None, metadata=False, mode='0644', file_suffix='img', 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)
|
||||
if not vol_fmt:
|
||||
vol_fmt = self.get_volume_type(name)
|
||||
|
@ -267,8 +266,8 @@ class wvmStorage(wvmConnect):
|
|||
<target>
|
||||
<format type='{vol_fmt}'/>
|
||||
<permissions>
|
||||
<owner>{owner['uid']}</owner>
|
||||
<group>{owner['guid']}</group>
|
||||
<owner>{disk_owner_uid}</owner>
|
||||
<group>{disk_owner_gid}</group>
|
||||
<mode>{mode}</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>"""
|
||||
|
|
|
@ -174,52 +174,10 @@ LIBVIRT_KEEPALIVE_INTERVAL = 5
|
|||
LIBVIRT_KEEPALIVE_COUNT = 5
|
||||
|
||||
ALLOW_INSTANCE_MULTIPLE_OWNER = True
|
||||
ALLOW_EMPTY_PASSWORD = False
|
||||
NEW_USER_DEFAULT_INSTANCES = []
|
||||
CLONE_INSTANCE_DEFAULT_PREFIX = 'instance'
|
||||
CLONE_INSTANCE_AUTO_NAME = False
|
||||
CLONE_INSTANCE_AUTO_MIGRATE = False
|
||||
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'
|
||||
|
||||
|
|
Loading…
Reference in a new issue