1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-12-24 15:15:22 +00:00
webvirtcloud/instances/views.py
2020-10-07 18:04:43 +06:00

1486 lines
60 KiB
Python

import crypt
import json
import os
import re
import socket
import time
from bisect import insort
from accounts.models import UserInstance, UserSSHKey
from admin.decorators import superuser_only
from appsettings.models import AppSettings
from appsettings.settings import app_settings
from computes.models import Compute
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import User
from django.http import Http404, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError)
from logs.views import addlogmsg
from vrtManager import util
from vrtManager.create import wvmCreate
from vrtManager.instance import wvmInstances
from vrtManager.storage import wvmStorage
from vrtManager.util import randomPasswd
from instances.models import Instance
from . import utils
from .forms import ConsoleForm, FlavorForm, NewVMForm
from .models import Flavor
def index(request):
instances = None
computes = Compute.objects.all().order_by("name").prefetch_related('instance_set').prefetch_related(
'instance_set__userinstance_set')
for compute in computes:
utils.refr(compute)
if request.user.is_superuser:
instances = Instance.objects.all().prefetch_related('userinstance_set')
else:
instances = Instance.objects.filter(userinstance__user=request.user).prefetch_related('userinstance_set')
return render(request, 'allinstances.html', {'computes': computes, 'instances': instances})
def instance(request, pk):
instance: Instance = get_object_or_404(Instance, pk=pk)
compute: Compute = instance.compute
computes = Compute.objects.all().order_by('name')
computes_count = computes.count()
users = User.objects.all().order_by('username')
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
keymaps = settings.QEMU_KEYMAPS
console_types = AppSettings.objects.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list()
#
console_form = ConsoleForm(
initial={
'type': instance.console_type,
'listen_on': instance.console_listen_address,
'password': instance.console_passwd,
'keymap': instance.console_keymap,
})
#
console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES
bottom_bar = app_settings.VIEW_INSTANCE_DETAIL_BOTTOM_BAR
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
try:
userinstance = UserInstance.objects.get(instance__compute_id=compute.id,
instance__name=instance.name,
user__id=request.user.id)
except UserInstance.DoesNotExist:
userinstance = None
if not request.user.is_superuser:
if not userinstance:
return redirect(reverse('index'))
if len(instance.media) != 0:
media_iso = sorted(instance.proxy.get_iso_media())
else:
media_iso = []
memory_range = [256, 512, 768, 1024, 2048, 3072, 4096, 6144, 8192, 16384]
if instance.memory not in memory_range:
insort(memory_range, instance.memory)
if instance.cur_memory not in memory_range:
insort(memory_range, instance.cur_memory)
clone_free_names = utils.get_clone_free_names()
user_quota_msg = utils.check_user_quota(request.user, 0, 0, 0, 0)
default_bus = app_settings.INSTANCE_VOLUME_DEFAULT_BUS
default_io = app_settings.INSTANCE_VOLUME_DEFAULT_IO
default_discard = app_settings.INSTANCE_VOLUME_DEFAULT_DISCARD
default_zeroes = app_settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES
default_cache = app_settings.INSTANCE_VOLUME_DEFAULT_CACHE
default_format = app_settings.INSTANCE_VOLUME_DEFAULT_FORMAT
# default_disk_owner_uid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
# default_disk_owner_gid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID)
# clone_instance_auto_name = app_settings.CLONE_INSTANCE_AUTO_NAME
# try:
# instance = Instance.objects.get(compute=compute, name=vname)
# if instance.uuid != uuid:
# instance.uuid = uuid
# instance.save()
# msg = _(f"Fixing UUID {uuid}")
# addlogmsg(request.user.username, instance.name, msg)
# except Instance.DoesNotExist:
# instance = Instance(compute=compute, name=vname, uuid=uuid)
# instance.save()
# msg = _("Instance does not exist: Creating new instance")
# addlogmsg(request.user.username, instance.name, msg)
# userinstances = UserInstance.objects.filter(instance=instance).order_by('user__username')
userinstances = instance.userinstance_set.order_by('user__username')
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
# Host resources
vcpu_host = len(instance.vcpu_range)
memory_host = instance.proxy.get_max_memory()
bus_host = instance.proxy.get_disk_bus_types(instance.arch, instance.machine)
# videos_host = instance.proxy.get_video_models(instance.arch, instance.machine)
networks_host = sorted(instance.proxy.get_networks())
nwfilters_host = instance.proxy.get_nwfilters()
storages_host = sorted(instance.proxy.get_storages(True))
net_models_host = instance.proxy.get_network_models()
try:
interfaces_host = sorted(instance.proxy.get_ifaces())
except Exception as e:
addlogmsg(request.user.username, instance.name, e)
messages.error(request, e)
return render(request, 'instance.html', locals())
def status(request, pk):
instance = get_instance(request.user, pk)
return JsonResponse({'status': instance.proxy.get_status()})
def stats(request, pk):
instance = get_instance(request.user, pk)
json_blk = []
json_net = []
# TODO: stats are inaccurate
cpu_usage = instance.proxy.cpu_usage()
mem_usage = instance.proxy.mem_usage()
blk_usage = instance.proxy.disk_usage()
net_usage = instance.proxy.net_usage()
current_time = time.strftime("%H:%M:%S")
for blk in blk_usage:
json_blk.append({'dev': blk['dev'], 'data': [int(blk['rd']) / 1048576, int(blk['wr']) / 1048576]})
for net in net_usage:
json_net.append({'dev': net['dev'], 'data': [int(net['rx']) / 1048576, int(net['tx']) / 1048576]})
return JsonResponse({
'cpudata': int(cpu_usage['cpu']),
'memdata': mem_usage,
'blkdata': json_blk,
'netdata': json_net,
'timeline': current_time,
})
def guess_mac_address(request, vname):
data = {'vname': vname}
mac = utils.get_dhcp_mac_address(vname)
if not mac:
mac = utils.get_random_mac_address()
data['mac'] = mac
return HttpResponse(json.dumps(data))
def random_mac_address(request):
data = dict()
data['mac'] = utils.get_random_mac_address()
return HttpResponse(json.dumps(data))
def guess_clone_name(request):
dhcp_file = '/srv/webvirtcloud/dhcpd.conf'
prefix = app_settings.CLONE_INSTANCE_DEFAULT_PREFIX
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:
for line in f:
line = line.strip()
if f"host {prefix}" in line:
fqdn = line.split(' ')[1]
hostname = fqdn.split('.')[0]
if hostname.startswith(prefix) and hostname not in instance_names:
return HttpResponse(json.dumps({'name': hostname}))
return HttpResponse(json.dumps({}))
def check_instance(request, vname):
instance = Instance.objects.filter(name=vname)
data = {'vname': vname, 'exists': False}
if instance:
data['exists'] = True
return HttpResponse(json.dumps(data))
def sshkeys(request, vname):
"""
:param request:
:param vname:
:return:
"""
instance_keys = []
userinstances = UserInstance.objects.filter(instance__name=vname)
for ui in userinstances:
keys = UserSSHKey.objects.filter(user=ui.user)
for k in keys:
instance_keys.append(k.keypublic)
if request.GET.get('plain', ''):
response = '\n'.join(instance_keys)
response += '\n'
else:
response = json.dumps(instance_keys)
return HttpResponse(response)
def get_instance(user, pk):
'''
Check that instance is available for user, if not raise 404
'''
instance = Instance.objects.get(pk=pk)
user_instances = user.userinstance_set.all().values_list('instance', flat=True)
if user.is_superuser or instance.id in user_instances:
return instance
else:
raise Http404()
def poweron(request, pk):
instance = get_instance(request.user, pk)
if instance.is_template:
messages.warning(request, _("Templates cannot be started."))
else:
instance.proxy.start()
addlogmsg(request.user.username, instance.name, _("Power On"))
return redirect(request.META.get('HTTP_REFERER'))
def powercycle(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.force_shutdown()
instance.proxy.start()
addlogmsg(request.user.username, instance.name, _("Power Cycle"))
return redirect(request.META.get('HTTP_REFERER'))
def poweroff(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.shutdown()
addlogmsg(request.user.username, instance.name, _("Power Off"))
return redirect(request.META.get('HTTP_REFERER'))
@superuser_only
def suspend(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.suspend()
addlogmsg(request.user.username, instance.name, _("Suspend"))
return redirect(request.META.get('HTTP_REFERER'))
@superuser_only
def resume(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.resume()
addlogmsg(request.user.username, instance.name, _("Resume"))
return redirect(request.META.get('HTTP_REFERER'))
def force_off(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.force_shutdown()
addlogmsg(request.user.username, instance.name, _("Force Off"))
return redirect(request.META.get('HTTP_REFERER'))
def destroy(request, pk):
instance = get_instance(request.user, pk)
try:
userinstance = instance.userinstance_set.get(user=request.user)
except:
userinstance = UserInstance(is_delete=request.user.is_superuser)
if request.method == 'POST' and userinstance.is_delete:
if instance.proxy.get_status() == 1:
instance.proxy.force_shutdown()
if request.POST.get('delete_disk', ''):
snapshots = sorted(instance.proxy.get_snapshot(), reverse=True, key=lambda k: k['date'])
for snapshot in snapshots:
instance.proxy.snapshot_delete(snapshot['name'])
instance.proxy.delete_all_disks()
if request.POST.get('delete_nvram', ''):
instance.proxy.delete(VIR_DOMAIN_UNDEFINE_NVRAM)
else:
instance.proxy.delete(VIR_DOMAIN_UNDEFINE_KEEP_NVRAM)
instance.delete()
addlogmsg(request.user, instance.name, _("Destroy"))
return redirect(reverse('instances:index'))
return render(
request,
'instances/destroy_instance_form.html',
{
'instance': instance,
'userinstance': userinstance,
},
)
@superuser_only
def migrate(request, pk):
instance = get_instance(request.user, pk)
compute_id = request.POST.get('compute_id', '')
live = request.POST.get('live_migrate', False)
unsafe = request.POST.get('unsafe_migrate', False)
xml_del = request.POST.get('xml_delete', False)
offline = request.POST.get('offline_migrate', False)
autoconverge = request.POST.get('autoconverge', False)
compress = request.POST.get('compress', False)
postcopy = request.POST.get('postcopy', False)
new_compute = Compute.objects.get(id=compute_id)
try:
utils.migrate_instance(new_compute, instance, request.user, live, unsafe, xml_del, offline)
except libvirtError as err:
messages.error(request, err)
msg = _("Migrate to %(hostname)%") % {'hostname': new_compute.hostname}
addlogmsg(request.user, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER'))
def set_root_pass(request, pk):
instance = get_instance(request.user, pk)
if request.method == 'POST':
passwd = request.POST.get('passwd', None)
if passwd:
passwd_hash = crypt.crypt(passwd, '$6$kgPoiREy')
data = {'action': 'password', 'passwd': passwd_hash, 'vname': instance.name}
if instance.proxy.get_status() == 5:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((instance.compute.hostname, 16510))
s.send(bytes(json.dumps(data).encode()))
d = s.recv(1024).strip()
result = json.loads(d)
s.close()
if result['return'] == 'success':
msg = _("Reset root password")
addlogmsg(request.user.username, instance.name, msg)
messages.success(request, msg)
else:
messages.error(request, result['message'])
else:
msg = _("Please shutdown down your instance and then try again")
messages.error(request, msg)
return redirect(reverse('instances:instance', args=[instance.id]) + '#access')
def add_public_key(request, pk):
instance = get_instance(request.user, pk)
if request.method == 'POST':
sshkeyid = request.POST.get('sshkeyid', '')
publickey = UserSSHKey.objects.get(id=sshkeyid)
data = {'action': 'publickey', 'key': publickey.keypublic, 'vname': instance.name}
if instance.proxy.get_status() == 5:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((instance.compute.hostname, 16510))
s.send(json.dumps(data).encode())
result = json.loads(s.recv(1024))
s.close()
if result['return'] == 'error':
msg = result['message']
else:
msg = _("Installed new SSH public key %(keyname)s") % {'keyname': publickey.keyname}
addlogmsg(request.user.username, instance.name, msg)
if result['return'] == 'success':
messages.success(request, msg)
else:
messages.error(request, msg)
else:
msg = _("Please shutdown down your instance and then try again")
messages.error(request, msg)
return redirect(reverse('instances:instance', args=[instance.id]) + '#access')
def resizevm_cpu(request, pk):
instance = get_instance(request.user, pk)
try:
userinstance = instance.userinstance_set.get(user=request.user)
except:
userinstance = UserInstance(is_change=False)
vcpu = instance.proxy.get_vcpu()
if request.method == 'POST':
if request.user.is_superuser or request.user.is_staff or userinstance.is_change:
new_vcpu = request.POST.get('vcpu', '')
new_cur_vcpu = request.POST.get('cur_vcpu', '')
quota_msg = utils.check_user_quota(request.user, 0, int(new_vcpu) - vcpu, 0, 0)
if not request.user.is_superuser and quota_msg:
msg = _("User %(quota_msg)s quota reached, cannot resize CPU of '%(instance_name)s'!") % {
'quota_msg': quota_msg,
'instance_name': instance.name
}
messages.error(request, msg)
else:
cur_vcpu = new_cur_vcpu
vcpu = new_vcpu
instance.proxy.resize_cpu(cur_vcpu, vcpu)
msg = _("Resize CPU")
addlogmsg(request.user.username, instance.name, msg)
messages.success(request, msg)
return redirect(reverse('instances:instance', args=[instance.id]) + '#resize')
def resize_memory(request, pk):
instance = get_instance(request.user, pk)
try:
userinstance = instance.userinstance_set.get(user=request.user)
except:
userinstance = UserInstance(is_change=False)
memory = instance.proxy.get_memory()
cur_memory = instance.proxy.get_cur_memory()
if request.method == 'POST':
if request.user.is_superuser or request.user.is_staff or userinstance.is_change:
new_memory = request.POST.get('memory', '')
new_memory_custom = request.POST.get('memory_custom', '')
if new_memory_custom:
new_memory = new_memory_custom
new_cur_memory = request.POST.get('cur_memory', '')
new_cur_memory_custom = request.POST.get('cur_memory_custom', '')
if new_cur_memory_custom:
new_cur_memory = new_cur_memory_custom
quota_msg = utils.check_user_quota(request.user, 0, 0, int(new_memory) - memory, 0)
if not request.user.is_superuser and quota_msg:
msg = _("User %(quota_msg)s quota reached, cannot resize memory of '%(instance_name)s'!") % {
'quota_msg': quota_msg,
'instance_name': instance.name
}
messages.error(request, msg)
else:
cur_memory = new_cur_memory
memory = new_memory
instance.proxy.resize_mem(cur_memory, memory)
msg = _("Resize Memory")
addlogmsg(request.user.username, instance.name, msg)
messages.success(request, msg)
return redirect(reverse('instances:instance', args=[instance.id]) + '#resize')
def resize_disk(request, pk):
instance = get_instance(request.user, pk)
try:
userinstance = instance.userinstance_set.get(user=request.user)
except:
userinstance = UserInstance(is_change=False)
disks = instance.proxy.get_disk_devices()
if request.method == 'POST':
if request.user.is_superuser or request.user.is_staff or userinstance.is_change:
disks_new = list()
for disk in disks:
# input_disk_size = utils.filesizefstr(request.POST.get('disk_size_' + disk['dev'], ''))
input_disk_size = int(request.POST.get('disk_size_' + disk['dev'], '0')) * 1073741824
if input_disk_size > disk['size'] + (64 << 20):
disk['size_new'] = input_disk_size
disks_new.append(disk)
disk_sum = sum([disk['size'] >> 30 for disk in disks_new])
disk_new_sum = sum([disk['size_new'] >> 30 for disk in disks_new])
quota_msg = utils.check_user_quota(request.user, 0, 0, 0, disk_new_sum - disk_sum)
if not request.user.is_superuser and quota_msg:
msg = _("User %(quota_msg)s quota reached, cannot resize disks of '%(instance_name)s'!") % {
'quota_msg': quota_msg,
'instance_name': instance.name
}
messages.error(request, msg)
else:
instance.proxy.resize_disk(disks_new)
msg = _("Disk resize")
addlogmsg(request.user.username, instance.name, msg)
messages.success(request, msg)
return redirect(reverse('instances:instance', args=[instance.id]) + '#resize')
def add_new_vol(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
media = instance.proxy.get_media_devices()
disks = instance.proxy.get_disk_devices()
conn_create = wvmCreate(
instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
)
storage = request.POST.get('storage', '')
name = request.POST.get('name', '')
format = request.POST.get('format', app_settings.INSTANCE_VOLUME_DEFAULT_FORMAT)
size = request.POST.get('size', 0)
meta_prealloc = True if request.POST.get('meta_prealloc', False) else False
bus = request.POST.get('bus', app_settings.INSTANCE_VOLUME_DEFAULT_BUS)
cache = request.POST.get('cache', app_settings.INSTANCE_VOLUME_DEFAULT_CACHE)
target_dev = utils.get_new_disk_dev(media, disks, bus)
source = conn_create.create_volume(
storage,
name,
size,
format,
meta_prealloc,
int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID),
int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID),
)
instance.proxy.attach_disk(target_dev, source, target_bus=bus, driver_type=format, cache_mode=cache)
msg = _("Attach new disk %(name)s (%(format)s)") % {'name': name, 'format': format}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def add_existing_vol(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
storage = request.POST.get('selected_storage', '')
name = request.POST.get('vols', '')
bus = request.POST.get('bus', app_settings.INSTANCE_VOLUME_DEFAULT_BUS)
cache = request.POST.get('cache', app_settings.INSTANCE_VOLUME_DEFAULT_CACHE)
media = instance.proxy.get_media_devices()
disks = instance.proxy.get_disk_devices()
conn_create = wvmStorage(
instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
storage,
)
driver_type = conn_create.get_volume_type(name)
path = conn_create.get_target_path()
target_dev = utils.get_new_disk_dev(media, disks, bus)
source = f"{path}/{name}"
instance.proxy.attach_disk(target_dev, source, target_bus=bus, driver_type=driver_type, cache_mode=cache)
msg = _("Attach Existing disk: %(target_dev)s") % {'target_dev': target_dev}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def edit_volume(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if 'edit_volume' in request.POST and allow_admin_or_not_template:
target_dev = request.POST.get('dev', '')
new_path = request.POST.get('vol_path', '')
shareable = bool(request.POST.get('vol_shareable', False))
readonly = bool(request.POST.get('vol_readonly', False))
disk_type = request.POST.get('vol_type', '')
new_bus = request.POST.get('vol_bus', '')
bus = request.POST.get('vol_bus_old', '')
serial = request.POST.get('vol_serial', '')
format = request.POST.get('vol_format', '')
cache = request.POST.get('vol_cache', app_settings.INSTANCE_VOLUME_DEFAULT_CACHE)
io = request.POST.get('vol_io_mode', app_settings.INSTANCE_VOLUME_DEFAULT_IO)
discard = request.POST.get('vol_discard_mode', app_settings.INSTANCE_VOLUME_DEFAULT_DISCARD)
zeroes = request.POST.get('vol_detect_zeroes', app_settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES)
new_target_dev = utils.get_new_disk_dev(instance.media, instance.disks, new_bus)
if new_bus != bus:
instance.proxy.detach_disk(target_dev)
instance.proxy.attach_disk(
new_target_dev,
new_path,
target_bus=new_bus,
driver_type=format,
cache_mode=cache,
readonly=readonly,
shareable=shareable,
serial=serial,
io_mode=io,
discard_mode=discard,
detect_zeroes_mode=zeroes,
)
else:
instance.proxy.edit_disk(
target_dev,
new_path,
readonly,
shareable,
new_bus,
serial,
format,
cache,
io,
discard,
zeroes,
)
if not instance.proxy.get_status() == 5:
messages.success(request, _("Volume changes are applied. " + "But it will be activated after shutdown"))
else:
messages.success(request, _("Volume is changed successfully."))
msg = _("Edit disk: %(target_dev)s") % {'target_dev': target_dev}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def delete_vol(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
storage = request.POST.get('storage', '')
conn_delete = wvmStorage(
instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
storage,
)
dev = request.POST.get('dev', '')
path = request.POST.get('path', '')
name = request.POST.get('name', '')
msg = _("Delete disk: %(dev)s") % {'dev': dev}
instance.proxy.detach_disk(dev)
conn_delete.del_volume(name)
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def detach_vol(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
dev = request.POST.get('dev', '')
path = request.POST.get('path', '')
instance.proxy.detach_disk(dev)
msg = _("Detach disk: %(dev)s") % {'dev': dev}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def add_cdrom(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
bus = request.POST.get('bus', 'ide' if instance.machine == 'pc' else 'sata')
target = utils.get_new_disk_dev(instance.media, instance.disks, bus)
instance.proxy.attach_disk(target, "", disk_device='cdrom', cache_mode='none', target_bus=bus, readonly=True)
msg = _("Add CD-ROM: %(target)s") % {'target': target}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def detach_cdrom(request, pk, dev):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
# dev = request.POST.get('detach_cdrom', '')
instance.proxy.detach_disk(dev)
msg = _('Detach CD-ROM: %(dev)s') % {'dev': dev}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def unmount_iso(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
image = request.POST.get('path', '')
dev = request.POST.get('umount_iso', '')
instance.proxy.umount_iso(dev, image)
msg = _("Mount media: %(dev)s") % {'dev': dev}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def mount_iso(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
image = request.POST.get('media', '')
dev = request.POST.get('mount_iso', '')
instance.proxy.mount_iso(dev, image)
msg = _("Unmount media: %(dev)s") % {'dev': dev}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#disks')
def snapshot(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
name = request.POST.get('name', '')
instance.proxy.create_snapshot(name)
msg = _("New snapshot: %(name)s") % {'name': name}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#managesnapshot')
def delete_snapshot(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
snap_name = request.POST.get('name', '')
instance.proxy.snapshot_delete(snap_name)
msg = _("Delete snapshot: %(snap_name)s") % {'snap_name': snap_name}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#managesnapshot')
def revert_snapshot(request, pk):
instance = get_instance(request.user, pk)
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
if allow_admin_or_not_template:
snap_name = request.POST.get('name', '')
instance.proxy.snapshot_revert(snap_name)
msg = _("Successful revert snapshot: ")
msg += snap_name
messages.success(request, msg)
msg = _("Revert snapshot")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#managesnapshot')
@superuser_only
def set_vcpu(request, pk):
instance = get_instance(request.user, pk)
id = request.POST.get('id', '')
enabled = request.POST.get('set_vcpu', '')
if enabled == 'True':
instance.proxy.set_vcpu(id, 1)
else:
instance.proxy.set_vcpu(id, 0)
msg = _("VCPU %(id)s is enabled=%(enabled)s") % {'id': id, 'enabled': enabled}
messages.success(request, msg)
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#resize')
@superuser_only
def set_vcpu_hotplug(request, pk):
instance = get_instance(request.user, pk)
status = request.POST.get('vcpu_hotplug', '')
# TODO: f strings are not translatable https://code.djangoproject.com/ticket/29174
msg = _("VCPU Hot-plug is enabled=%(status)s") % {'status': status}
instance.proxy.set_vcpu_hotplug(eval(status))
messages.success(request, msg)
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#resize')
@superuser_only
def set_autostart(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.set_autostart(1)
msg = _("Set autostart")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#boot_opt')
@superuser_only
def unset_autostart(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.set_autostart(0)
msg = _("Unset autostart")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#boot_opt')
@superuser_only
def set_bootmenu(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.set_bootmenu(1)
msg = _("Enable boot menu")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#boot_opt')
@superuser_only
def unset_bootmenu(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.set_bootmenu(0)
msg = _("Disable boot menu")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#boot_opt')
@superuser_only
def set_bootorder(request, pk):
instance = get_instance(request.user, pk)
bootorder = request.POST.get('bootorder', '')
if bootorder:
order_list = {}
for idx, val in enumerate(bootorder.split(',')):
dev_type, dev = val.split(':', 1)
order_list[idx] = {"type": dev_type, "dev": dev}
instance.proxy.set_bootorder(order_list)
msg = _("Set boot order")
if not instance.proxy.get_status() == 5:
messages.success(request, _("Boot menu changes applied. " + "But it will be activated after shutdown"))
else:
messages.success(request, _("Boot order changed successfully."))
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#boot_opt')
@superuser_only
def change_xml(request, pk):
instance = get_instance(request.user, pk)
exit_xml = request.POST.get('inst_xml', '')
if exit_xml:
instance.proxy._defineXML(exit_xml)
msg = _("Edit XML")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#xmledit')
@superuser_only
def set_guest_agent(request, pk):
instance = get_instance(request.user, pk)
status = request.POST.get('guest_agent')
if status == 'True':
instance.proxy.add_guest_agent()
if status == 'False':
instance.proxy.remove_guest_agent()
msg = _("Set Guest Agent %(status)s") % {'status': status}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#options')
@superuser_only
def set_video_model(request, pk):
instance = get_instance(request.user, pk)
video_model = request.POST.get('video_model', 'vga')
instance.proxy.set_video_model(video_model)
msg = _("Set Video Model")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#options')
@superuser_only
def change_network(request, pk):
instance = get_instance(request.user, pk)
msg = _("Change network")
network_data = {}
for post in request.POST:
if post.startswith('net-source-'):
(source, source_type) = utils.get_network_tuple(request.POST.get(post))
network_data[post] = source
network_data[post + '-type'] = source_type
elif post.startswith('net-'):
network_data[post] = request.POST.get(post, '')
instance.proxy.change_network(network_data)
addlogmsg(request.user.username, instance.name, msg)
msg = _("Network Device Config is changed. Please shutdown instance to activate.")
if instance.proxy.get_status() != 5: messages.success(request, msg)
return redirect(request.META.get('HTTP_REFERER') + '#network')
@superuser_only
def add_network(request, pk):
instance = get_instance(request.user, pk)
msg = _("Add network")
mac = request.POST.get('add-net-mac')
nwfilter = request.POST.get('add-net-nwfilter')
(source, source_type) = utils.get_network_tuple(request.POST.get('add-net-network'))
instance.proxy.add_network(mac, source, source_type, nwfilter=nwfilter)
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#network')
@superuser_only
def delete_network(request, pk):
instance = get_instance(request.user, pk)
msg = _("Delete network")
mac_address = request.POST.get('delete_network', '')
instance.proxy.delete_network(mac_address)
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#network')
@superuser_only
def set_link_state(request, pk):
instance = get_instance(request.user, pk)
mac_address = request.POST.get('mac', '')
state = request.POST.get('set_link_state')
state = 'down' if state == 'up' else 'up'
instance.proxy.set_link_state(mac_address, state)
msg = _("Set Link State: %(state)s") % {'state': state}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#network')
@superuser_only
def set_qos(request, pk):
instance = get_instance(request.user, pk)
qos_dir = request.POST.get('qos_direction', '')
average = request.POST.get('qos_average') or 0
peak = request.POST.get('qos_peak') or 0
burst = request.POST.get('qos_burst') or 0
keys = request.POST.keys()
mac_key = [key for key in keys if 'mac' in key]
if mac_key: mac = request.POST.get(mac_key[0])
instance.proxy.set_qos(mac, qos_dir, average, peak, burst)
if instance.proxy.get_status() == 5:
messages.success(request, _("%(qos_dir)s QoS is set") % {'qos_dir': qos_dir.capitalize()})
else:
messages.success(
request,
_("%(qos_dir)s QoS is set. Network XML is changed. \
Stop and start network to activate new config.") % {'qos_dir': qos_dir.capitalize()})
return redirect(request.META.get('HTTP_REFERER') + '#network')
@superuser_only
def unset_qos(request, pk):
instance = get_instance(request.user, pk)
qos_dir = request.POST.get('qos_direction', '')
mac = request.POST.get('net-mac')
instance.proxy.unset_qos(mac, qos_dir)
if instance.proxy.get_status() == 5:
messages.success(request, _("%(qos_dir)s QoS is deleted") % {'qos_dir': qos_dir.capitalize()})
else:
messages.success(
request,
_("%(qos_dir)s QoS is deleted. Network XML is changed. \
Stop and start network to activate new config.") % {'qos_dir': qos_dir.capitalize()})
return redirect(request.META.get('HTTP_REFERER') + '#network')
@superuser_only
def add_owner(request, pk):
instance = get_instance(request.user, pk)
user_id = request.POST.get('user_id')
check_inst = 0
if app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER == 'False':
check_inst = UserInstance.objects.filter(instance=instance).count()
if check_inst > 1:
messages.error(request, _("Only one owner is allowed and the one already added"))
else:
add_user_inst = UserInstance(instance=instance, user_id=user_id)
add_user_inst.save()
user = User.objects.get(id=user_id)
msg = _("Added owner %(user)s") % {'user': user}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#users')
@superuser_only
def del_owner(request, pk):
instance = get_instance(request.user, pk)
userinstance_id = int(request.POST.get('userinstance', ''))
userinstance = UserInstance.objects.get(pk=userinstance_id)
userinstance.delete()
msg = _("Deleted owner %(userinstance_id)s") % {'userinstance_id': userinstance_id}
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#users')
@permission_required('instances.clone_instances')
def clone(request, pk):
instance = get_instance(request.user, pk)
clone_data = dict()
clone_data['name'] = request.POST.get('name', '')
disk_sum = sum([disk['size'] >> 30 for disk in instance.disks])
quota_msg = utils.check_user_quota(request.user, 1, instance.vcpu, instance.memory, disk_sum)
check_instance = Instance.objects.filter(name=clone_data['name'])
clone_data['disk_owner_uid'] = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
clone_data['disk_owner_gid'] = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID)
for post in request.POST:
clone_data[post] = request.POST.get(post, '').strip()
if app_settings.CLONE_INSTANCE_AUTO_NAME == 'True' and not clone_data['name']:
auto_vname = utils.get_clone_free_names()[0]
clone_data['name'] = auto_vname
clone_data['clone-net-mac-0'] = utils.get_dhcp_mac_address(auto_vname)
for disk in instance.disks:
disk_dev = f"disk-{disk['dev']}"
disk_name = utils.get_clone_disk_name(disk, instance.name, auto_vname)
clone_data[disk_dev] = disk_name
if not request.user.is_superuser and quota_msg:
msg = _("User '%(quota_msg)s' quota reached, cannot create '%(clone_name)s'!") % {
'quota_msg': quota_msg,
'clone_name': clone_data['name'],
}
messages.error(request, msg)
elif check_instance:
msg = _("Instance 'clone_name' already exists!") % {'clone_name': clone_data['name']}
messages.error(request, msg)
elif not re.match(r'^[a-zA-Z0-9-]+$', clone_data['name']):
msg = _("Instance name '%(clone_name)s' contains invalid characters!") % {'clone_name': clone_data['name']}
messages.error(request, msg)
elif not re.match(r'^([0-9A-F]{2})(:?[0-9A-F]{2}){5}$', clone_data['clone-net-mac-0'], re.IGNORECASE):
msg = _("Instance MAC '%(clone_mac)s' invalid format!") % {'clone_mac': clone_data['clone-net-mac-0']}
messages.error(request, msg)
else:
new_instance = Instance(compute=instance.compute, name=clone_data['name'])
try:
new_uuid = instance.proxy.clone_instance(clone_data)
new_instance.uuid = new_uuid
new_instance.save()
user_instance = UserInstance(instance_id=new_instance.id, user_id=request.user.id, is_delete=True)
user_instance.save()
msg = _("Clone of '%(instance_name)s'") % {'instance_name': instance.name}
addlogmsg(request.user.username, new_instance.name, msg)
if app_settings.CLONE_INSTANCE_AUTO_MIGRATE == 'True':
new_compute = Compute.objects.order_by('?').first()
utils.migrate_instance(new_compute, new_instance, request.user, xml_del=True, offline=True)
return redirect(reverse('instances:instance', args=[new_instance.id]))
except Exception as e:
messages.error(request, e)
return redirect(request.META.get('HTTP_REFERER') + '#clone')
def update_console(request, pk):
instance = get_instance(request.user, pk)
try:
userinstance = instance.userinstance_set.get(user=request.user)
except:
userinstance = UserInstance(is_vnc=False)
if request.user.is_superuser or request.user.is_staff or userinstance.is_vnc:
form = ConsoleForm(request.POST or None)
if form.is_valid():
if 'generate_password' in form.changed_data or 'clear_password' in form.changed_data or 'password' in form.changed_data:
if form.cleaned_data['generate_password']:
password = randomPasswd()
elif form.cleaned_data['clear_password']:
password = ''
else:
password = form.cleaned_data['password']
if not instance.proxy.set_console_passwd(password):
msg = _("Error setting console password. " + "You should check that your instance have an graphic device.")
messages.error(request, msg)
else:
msg = _("Set VNC password")
addlogmsg(request.user.username, instance.name, msg)
if 'keymap' in form.changed_data or 'clear_keymap' in form.changed_data:
if form.cleaned_data['clear_keymap']:
instance.proxy.set_console_keymap('')
else:
instance.proxy.set_console_keymap(form.cleaned_data['keymap'])
msg = _("Set VNC keymap")
addlogmsg(request.user.username, instance.name, msg)
if 'type' in form.changed_data:
instance.proxy.set_console_type(form.cleaned_data['type'])
msg = _("Set VNC type")
addlogmsg(request.user.username, instance.name, msg)
if 'listen_on' in form.changed_data:
instance.proxy.set_console_listen_addr(form.cleaned_data['listen_on'])
msg = _("Set VNC listen address")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#vncsettings')
def change_options(request, pk):
instance = get_instance(request.user, pk)
try:
userinstance = instance.userinstance_set.get(user=request.user)
except:
userinstance = UserInstance(is_change=False)
if request.user.is_superuser or request.user.is_staff or userinstance.is_change:
instance.is_template = request.POST.get('is_template', False)
instance.save()
options = {}
for post in request.POST:
if post in ['title', 'description']:
options[post] = request.POST.get(post, '')
instance.proxy.set_options(options)
msg = _("Edit options")
addlogmsg(request.user.username, instance.name, msg)
return redirect(request.META.get('HTTP_REFERER') + '#options')
def getvvfile(request, pk):
instance = get_instance(request.user, pk)
conn = wvmInstances(
instance.compute.hostname,
instance.compute.login,
instance.compute.password,
instance.compute.type,
)
msg = _("Send console.vv file")
addlogmsg(request.user.username, instance.name, msg)
response = HttpResponse(content='', content_type='application/x-virt-viewer', status=200, reason=None, charset='utf-8')
response.writelines('[virt-viewer]\n')
response.writelines('type=' + conn.graphics_type(instance.name) + '\n')
if conn.graphics_listen(instance.name) == '0.0.0.0':
response.writelines('host=' + conn.host + '\n')
else:
response.writelines('host=' + conn.graphics_listen(instance.name) + '\n')
response.writelines('port=' + conn.graphics_port(instance.name) + '\n')
response.writelines('title=' + conn.domain_name(instance.name) + '\n')
response.writelines('password=' + conn.graphics_passwd(instance.name) + '\n')
response.writelines('enable-usbredir=1\n')
response.writelines('disable-effects=all\n')
response.writelines('secure-attention=ctrl+alt+ins\n')
response.writelines('release-cursor=ctrl+alt\n')
response.writelines('fullscreen=1\n')
response.writelines('delete-this-file=1\n')
response['Content-Disposition'] = 'attachment; filename="console.vv"'
return response
@superuser_only
def create_instance_select_type(request, compute_id):
"""
:param request:
:param compute_id:
:return:
"""
conn = None
storages = list()
networks = list()
hypervisors = list()
meta_prealloc = False
compute = get_object_or_404(Compute, pk=compute_id)
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
instances = conn.get_instances()
all_hypervisors = conn.get_hypervisors_machines()
# 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 = app_settings.INSTANCE_MACHINE_DEFAULT_TYPE
default_arch = app_settings.INSTANCE_ARCH_DEFAULT_TYPE
if request.method == 'POST':
if 'create_xml' in request.POST:
xml = request.POST.get('dom_xml', '')
try:
name = util.get_xml_path(xml, '/domain/name')
except util.etree.Error as err:
name = None
if name in instances:
error_msg = _("A virtual machine with this name already exists")
messages.error(request, error_msg)
else:
conn._defineXML(xml)
utils.refr(compute)
instance = compute.instance_set.get(name=name)
return redirect(reverse('instances:instance', args=[instance.id]))
return render(request, 'create_instance_w1.html', locals())
@superuser_only
def create_instance(request, compute_id, arch, machine):
"""
:param request:
:param compute_id:
:param arch:
:param machine:
:return:
"""
conn = None
storages = list()
networks = list()
hypervisors = list()
firmwares = list()
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 = app_settings.INSTANCE_FIRMWARE_DEFAULT_TYPE
default_cpu_mode = app_settings.INSTANCE_CPU_DEFAULT_MODE
instances = conn.get_instances()
videos = conn.get_video_models(arch, machine)
cache_modes = sorted(conn.get_cache_modes().items())
default_cache = app_settings.INSTANCE_VOLUME_DEFAULT_CACHE
default_io = app_settings.INSTANCE_VOLUME_DEFAULT_IO
default_zeroes = app_settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES
default_discard = app_settings.INSTANCE_VOLUME_DEFAULT_DISCARD
default_disk_format = app_settings.INSTANCE_VOLUME_DEFAULT_FORMAT
default_disk_owner_uid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
default_disk_owner_gid = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID)
default_scsi_disk_model = app_settings.INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER
listener_addr = settings.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 = app_settings.INSTANCE_VOLUME_DEFAULT_BUS
networks = sorted(conn.get_networks())
nwfilters = conn.get_nwfilters()
storages = sorted(conn.get_storages(only_actives=True))
default_graphics = app_settings.QEMU_CONSOLE_DEFAULT_TYPE
dom_caps = conn.get_dom_capabilities(arch, machine)
caps = conn.get_capabilities(arch)
virtio_support = conn.is_supports_virtio(arch, machine)
hv_supports_uefi = conn.supports_uefi_xml(dom_caps["loader_enums"])
# Add BIOS
label = conn.label_for_firmware_path(arch, None)
if label: firmwares.append(label)
# Add UEFI
loader_path = conn.find_uefi_path_for_arch(arch, dom_caps["loaders"])
label = conn.label_for_firmware_path(arch, loader_path)
if label: firmwares.append(label)
firmwares = list(set(firmwares))
flavor_form = FlavorForm()
if conn:
if not storages:
raise libvirtError(_("You haven't defined any storage pools"))
if not networks:
raise libvirtError(_("You haven't defined any network pools"))
if request.method == 'POST':
if 'create' in request.POST:
firmware = dict()
volume_list = list()
is_disk_created = False
clone_path = ""
form = NewVMForm(request.POST)
if form.is_valid():
data = form.cleaned_data
if data['meta_prealloc']:
meta_prealloc = True
if instances:
if data['name'] in instances:
raise libvirtError(_("A virtual machine with this name already exists"))
if Instance.objects.filter(name__exact=data['name']):
raise libvirtError(_("There is an instance with same name. Remove it and try again!"))
if data['hdd_size']:
if not data['mac']:
raise libvirtError(_("No Virtual Machine MAC has been entered"))
else:
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['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
elif data['template']:
templ_path = conn.get_volume_path(data['template'])
dest_vol = conn.get_volume_path(data["name"] + ".img", data['storage'])
if dest_vol:
raise libvirtError(_("Image has already exist. Please check volumes or change instance name"))
else:
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'
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:
if not data['images']:
raise libvirtError(_("First you need to create or select an image"))
else:
for idx, vol in enumerate(data['images'].split(',')):
path = conn.get_volume_path(vol)
volume = dict()
volume['path'] = path
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)
if data['cache_mode'] not in conn.get_cache_modes():
error_msg = _("Invalid cache mode")
raise libvirtError
if 'UEFI' in data["firmware"]:
firmware["loader"] = data["firmware"].split(":")[1].strip()
firmware["secure"] = 'no'
firmware["readonly"] = 'yes'
firmware["type"] = 'pflash'
if 'secboot' in firmware["loader"] and machine != 'q35':
messages.warning(
request, "Changing machine type from '%s' to 'q35' "
"which is required for UEFI secure boot." % machine)
machine = 'q35'
firmware["secure"] = 'yes'
uuid = util.randomUUID()
try:
conn.create_instance(name=data['name'],
memory=data['memory'],
vcpu=data['vcpu'],
vcpu_mode=data['vcpu_mode'],
uuid=uuid,
arch=arch,
machine=machine,
firmware=firmware,
volumes=volume_list,
networks=data['networks'],
virtio=data['virtio'],
listen_addr=data["listener_addr"],
nwfilter=data["nwfilter"],
graphics=data["graphics"],
video=data["video"],
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")
messages.success(request, msg)
addlogmsg(request.user.username, create_instance.name, msg)
return redirect(reverse('instances:instance', args=[create_instance.id]))
except libvirtError as lib_err:
if data['hdd_size'] or len(volume_list) > 0:
if is_disk_created:
for vol in volume_list:
conn.delete_volume(vol['path'])
messages.error(request, lib_err)
conn.close()
except libvirtError as lib_err:
messages.error(request, lib_err)
return render(request, 'create_instance_w2.html', locals())
@superuser_only
def flavor_create(request):
form = FlavorForm(request.POST or None)
if form.is_valid():
form.save()
messages.success(request, _('Flavor Created'))
return redirect(request.META.get('HTTP_REFERER'))
return render(
request,
'common/form.html',
{
'form': form,
'title': _('Create Flavor')
},
)
@superuser_only
def flavor_update(request, pk):
flavor = get_object_or_404(Flavor, pk=pk)
form = FlavorForm(request.POST or None, instance=flavor)
if form.is_valid():
form.save()
messages.success(request, _('Flavor Updated'))
return redirect(request.META.get('HTTP_REFERER'))
return render(
request,
'common/form.html',
{
'form': form,
'title': _('Update Flavor')
},
)
@superuser_only
def flavor_delete(request, pk):
flavor = get_object_or_404(Flavor, pk=pk)
if request.method == 'POST':
flavor.delete()
messages.success(request, _('Flavor Deleted'))
return redirect(request.META.get('HTTP_REFERER'))
return render(
request,
'common/confirm_delete.html',
{'object': flavor},
)