1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-12-24 23:25:24 +00:00

Enrich Instance Create operation: -add capability to create arm, ppc, i686, aarch64 instances, -add option to choose firmware, -add options to choose chipset. -add capability to choose volume driver options. -add new default settings

This commit is contained in:
catborise 2019-12-13 16:47:51 +03:00
parent 28b001e7cb
commit dd16a5b2d5
14 changed files with 828 additions and 211 deletions

View file

@ -72,6 +72,10 @@ Setup libvirt and KVM on server
```bash ```bash
wget -O - https://clck.ru/9V9fH | sudo sh wget -O - https://clck.ru/9V9fH | sudo sh
``` ```
Done!!
Go to http://serverip and you should see the login screen.
### Install WebVirtCloud panel (CentOS) ### Install WebVirtCloud panel (CentOS)

View file

@ -73,7 +73,7 @@
</button> </button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton{{ forloop.counter0 }}" role="menu"> <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton{{ forloop.counter0 }}" role="menu">
{% for arc in hypervisor.keys|slice:"4:" %} {% for arc in hypervisor.keys|slice:"4:" %}
<li><a href="#">{{ arc }}</a></li> <li><a tabindex="-1" href="#">{{ arc }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}

View file

@ -2,9 +2,9 @@ from django.conf.urls import url
from storages.views import storages, storage, get_volumes from storages.views import storages, storage, get_volumes
from networks.views import networks, network from networks.views import networks, network
from secrets.views import secrets from secrets.views import secrets
from create.views import create_instance from create.views import create_instance, create_instance_select_type
from interfaces.views import interfaces, interface from interfaces.views import interfaces, interface
from computes.views import overview, compute_graph, computes, get_compute_disk_buses from computes.views import overview, compute_graph, computes, get_compute_disk_buses, get_compute_machine_types, get_dom_capabilities
from instances.views import instances from instances.views import instances
from nwfilters.views import nwfilter, nwfilters from nwfilters.views import nwfilter, nwfilters
@ -23,6 +23,9 @@ urlpatterns = [
url(r'^(?P<compute_id>[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'), url(r'^(?P<compute_id>[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'),
url(r'^(?P<compute_id>[0-9]+)/nwfilter/(?P<nwfltr>[\w\-\.\:]+)/$', nwfilter, name='nwfilter'), url(r'^(?P<compute_id>[0-9]+)/nwfilter/(?P<nwfltr>[\w\-\.\:]+)/$', nwfilter, name='nwfilter'),
url(r'^(?P<compute_id>[0-9]+)/secrets/$', secrets, name='secrets'), url(r'^(?P<compute_id>[0-9]+)/secrets/$', secrets, name='secrets'),
url(r'^(?P<compute_id>[0-9]+)/create/$', create_instance, name='create_instance'), url(r'^(?P<compute_id>[0-9]+)/create/$', create_instance_select_type, name='create_instance_select_type'),
url(r'^(?P<compute_id>[0-9]+)/disk/(?P<disk>[\w\-\.\/]+)/buses$', get_compute_disk_buses, name='buses'), url(r'^(?P<compute_id>[0-9]+)/create/archs/(?P<arch>[\w\-\.\/]+)/machines/(?P<machine>[\w\-\.\/]+)$', create_instance, name='create_instance'),
url(r'^(?P<compute_id>[0-9]+)/archs/(?P<arch>[\w\-\.\/]+)/machines$', get_compute_machine_types, name='machines'),
url(r'^(?P<compute_id>[0-9]+)/archs/(?P<arch>[\w\-\.\/]+)/machines/(?P<machine>[\w\-\.\/]+)/disks/(?P<disk>[\w\-\.\/]+)/buses$', get_compute_disk_buses, name='buses'),
url(r'^(?P<compute_id>[0-9]+)/archs/(?P<arch>[\w\-\.\/]+)/machines/(?P<machine>[\w\-\.\/]+)/capabilities$', get_dom_capabilities, name='domcaps'),
] ]

View file

@ -155,7 +155,7 @@ def overview(request, compute_id):
compute.password, compute.password,
compute.type) compute.type)
hostname, host_arch, host_memory, logical_cpu, model_cpu, uri_conn = conn.get_node_info() hostname, host_arch, host_memory, logical_cpu, model_cpu, uri_conn = conn.get_node_info()
hypervisor = conn.hypervisor_type() hypervisor = conn.get_hypervisors_domain_types()
mem_usage = conn.get_memory_usage() mem_usage = conn.get_memory_usage()
emulator = conn.get_emulator(host_arch) emulator = conn.get_emulator(host_arch)
version = conn.get_version() version = conn.get_version()
@ -198,8 +198,8 @@ def compute_graph(request, compute_id):
@login_required @login_required
def get_compute_disk_buses(request, compute_id, disk): def get_compute_disk_buses(request, compute_id, arch, machine, disk):
data = {} data = dict()
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
try: try:
conn = wvmConnect(compute.hostname, conn = wvmConnect(compute.hostname,
@ -207,7 +207,7 @@ def get_compute_disk_buses(request, compute_id, disk):
compute.password, compute.password,
compute.type) compute.type)
disk_device_types = conn.get_disk_device_types() disk_device_types = conn.get_disk_device_types(arch, machine)
if disk in disk_device_types: if disk in disk_device_types:
if disk == 'disk': if disk == 'disk':
@ -223,3 +223,51 @@ def get_compute_disk_buses(request, compute_id, disk):
return HttpResponse(json.dumps(data)) return HttpResponse(json.dumps(data))
@login_required
def get_compute_machine_types(request, compute_id, arch):
data = dict()
try:
compute = get_object_or_404(Compute, pk=compute_id)
conn = wvmConnect(compute.hostname,
compute.login,
compute.password,
compute.type)
data['machines'] = conn.get_machine_types(arch)
except libvirtError:
pass
return HttpResponse(json.dumps(data))
@login_required
def get_compute_video_models(request, compute_id, arch, machine):
data = dict()
try:
compute = get_object_or_404(Compute, pk=compute_id)
conn = wvmConnect(compute.hostname,
compute.login,
compute.password,
compute.type)
data['videos'] = conn.get_video_models(arch, machine)
except libvirtError:
pass
return HttpResponse(json.dumps(data))
@login_required
def get_dom_capabilities(request, compute_id, arch, machine):
data = dict()
try:
compute = get_object_or_404(Compute, pk=compute_id)
conn = wvmConnect(compute.hostname,
compute.login,
compute.password,
compute.type)
data['videos'] = conn.get_disk_device_types(arch, machine)
data['bus'] = conn.get_disk_device_types(arch, machine)
except libvirtError:
pass
return HttpResponse(json.dumps(data))

View file

@ -33,8 +33,9 @@ class FlavorAddForm(forms.Form):
class NewVMForm(forms.Form): class NewVMForm(forms.Form):
name = forms.CharField(error_messages={'required': _('No Virtual Machine name has been entered')}, name = forms.CharField(error_messages={'required': _('No Virtual Machine name has been entered')},
max_length=64) max_length=64)
firmware = forms.CharField(max_length=50, required=False)
vcpu = forms.IntegerField(error_messages={'required': _('No VCPU has been entered')}) vcpu = forms.IntegerField(error_messages={'required': _('No VCPU has been entered')})
host_model = forms.BooleanField(required=False) vcpu_mode = forms.CharField(max_length=20, required=False)
disk = forms.IntegerField(required=False) disk = forms.IntegerField(required=False)
memory = forms.IntegerField(error_messages={'required': _('No RAM size has been entered')}) memory = forms.IntegerField(error_messages={'required': _('No RAM size has been entered')})
networks = forms.CharField(error_messages={'required': _('No Network pool has been choosen')}) networks = forms.CharField(error_messages={'required': _('No Network pool has been choosen')})
@ -48,8 +49,9 @@ class NewVMForm(forms.Form):
virtio = forms.BooleanField(required=False) virtio = forms.BooleanField(required=False)
qemu_ga = forms.BooleanField(required=False) qemu_ga = forms.BooleanField(required=False)
mac = forms.CharField(required=False) mac = forms.CharField(required=False)
console_pass = forms.CharField(required=False,empty_value="", widget=forms.PasswordInput()) console_pass = forms.CharField(required=False, empty_value="", widget=forms.PasswordInput())
video = forms.CharField(error_messages={'required': _('Please select a graphic display')}) graphics = forms.CharField(error_messages={'required': _('Please select a graphics type')})
video = forms.CharField(error_messages={'required': _('Please select a video driver')})
listener_addr = forms.ChoiceField(required=True, widget=forms.RadioSelect, choices=QEMU_CONSOLE_LISTEN_ADDRESSES) listener_addr = forms.ChoiceField(required=True, widget=forms.RadioSelect, choices=QEMU_CONSOLE_LISTEN_ADDRESSES)
def clean_name(self): def clean_name(self):

View file

@ -0,0 +1,151 @@
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block title %}{% trans "Create new instance - Select Type" %}{% endblock %}
{% block content %}
<!-- Page Heading -->
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">{% trans "New instance on" %} {{ compute.name }}</h1>
</div>
</div>
<!-- /.row -->
{% include 'errors_block.html' %}
{% include 'pleasewaitdialog.html' %}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<div class="row" id="max-width-page">
<div class="col-lg-12">
<div role="tabpanel">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#select_architecture" aria-controls="flavor" role="tab" data-toggle="tab">
{% trans "Architecture" %}
</a>
</li>
<li role="presentation">
<a href="#addFromXML" aria-controls="addFromXML" role="tab" data-toggle="tab">
{% trans "XML" %}
</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="select_architecture">
<div class="well">
<div class="center-block">
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Architecture" %}</label>
<div class="col-sm-6">
<select class="form-control" id="select_archs" name="archs" onchange="get_machine_types({{ compute_id }}, value);">
{% for hpv in hypervisors %}
<option value="{{ hpv }}" {% if hpv == default_arch %}selected{% endif %}>{{ hpv }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Chipset" %}</label>
<div class="col-sm-6">
<select class="form-control" id="select_chipset" name="chipset">
<!-- fill with script -->
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-6 col-lg-offset-3">
<button class="btn btn-block btn-primary" type="button" name="create_instance" onclick="goto_create()">
{% trans "Next >" %}
</button>
</div>
</div>
</form>
</div>
</div>
<div class="clearfix"></div>
</div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="addFromXML">
<div class="well">
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
<div class="col-sm-12" id="xmlheight">
<input type="hidden" name="dom_xml"/>
<textarea id="editor"></textarea>
</div>
<button type="submit" class="btn btn-primary" name="create_xml" onclick="showPleaseWaitDialog()">
{% trans "Create" %}
</button>
</form>
</div>
<div class="clearfix"/>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block script %}
<script>
$(document).ready(function () {
let arch = $("#select_archs").val();
get_machine_types({{ compute_id }}, arch);
});
function get_machine_types(compute_id, arch) {
get_machine_type_url = "/computes/" + compute_id + "/archs/" + arch + "/machines";
$.getJSON(get_machine_type_url, function (data) {
$("#select_chipset").find('option').remove();
$("#select_archs").val(arch);
$.each(data['machines'], function(i, item) {
if (item == '{{ default_machine }}') {
var selected = 'selected';
}else{
var selected = '';
}
$("#select_chipset").append('<option value="' + item + '"' + selected +'>' + item + '</option>');
});
});
}
</script>
<script src="{% static "js/ace.js" %}"></script>
<script>
var editor = ace.edit("editor");
editor.getSession().setMode("ace/mode/xml");
var input = $('input[name="dom_xml"]');
editor.getSession().on("change",function () {
input.val(editor.getSession().getValue());
})
</script>
{% if request.user.is_superuser %}
<script>
function goto_create() {
let compute = '{{ compute.id }}';
let arch = $("#select_archs").val();
let machine = $("#select_chipset").val();
create_machine_url = "/computes/" + compute + "/create/archs/" + arch + "/machines/" + machine;
{#url = "{% url 'create_instance' compute.id 'x86_64' 'pc' %}".replace(/x86_64/, arch).replace(/pc/, machine);#}
window.location.href = create_machine_url;
}
</script>
{% endif %}
{% endblock %}

View file

@ -9,7 +9,9 @@
<!-- Page Heading --> <!-- Page Heading -->
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
<h1 class="page-header">{% trans "New instance on" %} {{ compute.name }}</h1> <h1 class="page-header">
{% trans "New instance on" %} {{ compute.name }}
</h1>
</div> </div>
</div> </div>
<!-- /.row --> <!-- /.row -->
@ -37,6 +39,11 @@
<div role="tabpanel"> <div role="tabpanel">
<!-- Nav tabs --> <!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist"> <ul class="nav nav-tabs" role="tablist">
<li role="presentation">
<a class="pull-right" href="#" role="tab" data-toggle="tab" onclick="goto_compute()">
<span class="glyphicon glyphicon-arrow-left"></span>
</a>
</li>
<li role="presentation" class="active"> <li role="presentation" class="active">
<a href="#flavor" aria-controls="flavor" role="tab" data-toggle="tab"> <a href="#flavor" aria-controls="flavor" role="tab" data-toggle="tab">
{% trans "Flavor" %} {% trans "Flavor" %}
@ -52,11 +59,6 @@
{% trans "Template" %} {% trans "Template" %}
</a> </a>
</li> </li>
<li role="presentation">
<a href="#addFromXML" aria-controls="addFromXML" role="tab" data-toggle="tab">
{% trans "XML" %}
</a>
</li>
</ul> </ul>
<!-- Tab panes --> <!-- Tab panes -->
<div class="tab-content"> <div class="tab-content">
@ -112,9 +114,43 @@
<input type="hidden" name="hdd_size" value="{{ flavor.disk }}"> <input type="hidden" name="hdd_size" value="{{ flavor.disk }}">
</div> </div>
</div> </div>
{% if firmwares %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Firmware" %}</label>
<div class="col-sm-6">
<select class="form-control" id="select_firmware" name="firmware">
{% for frm in firmwares %}
<option value="{{ frm }}" {% if frm == default_firmware %}selected{% endif %}>{{ frm }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
{% if dom_caps.cpu_modes %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "VCPU Config" %}</label>
<div class="col-sm-6">
<select id="vcpu_mode" name="vcpu_mode" class="form-control">
<option value=""> {% trans 'no-mode' %}</option>
{% for mode in dom_caps.cpu_modes %}
{% if mode == 'custom' %}
<optgroup label="Custom CPU Models">
{% for model in dom_caps.cpu_custom_models %}
<option value="{{ model }}"> {% trans model %}</option>
{% endfor %}
</optgroup>
{% else %}
<option value="{{ mode }}" {% ifequal mode default_cpu_mode %}selected {% endifequal %}>
{% trans mode %}
</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Storage" %}</label> <label class="col-sm-3 control-label">{% trans "Storage" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="hidden" name="cache_mode" value="default"> <input type="hidden" name="cache_mode" value="default">
<select name="storage" class="form-control"> <select name="storage" class="form-control">
@ -166,6 +202,18 @@
<input type="text" class="form-control" name="mac" maxlength="17" value="{{ mac_auto }}" required pattern="[a-zA-Z0-9:]+"> <input type="text" class="form-control" name="mac" maxlength="17" value="{{ mac_auto }}" required pattern="[a-zA-Z0-9:]+">
</div> </div>
</div> </div>
{% if dom_caps.graphics_support == 'yes' %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Graphics" %}</label>
<div class="col-sm-6">
<select name="graphics" class="form-control">
{% for graphics in dom_caps.graphics_types %}
<option value="{{ graphics }}" {% if default_graphics == graphics %}selected{% endif %}>{{ graphics }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Video" %}</label> <label class="col-sm-3 control-label">{% trans "Video" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
@ -196,13 +244,6 @@
</select> </select>
</div> </div>
</div> </div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Host-Model" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="host_model" value="true" checked>
</div>
<label class="col-lg-1 control-label">{% trans "CPU" %}</label>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Guest Agent" %}</label> <label class="col-sm-3 control-label">{% trans "Guest Agent" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
@ -258,19 +299,47 @@
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="64" required pattern="[a-zA-Z0-9\.\-_]+"> <input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="64" required pattern="[a-zA-Z0-9\.\-_]+">
</div> </div>
</div> </div>
{% if firmwares %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Firmware" %}</label>
<div class="col-sm-7">
<select class="form-control" id="select_firmware" name="firmware">
{% for frm in firmwares %}
<option value="{{ frm }}" {% if frm == default_firmware %}selected{% endif %}>{{ frm }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "VCPU" %}</label> <label class="col-sm-3 control-label">{% trans "VCPU" %}</label>
<div class="col-sm-7"> <div class="col-sm-7">
<input type="text" class="form-control" name="vcpu" value="1" maxlength="2" required pattern="[0-9]"> <input type="text" class="form-control" name="vcpu" value="1" maxlength="2" required pattern="[0-9]">
</div> </div>
</div> </div>
<div class="form-group"> {% if dom_caps.cpu_modes %}
<label class="col-sm-3 control-label">{% trans "Host-Model" %}</label> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "VCPU Config" %}</label>
<div class="col-sm-7"> <div class="col-sm-7">
<input type="checkbox" name="host_model" value="true" checked> <select id="vcpu_mode" name="vcpu_mode" class="form-control">
<option value=""> {% trans 'no-mode' %}</option>
{% for mode in dom_caps.cpu_modes %}
{% if mode == 'custom' %}
<optgroup label="Custom CPU Models">
{% for model in dom_caps.cpu_custom_models %}
<option value="{{ model }}"> {% trans model %}</option>
{% endfor %}
</optgroup>
{% else %}
<option value="{{ mode }}" {% ifequal mode default_cpu_mode %}selected {% endifequal %}>
{% trans mode %}
</option>
{% endif %}
{% endfor %}
</select>
</div> </div>
<label class="col-sm-1 control-label">{% trans "CPU" %}</label>
</div> </div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "RAM" %}</label> <label class="col-sm-3 control-label">{% trans "RAM" %}</label>
<div class="col-sm-7"> <div class="col-sm-7">
@ -351,6 +420,18 @@
</select> </select>
</div> </div>
</div> </div>
{% if dom_caps.graphics_support == 'yes' %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Graphics" %}</label>
<div class="col-sm-7">
<select name="graphics" class="form-control">
{% for graphics in dom_caps.graphics_types %}
<option value="{{ graphics }}" {% if default_graphics == graphics %}selected{% endif %}>{{ graphics }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Video" %}</label> <label class="col-sm-3 control-label">{% trans "Video" %}</label>
<div class="col-sm-7"> <div class="col-sm-7">
@ -393,15 +474,18 @@
<input type="checkbox" name="virtio" value="true" checked> <input type="checkbox" name="virtio" value="true" checked>
</div> </div>
</div> </div>
<div class="form-group">
<div class="col-sm-7 col-sm-offset-3">
{% if storages %} {% if storages %}
<button type="submit" class="btn btn-primary" name="create" formnovalidate onclick="showPleaseWaitDialog()" value="1"> <button type="submit" class="btn btn-block btn-primary" name="create" formnovalidate onclick="showPleaseWaitDialog()" value="1">
{% trans "Create" %} {% trans "Create" %}
</button> </button>
{% else %} {% else %}
<button class="btn btn-primary disabled"> <button class="btn btn-block btn-primary disabled">
{% trans "Create" %} {% trans "Create" %}
</button> </button>
{% endif %} {% endif %}
</div></div>
</form> </form>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -416,6 +500,18 @@
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="64" required pattern="[a-zA-Z0-9\.\-_]+"> <input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="64" required pattern="[a-zA-Z0-9\.\-_]+">
</div> </div>
</div> </div>
{% if firmwares %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Firmware" %}</label>
<div class="col-sm-7">
<select class="form-control" id="select_firmware" name="firmware">
{% for frm in firmwares %}
<option value="{{ frm }}" {% if frm == default_firmware %}selected{% endif %}>{{ frm }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "VCPU" %}</label> <label class="col-sm-3 control-label">{% trans "VCPU" %}</label>
<div class="col-sm-7"> <div class="col-sm-7">
@ -423,11 +519,25 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Host-Model" %}</label> <label class="col-sm-3 control-label">{% trans "VCPU Config" %}</label>
<div class="col-sm-7"> <div class="col-sm-7">
<input type="checkbox" name="host_model" value="true" checked> <select id="vcpu_mode" name="vcpu_mode" class="form-control">
<option value=""> {% trans 'no-mode' %}</option>
{% for mode in dom_caps.cpu_modes %}
{% if mode == 'custom' %}
<optgroup label="Custom CPU Models">
{% for model in dom_caps.cpu_custom_models %}
<option value="{{ model }}"> {% trans model %}</option>
{% endfor %}
</optgroup>
{% else %}
<option value="{{ mode }}" {% ifequal mode default_cpu_mode %}selected {% endifequal %}>
{% trans mode %}
</option>
{% endif %}
{% endfor %}
</select>
</div> </div>
<label class="col-sm-1 control-label">{% trans "CPU" %}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "RAM" %}</label> <label class="col-sm-3 control-label">{% trans "RAM" %}</label>
@ -437,7 +547,7 @@
<label class="col-sm-1 control-label">{% trans "MB" %}</label> <label class="col-sm-1 control-label">{% trans "MB" %}</label>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "HDD" %}</label> <label class="col-sm-3 control-label">{% trans "Template Disk" %}</label>
<input id="images" name="images" type="hidden" value=""/> <input id="images" name="images" type="hidden" value=""/>
<div class="col-sm-3"> <div class="col-sm-3">
<select class="form-control" onchange="get_template_vols({{ compute_id }}, value);"> <select class="form-control" onchange="get_template_vols({{ compute_id }}, value);">
@ -510,6 +620,18 @@
</select> </select>
</div> </div>
</div> </div>
{% if dom_caps.graphics_support == 'yes' %}
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "Graphics" %}</label>
<div class="col-sm-7">
<select name="graphics" class="form-control">
{% for graphics in dom_caps.graphics_types %}
<option value="{{ graphics }}" {% if default_graphics == graphics %}selected{% endif %}>{{ graphics }}</option>
{% endfor %}
</select>
</div>
</div>
{% endif %}
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Video" %}</label> <label class="col-sm-3 control-label">{% trans "Video" %}</label>
<div class="col-sm-7"> <div class="col-sm-7">
@ -552,31 +674,19 @@
<input type="checkbox" name="virtio" value="true" checked> <input type="checkbox" name="virtio" value="true" checked>
</div> </div>
</div> </div>
<div class="form-group">
{% if storages %} <div class="col-sm-7 col-sm-offset-3">
<button type="submit" class="btn btn-primary" name="create" value="1" formnovalidate onclick="showPleaseWaitDialog()"> {% if storages %}
{% trans "Create" %} <button type="submit" class="btn btn-block btn-primary" name="create" value="1" formnovalidate onclick="showPleaseWaitDialog()">
</button> {% trans "Create" %}
{% else %} </button>
<button class="btn btn-primary disabled"> {% else %}
{% trans "Create" %} <button class="btn btn-primary disabled">
</button> {% trans "Create" %}
{% endif %} </button>
</form> {% endif %}
</div> </div>
<div class="clearfix"></div>
</div>
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="addFromXML">
<div class="well">
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
<div class="col-sm-12" id="xmlheight">
<input type="hidden" name="dom_xml"/>
<textarea id="editor"></textarea>
</div> </div>
<button type="submit" class="btn btn-primary" name="create_xml" onclick="showPleaseWaitDialog()">
{% trans "Create" %}
</button>
</form> </form>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -589,7 +699,7 @@
<script src="{% static "js/bootstrap-multiselect.js" %}"></script> <script src="{% static "js/bootstrap-multiselect.js" %}"></script>
<script> <script>
function toggleValue(string, updated_value, checked) { function toggleValue(string, updated_value, checked) {
var result = ''; let result = '';
if (checked) { if (checked) {
result = string; result = string;
if (result != '') result += ','; if (result != '') result += ',';
@ -620,15 +730,15 @@
return ''; return '';
}, },
onChange: function (element, checked) { onChange: function (element, checked) {
var input_value = toggleValue($('#images').val(), element.val(), checked); let input_value = toggleValue($('#images').val(), element.val(), checked);
$('#images').val(input_value); $('#images').val(input_value);
var selected_list_html = ''; let selected_list_html = '';
var counter = 0; let counter = 0;
if (input_value != '') { if (input_value != '') {
$('#disk_list_div').show(); $('#disk_list_div').show();
$.each(input_value.split(','), function (index, value) { $.each(input_value.split(','), function (index, value) {
var li = '<li>hdd' + counter + ' - ' + let li = '<li>hdd' + counter + ' - ' +
'<select name="device' + counter + '" class="image-format" onchange="get_disk_bus_choices({{ compute_id }},' + counter + ', value);">' + '<select name="device' + counter + '" class="image-format" onchange="get_disk_bus_choices({{ compute_id }},' + counter + ', value);">' +
'{% for dev in disk_devices %}' + '{% for dev in disk_devices %}' +
'<option value=' + '"{{ dev }}">' + '{% trans dev %}</option>' + '<option value=' + '"{{ dev }}">' + '{% trans dev %}</option>' +
@ -668,13 +778,13 @@
return '100%'; return '100%';
}, },
onChange: function (element, checked) { onChange: function (element, checked) {
var input_value = toggleValue($('#networks').val(), element.val(), checked); let input_value = toggleValue($('#networks').val(), element.val(), checked);
$('#networks').val(input_value); $('#networks').val(input_value);
var selected_list_html = ''; let selected_list_html = '';
var counter = 0; let counter = 0;
if (input_value != '') { if (input_value != '') {
$.each(input_value.split(','), function (index, value) { $.each(input_value.split(','), function (index, value) {
var li = '<li>eth' + counter + let li = '<li>eth' + counter +
' -> ' + value + ' ' + ' -> ' + value + ' ' +
'<a class="btn-link pull-right" onclick="javascript:$(\'#network-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a></a></li>'; '<a class="btn-link pull-right" onclick="javascript:$(\'#network-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a></a></li>';
selected_list_html += li; selected_list_html += li;
@ -686,6 +796,8 @@
}); });
}); });
$("id[vcpu_mode]").multiselect();
function get_cust_vols(compute_id, pool) { function get_cust_vols(compute_id, pool) {
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes"; get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
$.getJSON(get_vol_url, function (data) { $.getJSON(get_vol_url, function (data) {
@ -708,11 +820,12 @@
$("#template").removeAttr("disabled"); $("#template").removeAttr("disabled");
$("#storage").val(pool).change(); $("#storage").val(pool).change();
$("#storage").removeAttr("disabled"); $("#storage").removeAttr("disabled");
} }
function get_disk_bus_choices(compute_id, dev_idx, disk_type){ function get_disk_bus_choices(compute_id, dev_idx, disk_type){
get_diskBus_url = "/computes/" + compute_id + "/disk/" + disk_type + "/buses"; let arch = $('select[name="arch"]').val();
let machine = $("select[id='machine-control']").val();
get_diskBus_url = "/computes/" + compute_id + "/archs/" + arch + "/machines/" + machine + "/disks/" + disk_type + "/buses";
$.getJSON(get_diskBus_url, function (data) { $.getJSON(get_diskBus_url, function (data) {
$("#bus" + dev_idx).find('option').remove(); $("#bus" + dev_idx).find('option').remove();
$.each(data['bus'], function(i, item) { $.each(data['bus'], function(i, item) {
@ -721,15 +834,12 @@
}); });
} }
</script> </script>
{% if request.user.is_superuser %}
<script src="{% static "js/ace.js" %}"></script> <script>
<script> function goto_compute() {
var editor = ace.edit("editor"); let compute = {{ compute.id }}
editor.getSession().setMode("ace/mode/xml"); window.location.href = "{% url 'create_instance_select_type' 1 %}".replace(1, compute);
}
var input = $('input[name="dom_xml"]'); </script>
editor.getSession().on("change",function () { {% endif %}
input.val(editor.getSession().getValue());
})
</script>
{% endblock %} {% endblock %}

View file

@ -13,25 +13,76 @@ from libvirt import libvirtError
from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_CACHE from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_CACHE
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_BUS 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 django.contrib import messages from django.contrib import messages
from logs.views import addlogmsg from logs.views import addlogmsg
@login_required @login_required
def create_instance(request, compute_id): def create_instance_select_type(request, compute_id):
"""
:param request:
:param compute_id:
:return:
"""
if not request.user.is_superuser: if not request.user.is_superuser:
return HttpResponseRedirect(reverse('index')) return HttpResponseRedirect(reverse('index'))
conn = None conn = None
error_messages = [] error_messages = list()
storages = [] storages = list()
networks = [] networks = list()
hypervisors = list()
meta_prealloc = False
compute = get_object_or_404(Compute, pk=compute_id)
try:
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 = INSTANCE_MACHINE_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")
error_messages.append(error_msg)
else:
try:
conn._defineXML(xml)
return HttpResponseRedirect(reverse('instance', args=[compute_id, name]))
except libvirtError as lib_err:
error_messages.append(lib_err.message)
except libvirtError as lib_err:
error_messages.append(lib_err)
return render(request, 'create_instance_w1.html', locals())
@login_required
def create_instance(request, compute_id, arch, machine):
"""
:param request:
:param compute_id:
:return:
"""
if not request.user.is_superuser:
return HttpResponseRedirect(reverse('index'))
conn = None
error_messages = list()
storages = list()
networks = list()
hypervisors = list()
firmwares = list()
meta_prealloc = False meta_prealloc = False
compute = get_object_or_404(Compute, pk=compute_id) compute = get_object_or_404(Compute, pk=compute_id)
flavors = Flavor.objects.filter().order_by('id') flavors = Flavor.objects.filter().order_by('id')
@ -42,18 +93,34 @@ def create_instance(request, compute_id):
compute.password, compute.password,
compute.type) compute.type)
default_cpu_mode = INSTANCE_CPU_DEFAULT_MODE
instances = conn.get_instances() instances = conn.get_instances()
videos = conn.get_video_models() videos = conn.get_video_models(arch, machine)
cache_modes = sorted(conn.get_cache_modes().items()) cache_modes = sorted(conn.get_cache_modes().items())
default_cache = INSTANCE_VOLUME_DEFAULT_CACHE default_cache = INSTANCE_VOLUME_DEFAULT_CACHE
listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES
mac_auto = util.randomMAC() mac_auto = util.randomMAC()
disk_devices = conn.get_disk_device_types() disk_devices = conn.get_disk_device_types(arch, machine)
disk_buses = conn.get_disk_bus_types() disk_buses = conn.get_disk_bus_types(arch, machine)
default_bus = INSTANCE_VOLUME_DEFAULT_BUS default_bus = INSTANCE_VOLUME_DEFAULT_BUS
networks = sorted(conn.get_networks()) networks = sorted(conn.get_networks())
nwfilters = conn.get_nwfilters() nwfilters = conn.get_nwfilters()
storages = sorted(conn.get_storages(only_actives=True)) storages = sorted(conn.get_storages(only_actives=True))
default_graphics = QEMU_CONSOLE_DEFAULT_TYPE
dom_caps = conn.get_dom_capabilities(arch, machine)
caps = conn.get_capabilities(arch)
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))
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err) error_messages.append(lib_err)
@ -81,24 +148,9 @@ def create_instance(request, compute_id):
delete_flavor = Flavor.objects.get(id=flavor_id) delete_flavor = Flavor.objects.get(id=flavor_id)
delete_flavor.delete() delete_flavor.delete()
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
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)
return HttpResponseRedirect(reverse('instance', args=[compute_id, name]))
except libvirtError as lib_err:
error_messages.append(lib_err.message)
if 'create' in request.POST: if 'create' in request.POST:
volume_list = [] volume_list = list()
is_disk_created = False
clone_path = "" clone_path = ""
form = NewVMForm(request.POST) form = NewVMForm(request.POST)
if form.is_valid(): if form.is_valid():
@ -124,8 +176,9 @@ def create_instance(request, compute_id):
volume['path'] = path volume['path'] = path
volume['type'] = conn.get_volume_type(path) volume['type'] = conn.get_volume_type(path)
volume['device'] = 'disk' volume['device'] = 'disk'
volume['bus'] = 'virtio' volume['bus'] = INSTANCE_VOLUME_DEFAULT_BUS
volume_list.append(volume) volume_list.append(volume)
is_disk_created = True
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err.message) error_messages.append(lib_err.message)
elif data['template']: elif data['template']:
@ -140,8 +193,9 @@ def create_instance(request, compute_id):
volume['path'] = clone_path volume['path'] = clone_path
volume['type'] = conn.get_volume_type(clone_path) volume['type'] = conn.get_volume_type(clone_path)
volume['device'] = 'disk' volume['device'] = 'disk'
volume['bus'] = 'virtio' volume['bus'] = INSTANCE_VOLUME_DEFAULT_BUS
volume_list.append(volume) volume_list.append(volume)
is_disk_created = True
else: else:
if not data['images']: if not data['images']:
error_msg = _("First you need to create or select an image") error_msg = _("First you need to create or select an image")
@ -164,10 +218,15 @@ def create_instance(request, compute_id):
if not error_messages: if not error_messages:
uuid = util.randomUUID() uuid = util.randomUUID()
try: try:
conn.create_instance(data['name'], data['memory'], data['vcpu'], data['host_model'], conn.create_instance(name=data['name'], memory=data['memory'], vcpu=data['vcpu'],
uuid, volume_list, data['cache_mode'], data['networks'], data['virtio'], vcpu_mode=data['vcpu_mode'], uuid=uuid, arch=arch, machine=machine,
data["listener_addr"], data["nwfilter"], data["video"], data["console_pass"], firmware=data["firmware"],
data['mac'], data['qemu_ga']) images=volume_list, cache_mode=data['cache_mode'],
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 = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
create_instance.save() create_instance.save()
msg = _("Instance is created.") msg = _("Instance is created.")
@ -176,8 +235,9 @@ def create_instance(request, compute_id):
return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']])) return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']]))
except libvirtError as lib_err: except libvirtError as lib_err:
if data['hdd_size'] or len(volume_list) > 0: if data['hdd_size'] or len(volume_list) > 0:
for vol in volume_list: if is_disk_created:
conn.delete_volume(vol['path']) for vol in volume_list:
conn.delete_volume(vol['path'])
error_messages.append(lib_err) error_messages.append(lib_err)
conn.close() conn.close()
return render(request, 'create_instance.html', locals()) return render(request, 'create_instance_w2.html', locals())

View file

@ -176,8 +176,9 @@
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<script> <script>
function goto_compute() { function goto_compute() {
var compute = $("#compute_select").val(); let compute = $("#compute_select").val();
window.location.href = "{% url 'create_instance' 1 %}".replace(1, compute); {#window.location.href = "{% url 'create_instance' 1 %}".replace(1, compute);#}
window.location.href = "{% url 'create_instance_select_type' 1 %}".replace(1, compute);
} }
</script> </script>
{% endif %} {% endif %}

View file

@ -10,7 +10,7 @@
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-lg-12">
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<a href="{% url 'create_instance' compute.id %}" type="button" class="btn btn-success btn-header pull-right" data-toggle="modal"> <a href="{% url 'create_instance_select_type' compute.id %}" type="button" class="btn btn-success btn-header pull-right" data-toggle="modal">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
</a> </a>
{% endif %} {% endif %}
@ -161,7 +161,7 @@
<script src="{% static "js/sortable.min.js" %}"></script> <script src="{% static "js/sortable.min.js" %}"></script>
<script> <script>
function open_console(uuid) { function open_console(uuid) {
window.open("{% url 'console' %}?token=" + uuid, "", "width=850,height=485"); window.open("{% url 'console' %}?token=" + uuid, "", "width=850,height=685");
} }
</script> </script>
<script> <script>
@ -189,12 +189,4 @@
window.location = "/instances/" + compute + "/" + instance + "/#clone"; window.location = "/instances/" + compute + "/" + instance + "/#clone";
} }
</script> </script>
{% if request.user.is_superuser %}
<script>
function goto_compute() {
var compute = $("#compute_select").val();
window.location.href = "{% url 'create_instance' 1 %}".replace(1, compute);
}
</script>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -22,7 +22,7 @@ from vrtManager.connection import connection_manager
from vrtManager.create import wvmCreate from vrtManager.create import wvmCreate
from vrtManager.storage import wvmStorage from vrtManager.storage import wvmStorage
from vrtManager.util import randomPasswd from vrtManager.util import randomPasswd
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM
from logs.views import addlogmsg from logs.views import addlogmsg
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
@ -265,6 +265,8 @@ def instance(request, compute_id, vname):
autostart = conn.get_autostart() autostart = conn.get_autostart()
bootmenu = conn.get_bootmenu() bootmenu = conn.get_bootmenu()
boot_order = conn.get_bootorder() boot_order = conn.get_bootorder()
arch = conn.get_arch()
machine = conn.get_machine_type()
vcpu = conn.get_vcpu() vcpu = conn.get_vcpu()
cur_vcpu = conn.get_cur_vcpu() cur_vcpu = conn.get_cur_vcpu()
vcpus = conn.get_vcpus() vcpus = conn.get_vcpus()
@ -288,6 +290,7 @@ def instance(request, compute_id, vname):
insort(memory_range, memory) insort(memory_range, memory)
if cur_memory not in memory_range: if cur_memory not in memory_range:
insort(memory_range, cur_memory) insort(memory_range, cur_memory)
nvram = conn.get_nvram()
telnet_port = conn.get_telnet_port() telnet_port = conn.get_telnet_port()
console_type = conn.get_console_type() console_type = conn.get_console_type()
console_port = conn.get_console_port() console_port = conn.get_console_port()
@ -330,8 +333,8 @@ def instance(request, compute_id, vname):
# Host resources # Host resources
vcpu_host = len(vcpu_range) vcpu_host = len(vcpu_range)
memory_host = conn.get_max_memory() memory_host = conn.get_max_memory()
bus_host = conn.get_disk_bus_types() bus_host = conn.get_disk_bus_types(arch, machine)
videos_host = conn.get_video_models() videos_host = conn.get_video_models(arch, machine)
networks_host = sorted(conn.get_networks()) networks_host = sorted(conn.get_networks())
interfaces_host = sorted(conn.get_ifaces()) interfaces_host = sorted(conn.get_ifaces())
nwfilters_host = conn.get_nwfilters() nwfilters_host = conn.get_nwfilters()
@ -374,7 +377,11 @@ def instance(request, compute_id, vname):
for snap in snapshots: for snap in snapshots:
conn.snapshot_delete(snap['name']) conn.snapshot_delete(snap['name'])
conn.delete_all_disks() conn.delete_all_disks()
conn.delete()
if request.POST.get('delete_nvram', ''):
conn.delete(VIR_DOMAIN_UNDEFINE_NVRAM)
else:
conn.delete(VIR_DOMAIN_UNDEFINE_KEEP_NVRAM)
instance = Instance.objects.get(compute_id=compute_id, name=vname) instance = Instance.objects.get(compute_id=compute_id, name=vname)
instance_name = instance.name instance_name = instance.name

View file

@ -1,6 +1,7 @@
import libvirt import libvirt
import threading import threading
import socket import socket
import re
from vrtManager import util from vrtManager import util
from vrtManager.rwlock import ReadWriteLock from vrtManager.rwlock import ReadWriteLock
from django.conf import settings from django.conf import settings
@ -344,15 +345,88 @@ class wvmConnect(object):
"""Return xml capabilities""" """Return xml capabilities"""
return self.wvm.getCapabilities() return self.wvm.getCapabilities()
def get_dom_cap_xml(self): def get_dom_cap_xml(self, arch, machine):
""" Return domcapabilities xml""" """ Return domain capabilities xml"""
arch = self.wvm.getInfo()[0]
machine = self.get_machines(arch)
emulatorbin = self.get_emulator(arch) emulatorbin = self.get_emulator(arch)
virttype = self.hypervisor_type()[arch][0] virttype = self.get_hypervisors_domain_types()[arch][0]
machine_types = self.get_machine_types(arch)
if not machine or machine not in machine_types:
machine = 'pc' if 'pc' in machine_types else machine_types[0]
return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype) return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype)
def get_capabilities(self, arch):
""" Host Capabilities for specified architecture """
def guests(ctx):
result = dict()
for arch_el in ctx.xpath("/capabilities/guest/arch[@name='{}']".format(arch)):
result["wordsize"] = arch_el.find("wordsize").text
result["emulator"] = arch_el.find("emulator").text
result["domain"] = [v for v in arch_el.xpath("domain/@type")]
result["machines"] = []
for m in arch_el.xpath("machine"):
result["machines"].append({"machine": m.text,
"max_cpu": m.get("maxCpus"),
"canonical": m.get("canonical")})
guest_el = arch_el.getparent()
for f in guest_el.xpath("features"):
result["features"] = [t.tag for t in f.getchildren()]
result["os_type"] = guest_el.find("os_type").text
return result
return util.get_xml_path(self.get_cap_xml(), func=guests)
def get_dom_capabilities(self, arch, machine):
"""Return domain capabilities"""
result = dict()
xml = self.get_dom_cap_xml(arch, machine)
result["path"] = util.get_xml_path(xml,"/domainCapabilities/path")
result["domain"] = util.get_xml_path(xml, "/domainCapabilities/domain")
result["machine"] = util.get_xml_path(xml, "/domainCapabilities/machine")
result["vcpu_max"] = util.get_xml_path(xml, "/domainCapabilities/vcpu/@max")
result["iothreads_support"] = util.get_xml_path(xml, "/domainCapabilities/iothreads/@supported")
result["os_support"] = util.get_xml_path(xml, "/domainCapabilities/os/@supported")
result["loader_support"] = util.get_xml_path(xml, "/domainCapabilities/os/loader/@supported")
if result["loader_support"] == 'yes':
result["loaders"] = self.get_os_loaders(arch, machine)
result["loader_enums"] = self.get_os_loader_enums(arch, machine)
result["cpu_modes"] = self.get_cpu_modes(arch, machine)
if "custom" in result["cpu_modes"]:
# supported and unknown cpu models
result["cpu_custom_models"] = self.get_cpu_custom_types(arch, machine)
result["disk_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/disk/@supported")
if result["disk_support"] == 'yes':
result["disk_devices"] = self.get_disk_device_types(arch, machine)
result["disk_bus"] = self.get_disk_bus_types(arch, machine)
result["graphics_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/graphics/@supported")
if result["graphics_support"] == 'yes':
result["graphics_types"] = self.get_graphics_types(arch, machine)
result["video_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/video/@supported")
if result["video_support"] == 'yes':
result["video_types"] = self.get_video_models(arch, machine)
result["hostdev_support"] = util.get_xml_path(xml, "/domainCapabilities/devices/hostdev/@supported")
if result["hostdev_support"] == 'yes':
result["hostdev_types"] = self.get_hostdev_modes(arch, machine)
result["hostdev_startup_policies"] = self.get_hostdev_startup_policies(arch, machine)
result["hostdev_subsys_types"] = self.get_hostdev_subsys_types(arch, machine)
result["features_gic_support"] = util.get_xml_path(xml, "/domainCapabilities/features/gic/@supported")
result["features_genid_support"] = util.get_xml_path(xml, "/domainCapabilities/features/genid/@supported")
result["features_vmcoreinfo_support"] = util.get_xml_path(xml, "/domainCapabilities/features/vmcoreinfo/@supported")
result["features_sev_support"] = util.get_xml_path(xml, "/domainCapabilities/features/sev/@supported")
return result
def get_version(self): def get_version(self):
ver = self.wvm.getVersion() ver = self.wvm.getVersion()
major = ver / 1000000 major = ver / 1000000
@ -417,7 +491,7 @@ class wvmConnect(object):
'unsafe': 'Unsafe', # since libvirt 0.9.7 'unsafe': 'Unsafe', # since libvirt 0.9.7
} }
def hypervisor_type(self): def get_hypervisors_domain_types(self):
"""Return hypervisor type""" """Return hypervisor type"""
def hypervisors(ctx): def hypervisors(ctx):
result = {} result = {}
@ -428,10 +502,34 @@ class wvmConnect(object):
return result return result
return util.get_xml_path(self.get_cap_xml(), func=hypervisors) return util.get_xml_path(self.get_cap_xml(), func=hypervisors)
def get_hypervisors_machines(self):
"""Return hypervisor and its machine types"""
def machines(ctx):
result = dict()
for arche in ctx.xpath('/capabilities/guest/arch'):
arch = arche.get("name")
result[arch] = self.get_machine_types(arch)
return result
return util.get_xml_path(self.get_cap_xml(), func=machines)
def get_emulator(self, arch): def get_emulator(self, arch):
"""Return emulator """ """Return emulator """
return util.get_xml_path(self.get_cap_xml(), "/capabilities/guest/arch[@name='{}']/emulator".format(arch)) return util.get_xml_path(self.get_cap_xml(), "/capabilities/guest/arch[@name='{}']/emulator".format(arch))
def get_machine_types(self, arch):
"""Return canonical(if exist) name of machine types """
def machines(ctx):
result = list()
canonical_name = ctx.xpath("/capabilities/guest/arch[@name='{}']/machine[@canonical]".format(arch))
if not canonical_name:
canonical_name = ctx.xpath("/capabilities/guest/arch[@name='{}']/machine".format(arch))
for archi in canonical_name:
result.append(archi.text)
return result
return util.get_xml_path(self.get_cap_xml(), func=machines)
def get_emulators(self): def get_emulators(self):
def emulators(ctx): def emulators(ctx):
result = {} result = {}
@ -442,35 +540,76 @@ class wvmConnect(object):
return result return result
return util.get_xml_path(self.get_cap_xml(), func=emulators) return util.get_xml_path(self.get_cap_xml(), func=emulators)
def get_machines(self, arch): def get_os_loaders(self, arch='x86_64', machine='pc'):
""" Return machine type of emulation""" """Get available os loaders list"""
return util.get_xml_path(self.get_cap_xml(), "/capabilities/guest/arch[@name='{}']/machine".format(arch)) def get_os_loaders(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/value")]
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_os_loaders)
def get_disk_bus_types(self): def get_os_loader_enums(self, arch, machine):
"""Get available os loaders list"""
def get_os_loader_enums(ctx):
result = dict()
enums = [v for v in ctx.xpath("/domainCapabilities/os/loader[@supported='yes']/enum/@name")]
for enum in enums:
path = "/domainCapabilities/os/loader[@supported='yes']/enum[@name='{}']/value".format(enum)
result[enum] = [v.text for v in ctx.xpath(path)]
return result
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_os_loader_enums)
def get_disk_bus_types(self, arch, machine):
"""Get available disk bus types list""" """Get available disk bus types list"""
def get_bus_list(ctx): def get_bus_list(ctx):
result = [] return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='bus']/value")]
for disk_enum in ctx.xpath('/domainCapabilities/devices/disk/enum'):
if disk_enum.xpath("@name")[0] == "bus":
for values in disk_enum: result.append(values.text)
return result
# return [ 'ide', 'scsi', 'usb', 'virtio' ] # return [ 'ide', 'scsi', 'usb', 'virtio' ]
return util.get_xml_path(self.get_dom_cap_xml(), func=get_bus_list) return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_bus_list)
def get_disk_device_types(self): def get_disk_device_types(self, arch, machine):
"""Get available disk device type list""" """Get available disk device type list"""
def get_device_list(ctx): def get_device_list(ctx):
result = [] return [v.text for v in ctx.xpath("/domainCapabilities/devices/disk/enum[@name='diskDevice']/value")]
for disk_enum in ctx.xpath('/domainCapabilities/devices/disk/enum'):
if disk_enum.xpath("@name")[0] == "diskDevice":
for values in disk_enum: result.append(values.text)
return result
# return [ 'disk', 'cdrom', 'floppy', 'lun' ] # return [ 'disk', 'cdrom', 'floppy', 'lun' ]
return util.get_xml_path(self.get_dom_cap_xml(), func=get_device_list) return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_device_list)
def get_graphics_types(self, arch, machine):
"""Get available graphics types """
def get_graphics_list(ctx):
return [ v.text for v in ctx.xpath("/domainCapabilities/devices/graphics/enum[@name='type']/value")]
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_graphics_list)
def get_cpu_modes(self, arch, machine):
"""Get available cpu modes """
def get_cpu_modes(ctx):
return [v for v in ctx.xpath("/domainCapabilities/cpu/mode[@supported='yes']/@name")]
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_cpu_modes)
def get_cpu_custom_types(self, arch, machine):
"""Get available graphics types """
def get_custom_list(ctx):
usable_yes = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='yes']"
usable_unknown = "/domainCapabilities/cpu/mode[@name='custom'][@supported='yes']/model[@usable='unknown']"
result = [v.text for v in ctx.xpath(usable_yes)]
result += [v.text for v in ctx.xpath(usable_unknown)]
return result
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_custom_list)
def get_hostdev_modes(self, arch, machine):
"""Get available nodedev modes """
def get_hostdev_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='mode']/value")]
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_hostdev_list)
def get_hostdev_startup_policies(self, arch, machine):
"""Get available hostdev modes """
def get_hostdev_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='startupPolicy']/value")]
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_hostdev_list)
def get_hostdev_subsys_types(self, arch, machine):
"""Get available nodedev sub system types """
def get_hostdev_list(ctx):
return [v.text for v in ctx.xpath("/domainCapabilities/devices/hostdev/enum[@name='subsysType']/value")]
return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_hostdev_list)
def get_image_formats(self): def get_image_formats(self):
"""Get available image formats""" """Get available image formats"""
@ -480,7 +619,7 @@ class wvmConnect(object):
"""Get available image filename extensions""" """Get available image filename extensions"""
return ['img', 'qcow', 'qcow2'] return ['img', 'qcow', 'qcow2']
def get_video_models(self): def get_video_models(self, arch, machine):
""" Get available graphics video types """ """ Get available graphics video types """
def get_video_list(ctx): def get_video_list(ctx):
result = [] result = []
@ -488,7 +627,7 @@ class wvmConnect(object):
if video_enum.xpath("@name")[0] == "modelType": if video_enum.xpath("@name")[0] == "modelType":
for values in video_enum: result.append(values.text) for values in video_enum: result.append(values.text)
return result return result
return util.get_xml_path(self.get_dom_cap_xml(), func=get_video_list) return util.get_xml_path(self.get_dom_cap_xml(arch, machine), func=get_video_list)
def get_iface(self, name): def get_iface(self, name):
return self.wvm.interfaceLookupByName(name) return self.wvm.interfaceLookupByName(name)
@ -624,3 +763,49 @@ class wvmConnect(object):
# to-do: do not close connection ;) # to-do: do not close connection ;)
# self.wvm.close() # self.wvm.close()
pass pass
def find_uefi_path_for_arch(self, arch, machine):
"""
Search the loader paths for one that matches the passed arch
"""
if not self.arch_can_uefi(arch):
return
loaders = self.get_os_loaders(arch, machine)
patterns = util.uefi_arch_patterns.get(arch)
for pattern in patterns:
for path in loaders:
if re.match(pattern, path):
return path
def label_for_firmware_path(self, arch, path):
"""
Return a pretty label for passed path, based on if we know
about it or not
"""
if not path:
if arch in ["i686", "x86_64"]:
return "BIOS"
return
for arch, patterns in util.uefi_arch_patterns.items():
for pattern in patterns:
if re.match(pattern, path):
return ("UEFI %(arch)s: %(path)s" %
{"arch": arch, "path": path})
return "Custom: %(path)s" % {"path": path}
def arch_can_uefi(self, arch):
"""
Return True if we know how to setup UEFI for the passed arch
"""
return arch in list(util.uefi_arch_patterns.keys())
def supports_uefi_xml(self, loader_enums):
"""
Return True if libvirt advertises support for proper UEFI setup
"""
return ("readonly" in loader_enums and
"yes" in loader_enums.get("readonly"))

View file

@ -1,9 +1,11 @@
import string import string
from vrtManager import util from vrtManager import util
from vrtManager.connection import wvmConnect from vrtManager.connection import wvmConnect
from webvirtcloud.settings import QEMU_CONSOLE_DEFAULT_TYPE from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as DEFAULT_OWNER
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_FORMAT
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DRIVER_OPTS as OPTS
def get_rbd_storage_data(stg): def get_rbd_storage_data(stg):
@ -11,7 +13,7 @@ def get_rbd_storage_data(stg):
ceph_user = util.get_xml_path(xml, "/pool/source/auth/@username") ceph_user = util.get_xml_path(xml, "/pool/source/auth/@username")
def get_ceph_hosts(doc): def get_ceph_hosts(doc):
hosts = [] hosts = list()
for host in doc.xpath("/pool/source/host"): for host in doc.xpath("/pool/source/host"):
name = host.prop("name") name = host.prop("name")
if name: if name:
@ -29,7 +31,7 @@ class wvmCreate(wvmConnect):
""" """
Function return all images on all storages Function return all images on all storages
""" """
images = [] images = list()
storages = self.get_storages(only_actives=True) storages = self.get_storages(only_actives=True)
for storage in storages: for storage in storages:
stg = self.get_storage(storage) stg = self.get_storage(storage)
@ -45,14 +47,14 @@ class wvmCreate(wvmConnect):
return images return images
def get_os_type(self): def get_os_type(self):
"""Get guest capabilities""" """Get guest os type"""
return util.get_xml_path(self.get_cap_xml(), "/capabilities/guest/os_type") return util.get_xml_path(self.get_cap_xml(), "/capabilities/guest/os_type")
def get_host_arch(self): def get_host_arch(self):
"""Get guest capabilities""" """Get guest capabilities"""
return util.get_xml_path(self.get_cap_xml(), "/capabilities/host/cpu/arch") return util.get_xml_path(self.get_cap_xml(), "/capabilities/host/cpu/arch")
def create_volume(self, storage, name, size, image_format=image_format, metadata=False, owner=default_owner): def create_volume(self, storage, name, size, image_format=image_format, metadata=False, owner=DEFAULT_OWNER):
size = int(size) * 1073741824 size = int(size) * 1073741824
stg = self.get_storage(storage) stg = self.get_storage(storage)
storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type") storage_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
@ -120,7 +122,7 @@ class wvmCreate(wvmConnect):
vol = self.get_volume_by_path(vol_path) vol = self.get_volume_by_path(vol_path)
return vol.storagePoolLookupByVolume() return vol.storagePoolLookupByVolume()
def clone_from_template(self, clone, template, storage=None, metadata=False, owner=default_owner): def clone_from_template(self, clone, template, storage=None, metadata=False, owner=DEFAULT_OWNER):
vol = self.get_volume_by_path(template) vol = self.get_volume_by_path(template)
if not storage: if not storage:
stg = vol.storagePoolLookupByVolume() stg = vol.storagePoolLookupByVolume()
@ -163,16 +165,15 @@ class wvmCreate(wvmConnect):
vol = self.get_volume_by_path(path) vol = self.get_volume_by_path(path)
vol.delete() vol.delete()
def create_instance(self, name, memory, vcpu, host_model, uuid, images, cache_mode, networks, virtio, listen_addr, nwfilter=None, video="cirrus", console_pass="random", mac=None, qemu_ga=False): def create_instance(self, name, memory, vcpu, vcpu_mode, uuid, arch, machine, firmware, images, cache_mode, networks, nwfilter, graphics, virtio, listen_addr, video="vga", console_pass="random", mac=None, qemu_ga=False):
""" """
Create VM function Create VM function
""" """
memory = int(memory) * 1024 caps = self.get_capabilities(arch)
dom_caps = self.get_dom_capabilities(arch, machine)
if self.is_kvm_supported(): memory = int(memory) * 1024
hypervisor_type = 'kvm' #hypervisor_type = 'kvm' if self.is_kvm_supported() else 'qemu'
else:
hypervisor_type = 'qemu'
xml = """ xml = """
<domain type='%s'> <domain type='%s'>
@ -180,23 +181,46 @@ class wvmCreate(wvmConnect):
<description>None</description> <description>None</description>
<uuid>%s</uuid> <uuid>%s</uuid>
<memory unit='KiB'>%s</memory> <memory unit='KiB'>%s</memory>
<vcpu>%s</vcpu>""" % (hypervisor_type, name, uuid, memory, vcpu) <vcpu>%s</vcpu>""" % (dom_caps["domain"], name, uuid, memory, vcpu)
if host_model:
if dom_caps["os_support"] == 'yes':
xml += """<os>
<type arch='%s' machine='%s'>%s</type>""" % (arch, machine, caps["os_type"])
xml += """ <boot dev='hd'/>
<boot dev='cdrom'/>
<bootmenu enable='yes'/>"""
if 'UEFI' in firmware:
xml += """<loader readonly='yes' type='pflash'>%s</loader>""" % firmware.split(":")[1].strip()
xml += """</os>"""
if caps["features"]:
xml += """<features>"""
if 'acpi' in caps["features"]:
xml += """<acpi/>"""
if 'apic' in caps["features"]:
xml += """<apic/>"""
if 'pae' in caps["features"]:
xml += """<pae/>"""
xml += """</features>"""
if vcpu_mode == "host-model":
xml += """<cpu mode='host-model'/>""" xml += """<cpu mode='host-model'/>"""
xml += """<os> elif vcpu_mode == "host-passthrough":
<type arch='%s'>%s</type> xml += """<cpu mode='host-passthrough'/>"""
<boot dev='hd'/> elif vcpu_mode == "":
<boot dev='cdrom'/> pass
<bootmenu enable='yes'/> else:
</os>""" % (self.get_host_arch(), self.get_os_type()) xml += """<cpu mode='custom' match='exact' check='none'>
xml += """<features> <model fallback='allow'>{}</model>
<acpi/><apic/><pae/> </cpu>""".format(vcpu_mode)
</features>
xml += """
<clock offset="utc"/> <clock offset="utc"/>
<on_poweroff>destroy</on_poweroff> <on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot> <on_reboot>restart</on_reboot>
<on_crash>restart</on_crash> <on_crash>restart</on_crash>
<devices>""" """
xml += """<devices>"""
vd_disk_letters = list(string.lowercase) vd_disk_letters = list(string.lowercase)
fd_disk_letters = list(string.lowercase) fd_disk_letters = list(string.lowercase)
@ -212,11 +236,11 @@ class wvmCreate(wvmConnect):
if stg_type == 'rbd': if stg_type == 'rbd':
ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg) ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg)
xml += """<disk type='network' device='disk'> xml += """<disk type='network' device='disk'>
<driver name='qemu' type='%s' cache='%s'/> <driver name='qemu' type='%s' cache='%s' %s />""" % (volume['type'], cache_mode, OPTS.get("network", ''))
<auth username='%s'> xml += """ <auth username='%s'>
<secret type='ceph' uuid='%s'/> <secret type='ceph' uuid='%s'/>
</auth> </auth>
<source protocol='rbd' name='%s'>""" % (volume['type'], cache_mode, ceph_user, secret_uuid, volume['path']) <source protocol='rbd' name='%s'>""" % (ceph_user, secret_uuid, volume['path'])
if isinstance(ceph_hosts, list): if isinstance(ceph_hosts, list):
for host in ceph_hosts: for host in ceph_hosts:
if host.get('port'): if host.get('port'):
@ -225,12 +249,11 @@ class wvmCreate(wvmConnect):
else: else:
xml += """ xml += """
<host name='%s'/>""" % host.get('name') <host name='%s'/>""" % host.get('name')
xml += """ xml += """</source>"""
</source>"""
else: else:
xml += """<disk type='file' device='%s'> xml += """<disk type='file' device='%s'>""" % volume['device']
<driver name='qemu' type='%s' cache='%s'/> xml += """ <driver name='qemu' type='%s' cache='%s' %s/>""" % (volume['type'], cache_mode, OPTS.get("file", ''))
<source file='%s'/>""" % (volume['device'], volume['type'], cache_mode, volume['path']) xml += """ <source file='%s'/>""" % volume['path']
if volume['bus'] == 'virtio': if volume['bus'] == 'virtio':
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume['bus']) xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume['bus'])
@ -242,12 +265,23 @@ class wvmCreate(wvmConnect):
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume['bus']) xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume['bus'])
xml += """</disk>""" xml += """</disk>"""
if add_cd: if add_cd:
xml += """ <disk type='file' device='cdrom'> xml += """<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/> <driver name='qemu' type='raw'/>
<source file=''/> <source file = '' />
<target dev='hd%s' bus='ide'/> <readonly/>"""
<readonly/> if 'ide' in dom_caps['disk_bus']:
</disk>""" % (hd_disk_letters.pop(0),) xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), 'ide')
elif 'sata' in dom_caps['disk_bus']:
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'sata')
elif 'scsi' in dom_caps['disk_bus']:
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), 'scsi')
else:
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), 'virtio')
xml += """</disk>"""
if volume['bus'] == 'scsi':
xml += """<controller type='scsi' model='%s'/>""" % INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER
for net in networks.split(','): for net in networks.split(','):
xml += """<interface type='network'>""" xml += """<interface type='network'>"""
if mac: if mac:
@ -265,10 +299,11 @@ class wvmCreate(wvmConnect):
if not console_pass == "": if not console_pass == "":
console_pass = "passwd='" + console_pass + "'" console_pass = "passwd='" + console_pass + "'"
xml += """ <input type='mouse' bus='ps2'/> xml += """<input type='mouse' bus='virtio'/>"""
<input type='tablet' bus='usb'/> xml += """<input type='tablet' bus='virtio'/>"""
<graphics type='%s' port='-1' autoport='yes' %s listen='%s'/> xml += """
<console type='pty'/> """ % (QEMU_CONSOLE_DEFAULT_TYPE, console_pass, listen_addr) <graphics type='%s' port='-1' autoport='yes' %s listen='%s'/>
<console type='pty'/> """ % (graphics, console_pass, listen_addr)
if qemu_ga: if qemu_ga:
xml += """ <channel type='unix'> xml += """ <channel type='unix'>
@ -278,7 +313,6 @@ class wvmCreate(wvmConnect):
xml += """ <video> xml += """ <video>
<model type='%s'/> <model type='%s'/>
</video> </video>
<memballoon model='virtio'/>
</devices> </devices>
</domain>""" % video </domain>""" % video
self._defineXML(xml) self._defineXML(xml)

View file

@ -149,11 +149,31 @@ SHOW_PROFILE_EDIT_PASSWORD = False
# available: default (grid), list # available: default (grid), list
VIEW_ACCOUNTS_STYLE = 'grid' VIEW_ACCOUNTS_STYLE = 'grid'
# available: default (grouped), nongrouped # available list style: default (grouped), nongrouped
VIEW_INSTANCES_LIST_STYLE = 'grouped' VIEW_INSTANCES_LIST_STYLE = 'grouped'
# available volume format: raw, qcow2, qcow
INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2' INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2'
# available bus types: virtio, scsi, ide, usb, sata
INSTANCE_VOLUME_DEFAULT_BUS = 'virtio' INSTANCE_VOLUME_DEFAULT_BUS = 'virtio'
#SCSI types: 'virtio-scsi', 'lsilogic'
INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER = 'virtio-scsi'
# Volume optionals: two variable: disk driver type is file and network(rbd, iscsi),
# optionals : discard='unmap|ignore', detect_zeroes='on|off|unmap', copy_on_read='on|off'
# Example: {"file": "discard='unmap' copy_on_read='on'", "network": "detect_zeroes='unmap'"}
INSTANCE_VOLUME_DEFAULT_DRIVER_OPTS = {"file": "", "network": ""}
# available cache types: none, unsafe, writeback, writethrough
INSTANCE_VOLUME_DEFAULT_CACHE = 'directsync' INSTANCE_VOLUME_DEFAULT_CACHE = 'directsync'
# up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu) # up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)
INSTANCE_VOLUME_DEFAULT_OWNER = {'uid': 0, 'guid': 0} 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'