2020-04-24 16:34:29 +00:00
|
|
|
from django.contrib import messages
|
2015-04-02 12:39:40 +00:00
|
|
|
from django.shortcuts import render, get_object_or_404
|
2015-02-27 12:25:41 +00:00
|
|
|
from django.http import HttpResponseRedirect
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
2020-01-24 07:09:46 +00:00
|
|
|
from django.urls import reverse
|
2020-04-24 16:34:29 +00:00
|
|
|
from libvirt import libvirtError
|
|
|
|
from admin.decorators import superuser_only
|
2015-02-27 12:25:41 +00:00
|
|
|
from computes.models import Compute
|
2015-02-27 12:44:44 +00:00
|
|
|
from create.models import Flavor
|
|
|
|
from create.forms import FlavorAddForm, NewVMForm
|
2020-05-28 21:43:26 +00:00
|
|
|
from appsettings.models import AppSettings
|
2015-02-27 12:25:41 +00:00
|
|
|
from instances.models import Instance
|
|
|
|
from vrtManager.create import wvmCreate
|
|
|
|
from vrtManager import util
|
2020-04-24 16:34:29 +00:00
|
|
|
from logs.views import addlogmsg
|
2018-09-14 13:23:25 +00:00
|
|
|
from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES
|
2020-03-16 13:59:45 +00:00
|
|
|
|
2020-06-19 04:38:06 +00:00
|
|
|
|
2020-05-27 12:24:06 +00:00
|
|
|
@superuser_only
|
2019-12-13 13:47:51 +00:00
|
|
|
def create_instance_select_type(request, compute_id):
|
2020-04-24 16:34:29 +00:00
|
|
|
"""
|
|
|
|
:param request:
|
|
|
|
:param compute_id:
|
|
|
|
:return:
|
|
|
|
"""
|
2019-12-13 13:47:51 +00:00
|
|
|
conn = None
|
|
|
|
error_messages = list()
|
|
|
|
storages = list()
|
|
|
|
networks = list()
|
|
|
|
hypervisors = list()
|
|
|
|
meta_prealloc = False
|
|
|
|
compute = get_object_or_404(Compute, pk=compute_id)
|
2020-05-28 21:43:26 +00:00
|
|
|
appsettings = AppSettings.objects.all()
|
2019-12-13 13:47:51 +00:00
|
|
|
|
|
|
|
try:
|
2020-05-27 12:24:06 +00:00
|
|
|
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
|
2019-12-13 13:47:51 +00:00
|
|
|
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"]
|
2020-03-16 13:59:45 +00:00
|
|
|
hypervisors = [hpv for hpv in all_hypervisors.keys() if hpv in supported_arch]
|
2020-05-28 21:43:26 +00:00
|
|
|
default_machine = appsettings.get(key="INSTANCE_MACHINE_DEFAULT_TYPE").value
|
|
|
|
default_arch = appsettings.get(key="INSTANCE_ARCH_DEFAULT_TYPE").value
|
2019-12-13 13:47:51 +00:00
|
|
|
|
|
|
|
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")
|
|
|
|
error_messages.append(error_msg)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
conn._defineXML(xml)
|
2020-06-19 04:38:06 +00:00
|
|
|
return HttpResponseRedirect(reverse('instances:instance', args=[compute_id, name]))
|
2019-12-13 13:47:51 +00:00
|
|
|
except libvirtError as lib_err:
|
2020-03-16 13:59:45 +00:00
|
|
|
error_messages.append(lib_err)
|
2019-12-13 13:47:51 +00:00
|
|
|
|
|
|
|
except libvirtError as lib_err:
|
|
|
|
error_messages.append(lib_err)
|
|
|
|
|
|
|
|
return render(request, 'create_instance_w1.html', locals())
|
2018-11-23 12:18:32 +00:00
|
|
|
|
2020-03-16 13:59:45 +00:00
|
|
|
|
2020-05-27 12:24:06 +00:00
|
|
|
@superuser_only
|
2019-12-13 13:47:51 +00:00
|
|
|
def create_instance(request, compute_id, arch, machine):
|
2015-02-27 12:25:41 +00:00
|
|
|
"""
|
|
|
|
:param request:
|
2019-09-10 06:48:31 +00:00
|
|
|
:param compute_id:
|
2020-03-16 13:59:45 +00:00
|
|
|
:param arch:
|
|
|
|
:param machine:
|
2015-02-27 12:25:41 +00:00
|
|
|
:return:
|
|
|
|
"""
|
2015-03-03 09:34:09 +00:00
|
|
|
|
2015-02-27 12:25:41 +00:00
|
|
|
conn = None
|
2019-12-13 13:47:51 +00:00
|
|
|
error_messages = list()
|
|
|
|
storages = list()
|
|
|
|
networks = list()
|
|
|
|
hypervisors = list()
|
|
|
|
firmwares = list()
|
2015-02-27 12:25:41 +00:00
|
|
|
meta_prealloc = False
|
2015-04-02 12:39:40 +00:00
|
|
|
compute = get_object_or_404(Compute, pk=compute_id)
|
2015-02-27 12:25:41 +00:00
|
|
|
flavors = Flavor.objects.filter().order_by('id')
|
2020-05-28 21:43:26 +00:00
|
|
|
appsettings = AppSettings.objects.all()
|
2015-02-27 12:25:41 +00:00
|
|
|
|
|
|
|
try:
|
2020-05-27 12:24:06 +00:00
|
|
|
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
|
2015-02-27 12:25:41 +00:00
|
|
|
|
2020-05-28 21:43:26 +00:00
|
|
|
default_firmware = appsettings.get(key="INSTANCE_FIRMWARE_DEFAULT_TYPE").value
|
|
|
|
default_cpu_mode = appsettings.get(key="INSTANCE_CPU_DEFAULT_MODE").value
|
2015-02-27 12:25:41 +00:00
|
|
|
instances = conn.get_instances()
|
2019-12-13 13:47:51 +00:00
|
|
|
videos = conn.get_video_models(arch, machine)
|
2016-04-17 21:41:40 +00:00
|
|
|
cache_modes = sorted(conn.get_cache_modes().items())
|
2020-05-28 21:43:26 +00:00
|
|
|
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
|
2018-09-14 13:23:25 +00:00
|
|
|
listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES
|
2015-02-27 12:25:41 +00:00
|
|
|
mac_auto = util.randomMAC()
|
2019-12-13 13:47:51 +00:00
|
|
|
disk_devices = conn.get_disk_device_types(arch, machine)
|
|
|
|
disk_buses = conn.get_disk_bus_types(arch, machine)
|
2020-05-28 21:43:26 +00:00
|
|
|
default_bus = appsettings.get(key="INSTANCE_VOLUME_DEFAULT_BUS").value
|
2019-09-10 13:06:30 +00:00
|
|
|
networks = sorted(conn.get_networks())
|
|
|
|
nwfilters = conn.get_nwfilters()
|
|
|
|
storages = sorted(conn.get_storages(only_actives=True))
|
2020-05-28 21:43:26 +00:00
|
|
|
default_graphics = appsettings.get(key="QEMU_CONSOLE_DEFAULT_TYPE").value
|
2019-12-13 13:47:51 +00:00
|
|
|
|
|
|
|
dom_caps = conn.get_dom_capabilities(arch, machine)
|
|
|
|
caps = conn.get_capabilities(arch)
|
|
|
|
|
2019-12-19 10:49:41 +00:00
|
|
|
virtio_support = conn.is_supports_virtio(arch, machine)
|
2019-12-13 13:47:51 +00:00
|
|
|
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))
|
|
|
|
|
2015-02-27 12:25:41 +00:00
|
|
|
except libvirtError as lib_err:
|
|
|
|
error_messages.append(lib_err)
|
|
|
|
|
|
|
|
if conn:
|
|
|
|
if not storages:
|
2015-05-15 17:54:55 +00:00
|
|
|
msg = _("You haven't defined any storage pools")
|
2015-02-27 12:25:41 +00:00
|
|
|
error_messages.append(msg)
|
|
|
|
if not networks:
|
2015-05-15 17:54:55 +00:00
|
|
|
msg = _("You haven't defined any network pools")
|
2015-02-27 12:25:41 +00:00
|
|
|
error_messages.append(msg)
|
|
|
|
|
|
|
|
if request.method == 'POST':
|
|
|
|
if 'create_flavor' in request.POST:
|
|
|
|
form = FlavorAddForm(request.POST)
|
|
|
|
if form.is_valid():
|
|
|
|
data = form.cleaned_data
|
2020-05-27 12:24:06 +00:00
|
|
|
create_flavor = Flavor(label=data['label'], vcpu=data['vcpu'], memory=data['memory'], disk=data['disk'])
|
2015-02-27 12:25:41 +00:00
|
|
|
create_flavor.save()
|
|
|
|
return HttpResponseRedirect(request.get_full_path())
|
|
|
|
if 'delete_flavor' in request.POST:
|
|
|
|
flavor_id = request.POST.get('flavor', '')
|
|
|
|
delete_flavor = Flavor.objects.get(id=flavor_id)
|
|
|
|
delete_flavor.delete()
|
|
|
|
return HttpResponseRedirect(request.get_full_path())
|
|
|
|
if 'create' in request.POST:
|
2019-12-19 10:49:41 +00:00
|
|
|
firmware = dict()
|
2019-12-13 13:47:51 +00:00
|
|
|
volume_list = list()
|
|
|
|
is_disk_created = False
|
2018-11-23 12:18:32 +00:00
|
|
|
clone_path = ""
|
2015-02-27 12:25:41 +00:00
|
|
|
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:
|
|
|
|
msg = _("A virtual machine with this name already exists")
|
|
|
|
error_messages.append(msg)
|
2018-10-04 07:14:08 +00:00
|
|
|
if Instance.objects.filter(name__exact=data['name']):
|
2019-09-10 06:48:31 +00:00
|
|
|
messages.warning(request, _("There is an instance with same name. Are you sure?"))
|
2015-02-27 12:25:41 +00:00
|
|
|
if not error_messages:
|
|
|
|
if data['hdd_size']:
|
|
|
|
if not data['mac']:
|
|
|
|
error_msg = _("No Virtual Machine MAC has been entered")
|
|
|
|
error_messages.append(error_msg)
|
|
|
|
else:
|
|
|
|
try:
|
2020-05-28 21:43:26 +00:00
|
|
|
path = conn.create_volume(
|
2020-06-19 04:38:06 +00:00
|
|
|
data['storage'],
|
|
|
|
data['name'],
|
|
|
|
data['hdd_size'],
|
2020-05-28 21:43:26 +00:00
|
|
|
default_disk_format,
|
2020-06-19 04:38:06 +00:00
|
|
|
meta_prealloc,
|
|
|
|
default_disk_owner_uid,
|
|
|
|
default_disk_owner_gid,
|
|
|
|
)
|
2018-11-23 12:18:32 +00:00
|
|
|
volume = dict()
|
2020-05-28 21:43:26 +00:00
|
|
|
volume['device'] = 'disk'
|
2018-11-23 12:18:32 +00:00
|
|
|
volume['path'] = path
|
|
|
|
volume['type'] = conn.get_volume_type(path)
|
2020-05-28 21:43:26 +00:00
|
|
|
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
|
|
|
|
|
2018-11-23 12:18:32 +00:00
|
|
|
volume_list.append(volume)
|
2019-12-13 13:47:51 +00:00
|
|
|
is_disk_created = True
|
2020-06-19 04:38:06 +00:00
|
|
|
|
2015-02-27 12:25:41 +00:00
|
|
|
except libvirtError as lib_err:
|
2020-03-16 13:59:45 +00:00
|
|
|
error_messages.append(lib_err)
|
2015-02-27 12:25:41 +00:00
|
|
|
elif data['template']:
|
|
|
|
templ_path = conn.get_volume_path(data['template'])
|
2018-12-18 07:46:23 +00:00
|
|
|
dest_vol = conn.get_volume_path(data["name"] + ".img", data['storage'])
|
2018-09-14 13:23:25 +00:00
|
|
|
if dest_vol:
|
|
|
|
error_msg = _("Image has already exist. Please check volumes or change instance name")
|
|
|
|
error_messages.append(error_msg)
|
|
|
|
else:
|
2020-05-28 21:43:26 +00:00
|
|
|
clone_path = conn.clone_from_template(
|
2020-06-04 12:22:55 +00:00
|
|
|
data['name'],
|
|
|
|
templ_path,
|
|
|
|
data['storage'],
|
|
|
|
meta_prealloc,
|
|
|
|
default_disk_owner_uid,
|
2020-06-19 04:38:06 +00:00
|
|
|
default_disk_owner_gid,
|
|
|
|
)
|
2018-11-23 12:18:32 +00:00
|
|
|
volume = dict()
|
|
|
|
volume['path'] = clone_path
|
|
|
|
volume['type'] = conn.get_volume_type(clone_path)
|
|
|
|
volume['device'] = 'disk'
|
2020-05-28 21:43:26 +00:00
|
|
|
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
|
|
|
|
|
2018-11-23 12:18:32 +00:00
|
|
|
volume_list.append(volume)
|
2019-12-13 13:47:51 +00:00
|
|
|
is_disk_created = True
|
2015-02-27 12:25:41 +00:00
|
|
|
else:
|
|
|
|
if not data['images']:
|
|
|
|
error_msg = _("First you need to create or select an image")
|
|
|
|
error_messages.append(error_msg)
|
|
|
|
else:
|
2018-11-23 12:18:32 +00:00
|
|
|
for idx, vol in enumerate(data['images'].split(',')):
|
2015-02-27 12:25:41 +00:00
|
|
|
try:
|
|
|
|
path = conn.get_volume_path(vol)
|
2018-11-23 12:18:32 +00:00
|
|
|
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), '')
|
2020-05-28 21:43:26 +00:00
|
|
|
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
|
|
|
|
|
2018-11-23 12:18:32 +00:00
|
|
|
volume_list.append(volume)
|
2015-02-27 12:25:41 +00:00
|
|
|
except libvirtError as lib_err:
|
2020-03-16 13:59:45 +00:00
|
|
|
error_messages.append(lib_err)
|
2016-04-17 21:41:40 +00:00
|
|
|
if data['cache_mode'] not in conn.get_cache_modes():
|
|
|
|
error_msg = _("Invalid cache mode")
|
|
|
|
error_messages.append(error_msg)
|
2019-12-19 13:06:06 +00:00
|
|
|
|
2019-12-19 10:49:41 +00:00
|
|
|
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':
|
2020-05-27 12:24:06 +00:00
|
|
|
messages.warning(
|
|
|
|
request, "Changing machine type from '%s' to 'q35' "
|
|
|
|
"which is required for UEFI secure boot." % machine)
|
2019-12-19 10:49:41 +00:00
|
|
|
machine = 'q35'
|
|
|
|
firmware["secure"] = 'yes'
|
|
|
|
|
2015-02-27 12:25:41 +00:00
|
|
|
if not error_messages:
|
|
|
|
uuid = util.randomUUID()
|
|
|
|
try:
|
2020-05-27 12:24:06 +00:00
|
|
|
conn.create_instance(name=data['name'],
|
|
|
|
memory=data['memory'],
|
|
|
|
vcpu=data['vcpu'],
|
|
|
|
vcpu_mode=data['vcpu_mode'],
|
|
|
|
uuid=uuid,
|
|
|
|
arch=arch,
|
|
|
|
machine=machine,
|
2019-12-19 10:49:41 +00:00
|
|
|
firmware=firmware,
|
2020-05-28 21:43:26 +00:00
|
|
|
volumes=volume_list,
|
2020-06-19 04:38:06 +00:00
|
|
|
networks=data['networks'],
|
2020-05-27 12:24:06 +00:00
|
|
|
virtio=data['virtio'],
|
2020-06-19 04:38:06 +00:00
|
|
|
listen_addr=data["listener_addr"],
|
2020-05-27 12:24:06 +00:00
|
|
|
nwfilter=data["nwfilter"],
|
2020-06-19 04:38:06 +00:00
|
|
|
graphics=data["graphics"],
|
2020-05-27 12:24:06 +00:00
|
|
|
video=data["video"],
|
2020-06-19 04:38:06 +00:00
|
|
|
console_pass=data["console_pass"],
|
2020-05-27 12:24:06 +00:00
|
|
|
mac=data['mac'],
|
2019-12-13 13:47:51 +00:00
|
|
|
qemu_ga=data['qemu_ga'])
|
2015-03-10 09:15:36 +00:00
|
|
|
create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
|
2015-02-27 12:25:41 +00:00
|
|
|
create_instance.save()
|
2020-05-28 21:43:26 +00:00
|
|
|
msg = _("Instance is created")
|
2018-11-14 08:46:13 +00:00
|
|
|
messages.success(request, msg)
|
|
|
|
addlogmsg(request.user.username, create_instance.name, msg)
|
2020-06-19 04:38:06 +00:00
|
|
|
return HttpResponseRedirect(reverse('instances:instance', args=[compute_id, data['name']]))
|
2015-02-27 12:25:41 +00:00
|
|
|
except libvirtError as lib_err:
|
2019-09-10 06:48:31 +00:00
|
|
|
if data['hdd_size'] or len(volume_list) > 0:
|
2019-12-13 13:47:51 +00:00
|
|
|
if is_disk_created:
|
|
|
|
for vol in volume_list:
|
|
|
|
conn.delete_volume(vol['path'])
|
2015-02-27 12:25:41 +00:00
|
|
|
error_messages.append(lib_err)
|
|
|
|
conn.close()
|
2019-12-13 13:47:51 +00:00
|
|
|
return render(request, 'create_instance_w2.html', locals())
|