mirror of
https://github.com/retspen/webvirtcloud
synced 2024-11-01 03:54:15 +00:00
Merge pull request #208 from catborise/master
New Features: Add/Remove CD-Rom Device, Enchance VM Creation
This commit is contained in:
commit
b7639d2ba6
18 changed files with 1955 additions and 538 deletions
|
@ -42,6 +42,7 @@
|
|||
<p>{% trans "Hostname" %}</p>
|
||||
<p>{% trans "Hypervisors" %}</p>
|
||||
<p>{% trans "Emulator" %}</p>
|
||||
<p>{% trans "Version" %}</p>
|
||||
<p>{% trans "Memory" %}</p>
|
||||
<p>{% trans "Architecture" %}</p>
|
||||
<p>{% trans "Logical CPUs" %}</p>
|
||||
|
@ -55,10 +56,17 @@
|
|||
<span class="glyphicon glyphicon-chevron-right"></span>
|
||||
<span class="label label-default">{{ arch }}</span>
|
||||
{% for h in hpv %}
|
||||
<span class="label label-primary">{{ h }}</span>{% endfor %}
|
||||
<span class="label label-primary">{{ h }}</span>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p>{{ emulator }}</p>
|
||||
<p>
|
||||
<span class="label label-default">{% trans 'Qemu' %} </span>
|
||||
<span class="label label-primary">{{ version }}</span>
|
||||
<span class="label label-default">{% trans 'Libvirt' %} </span>
|
||||
<span class="label label-primary">{{ lib_version }}</span>
|
||||
</p>
|
||||
<p>{{ host_memory|filesizeformat }}</p>
|
||||
<p>{{ host_arch }}</p>
|
||||
<p>{{ logical_cpu }}</p>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from django.conf.urls import url
|
||||
from storages.views import storages, storage
|
||||
from storages.views import storages, storage, get_volumes
|
||||
from networks.views import networks, network
|
||||
from secrets.views import secrets
|
||||
from create.views import create_instance
|
||||
from interfaces.views import interfaces, interface
|
||||
from computes.views import overview, compute_graph, computes
|
||||
from computes.views import overview, compute_graph, computes, get_compute_disk_buses
|
||||
from instances.views import instances
|
||||
from nwfilters.views import nwfilter, nwfilters
|
||||
|
||||
|
@ -14,6 +14,7 @@ urlpatterns = [
|
|||
url(r'^(?P<compute_id>[0-9]+)/statistics$', compute_graph, name='compute_graph'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/instances/$', instances, name='instances'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/storages/$', storages, name='storages'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/storage/(?P<pool>[\w\-\.\/]+)/volumes$', get_volumes, name='volumes'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/storage/(?P<pool>[\w\-\.\/]+)/$', storage, name='storage'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/networks/$', networks, name='networks'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/network/(?P<pool>[\w\-\.]+)/$', network, name='network'),
|
||||
|
@ -23,4 +24,5 @@ urlpatterns = [
|
|||
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]+)/create/$', create_instance, name='create_instance'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/disk/(?P<disk>[\w\-\.\/]+)/buses$', get_compute_disk_buses, name='buses'),
|
||||
]
|
||||
|
|
|
@ -9,7 +9,7 @@ from instances.models import Instance
|
|||
from accounts.models import UserInstance
|
||||
from computes.forms import ComputeAddTcpForm, ComputeAddSshForm, ComputeEditHostForm, ComputeAddTlsForm, ComputeAddSocketForm
|
||||
from vrtManager.hostdetails import wvmHostDetails
|
||||
from vrtManager.connection import CONN_SSH, CONN_TCP, CONN_TLS, CONN_SOCKET, connection_manager
|
||||
from vrtManager.connection import CONN_SSH, CONN_TCP, CONN_TLS, CONN_SOCKET, connection_manager, wvmConnect
|
||||
from libvirt import libvirtError
|
||||
|
||||
|
||||
|
@ -157,6 +157,8 @@ def overview(request, compute_id):
|
|||
hypervisor = conn.hypervisor_type()
|
||||
mem_usage = conn.get_memory_usage()
|
||||
emulator = conn.get_emulator(host_arch)
|
||||
version = conn.get_version()
|
||||
lib_version = conn.get_lib_version()
|
||||
conn.close()
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
@ -225,3 +227,32 @@ def compute_graph(request, compute_id):
|
|||
response.cookies['mem'] = datasets['mem']
|
||||
response.write(data)
|
||||
return response
|
||||
|
||||
|
||||
@login_required
|
||||
def get_compute_disk_buses(request, compute_id, disk):
|
||||
data = {}
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
try:
|
||||
conn = wvmConnect(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
|
||||
disk_device_types = conn.get_disk_device_types()
|
||||
disk_bus_types = conn.get_disk_bus_types()
|
||||
|
||||
if disk in disk_device_types:
|
||||
if disk == 'disk':
|
||||
data['bus'] = sorted(disk_device_types)
|
||||
elif disk == 'cdrom':
|
||||
data['bus'] = ['ide', 'sata', 'scsi',]
|
||||
elif disk == 'floppy':
|
||||
data['bus'] = ['fdc',]
|
||||
elif disk == 'lun':
|
||||
data['bus'] = ['scsi',]
|
||||
except libvirtError:
|
||||
pass
|
||||
|
||||
return HttpResponse(json.dumps(data))
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class NewVMForm(forms.Form):
|
|||
host_model = forms.BooleanField(required=False)
|
||||
disk = forms.IntegerField(required=False)
|
||||
memory = forms.IntegerField(error_messages={'required': _('No RAM size has been entered')})
|
||||
networks = forms.CharField(error_messages={'required': _('No Network pool has been choice')})
|
||||
networks = forms.CharField(error_messages={'required': _('No Network pool has been choosen')})
|
||||
nwfilter = forms.CharField(required=False)
|
||||
storage = forms.CharField(max_length=20, required=False)
|
||||
template = forms.CharField(required=False)
|
||||
|
@ -46,6 +46,7 @@ class NewVMForm(forms.Form):
|
|||
hdd_size = forms.IntegerField(required=False)
|
||||
meta_prealloc = forms.BooleanField(required=False)
|
||||
virtio = forms.BooleanField(required=False)
|
||||
qemu_ga = forms.BooleanField(required=False)
|
||||
mac = forms.CharField(required=False)
|
||||
console_pass = forms.CharField(required=False,empty_value="", widget=forms.PasswordInput())
|
||||
video = forms.CharField(error_messages={'required': _('Please select a graphic display')})
|
||||
|
|
|
@ -16,6 +16,22 @@
|
|||
{% 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">
|
||||
|
@ -187,6 +203,12 @@
|
|||
</div>
|
||||
<label class="col-lg-1 control-label">{% trans "CPU" %}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Guest Agent" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="checkbox" name="qemu_ga" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VirtIO" %}</label>
|
||||
<div class="col-sm-6">
|
||||
|
@ -232,58 +254,70 @@
|
|||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Name" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="14" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="20" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VCPU" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" name="vcpu" value="1" maxlength="1" required pattern="[0-9]">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" name="vcpu" value="1" maxlength="2" required pattern="[0-9]">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Host-Model" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="checkbox" name="host_model" value="true" checked>
|
||||
</div>
|
||||
<label class="col-sm-1 control-label">{% trans "CPU" %}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "RAM" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" name="memory" value="512" maxlength="5" required pattern="[0-9]+">
|
||||
</div>
|
||||
<label class="col-sm-1 control-label">{% trans "MB" %}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "HDD" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<ul id="img-list">
|
||||
<div id="disk_list_div" class="form-group" hidden>
|
||||
<label id="added_disks" class="col-sm-3 control-label">{% trans "Added Disks" %}</label>
|
||||
<div class="col-sm-7">
|
||||
<ul id="img-list" class="form-row">
|
||||
<!-- populated from javascript -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "HDD" %}</label>
|
||||
<input id="images" name="images" type="hidden" value=""/>
|
||||
<select id="image-control" name="image-control" class="form-control" multiple="multiple">
|
||||
{% if get_images %}
|
||||
{% for name in get_images %}
|
||||
<option value="{{ name }}">{{ name }}</option>
|
||||
<div class="col-sm-3">
|
||||
<select id="storage-control" name="storage-control" class="form-control" onchange="get_cust_vols({{ compute_id }}, value);">
|
||||
{% if storages %}
|
||||
<option value disabled selected>{% trans "Select pool..." %}</option>
|
||||
{% for storage in storages %}
|
||||
<option value="{{ storage }}" >{{ storage }}</option>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<select id="image-control" class="form-control" name="image-control" multiple="multiple">
|
||||
<!-- populated from javascript -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group meta-prealloc">
|
||||
<label class="col-sm-3 control-label">{% trans "Metadata" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="checkbox" name="meta_prealloc" title="Metadata preallocation" value="true">
|
||||
</div>
|
||||
<label class="col-lg-1 control-label">{% trans "Image" %}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "HDD cache mode" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select id="cache_mode" name="cache_mode" class="form-control">
|
||||
{% for mode, name in cache_modes %}
|
||||
<option value="{{ mode }}" {% ifequal mode default_cache %}selected {% endifequal %}>
|
||||
|
@ -294,7 +328,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Network" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<ul id="net-list">
|
||||
<!-- populated from javascript -->
|
||||
</ul>
|
||||
|
@ -308,7 +342,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "NWFilter" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select name="nwfilter" class="form-control">
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% for nwfilter in nwfilters %}
|
||||
|
@ -319,7 +353,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Video" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select name="video" class="form-control">
|
||||
{% if not videos %}
|
||||
<option value="vga">vga</option>
|
||||
|
@ -333,13 +367,13 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Console Password" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="password" class="form-control" name="console_pass" placeholder="{% trans "Console Password" %}" maxlength="14">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Console Access" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select name="listener_addr" class="form-control">
|
||||
{% for addr, label in listener_addr %}
|
||||
<option value="{{ addr }}" {% if addr == "0.0.0.0" %} selected {% endif %}>{{ label }}</option>
|
||||
|
@ -348,13 +382,19 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VirtIO" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Guest Agent" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="checkbox" name="qemu_ga" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VirtIO" %}</label>
|
||||
<div class="col-sm-7">
|
||||
<input type="checkbox" name="virtio" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
{% if storages %}
|
||||
<button type="submit" class="btn btn-primary" name="create" onclick="showPleaseWaitDialog()" value="1">
|
||||
<button type="submit" class="btn btn-primary" name="create" formnovalidate onclick="showPleaseWaitDialog()" value="1">
|
||||
{% trans "Create" %}
|
||||
</button>
|
||||
{% else %}
|
||||
|
@ -372,54 +412,62 @@
|
|||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Name" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="14" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" maxlength="20" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VCPU" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" name="vcpu" value="1" maxlength="1" required pattern="[0-9]">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" name="vcpu" value="1" maxlength="2" required pattern="[0-9]">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Host-Model" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="checkbox" name="host_model" value="true" checked>
|
||||
</div>
|
||||
<label class="col-sm-1 control-label">{% trans "CPU" %}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "RAM" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" name="memory" value="512" maxlength="5" required pattern="[0-9]+">
|
||||
</div>
|
||||
<label class="col-sm-1 control-label">{% trans "MB" %}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "HDD" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="template" class="form-control">
|
||||
{% if get_images %}
|
||||
{% for name in get_images %}
|
||||
<option value="{{ name }}">{{ name }}</option>
|
||||
<input id="images" name="images" type="hidden" value=""/>
|
||||
<div class="col-sm-3">
|
||||
<select id="temp-storage-control" name="temp-storage-control" class="form-control" onchange="get_template_vols({{ compute_id }}, value);">
|
||||
{% if storages %}
|
||||
<option value disabled selected>{% trans "Select pool" %}...</option>
|
||||
{% for storage in storages %}
|
||||
<option value="{{ storage }}" >{{ storage }}</option>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<select id="template" class="form-control" name="template" disabled>
|
||||
<!-- populated from javascript -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group meta-prealloc">
|
||||
<label class="col-sm-3 control-label">{% trans "Metadata" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="checkbox" name="meta_prealloc" title="Metadata preallocation" value="true">
|
||||
</div>
|
||||
<label class="col-lg-1 control-label">{% trans "Image" %}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "HDD cache mode" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select id="cache_mode" name="cache_mode" class="form-control">
|
||||
{% for mode, name in cache_modes %}
|
||||
<option value="{{ mode }}" {% ifequal mode default_cache %}selected {% endifequal %}>
|
||||
|
@ -430,7 +478,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Network" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select name="networks" class="form-control">
|
||||
{% for network in networks %}
|
||||
<option value="{{ network }}">{{ network }}</option>
|
||||
|
@ -440,7 +488,7 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "NWFilter" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select name="nwfilter" class="form-control">
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% for nwfilter in nwfilters %}
|
||||
|
@ -449,15 +497,9 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VirtIO" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="checkbox" name="virtio" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Video" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select name="video" class="form-control">
|
||||
{% if not videos %}
|
||||
<option value="vga">vga</option>
|
||||
|
@ -471,13 +513,13 @@
|
|||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Console Password" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<input type="password" class="form-control" name="console_pass" placeholder="{% trans "Console Password" %}" maxlength="14">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Console Access" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-7">
|
||||
<select name="listener_addr" class="form-control">
|
||||
{% for addr, label in listener_addr %}
|
||||
<option value="{{ addr }}" {% if addr == "0.0.0.0" %} selected {% endif %}>{{ label }}</option>
|
||||
|
@ -485,9 +527,21 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Guest Agent" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="checkbox" name="qemu_ga" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VirtIO" %}</label>
|
||||
<div class="col-sm-7">
|
||||
<input type="checkbox" name="virtio" value="true" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if storages %}
|
||||
<button type="submit" class="btn btn-primary" name="create" value="1" onclick="showPleaseWaitDialog()">
|
||||
<button type="submit" class="btn btn-primary" name="create" value="1" formnovalidate onclick="showPleaseWaitDialog()">
|
||||
{% trans "Create" %}
|
||||
</button>
|
||||
{% else %}
|
||||
|
@ -539,9 +593,17 @@
|
|||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$('#image-control').multiselect({
|
||||
disableIfEmpty: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
maxHeight: 400,
|
||||
inheritClass: true,
|
||||
buttonWidth:function (options, select) {
|
||||
return '100%';
|
||||
},
|
||||
buttonText: function (options, select) {
|
||||
return 'Add image <b class="caret"></b>';
|
||||
return 'Add image...';
|
||||
},
|
||||
buttonTitle: function (options, select) {
|
||||
return '';
|
||||
|
@ -549,28 +611,51 @@
|
|||
onChange: function (element, checked) {
|
||||
var input_value = toggleValue($('#images').val(), element.val(), checked);
|
||||
$('#images').val(input_value);
|
||||
|
||||
var selected_list_html = '';
|
||||
var counter = 0;
|
||||
if (input_value != '') {
|
||||
$('#disk_list_div').show();
|
||||
$.each(input_value.split(','), function (index, value) {
|
||||
var li = '<li>hdd' + counter +
|
||||
var li = '<li>hdd' + counter + ' - ' +
|
||||
'<select name="device' + counter + '" class="image-format" onchange="get_disk_bus_choices({{ compute_id }},' + counter + ', value);">' +
|
||||
'{% for dev in disk_devices %}' +
|
||||
'<option value=' + '"{{ dev }}">' + '{% trans dev %}</option>' +
|
||||
'{% endfor %}' +
|
||||
'</select>' +
|
||||
'<select id="bus' + counter + '" name="bus' + counter + '" class="image-format">' +
|
||||
'{% for bus in disk_buses %}' +
|
||||
'<option value=' + '"{{ bus }}"' +
|
||||
'{% if bus == default_bus %}selected{% endif %}>' +
|
||||
'{% trans bus %}</option>' +
|
||||
'{% endfor %}' +
|
||||
'</select>' +
|
||||
' -> ' + value + ' ' +
|
||||
'<a class="btn-link" onclick="javascript:$(\'#image-control\').multiselect(\'deselect\', \'' + value + '\')">x</a></li>';
|
||||
'<a class="btn-link pull-right" onclick="javascript:$(\'#image-control\').multiselect(\'deselect\', \'' + value + '\', true)"><i class="fa fa-remove"></i></a>' +
|
||||
'</li>';
|
||||
selected_list_html += li;
|
||||
counter++;
|
||||
});
|
||||
}else {
|
||||
$('#disk_list_div').hide();
|
||||
}
|
||||
$('#img-list').html(selected_list_html);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$('#network-control').multiselect({
|
||||
inheritClass: true,
|
||||
buttonText: function (options, select) {
|
||||
return 'Add network <b class="caret"></b>';
|
||||
return 'Add network';
|
||||
},
|
||||
buttonTitle: function (options, select) {
|
||||
return '';
|
||||
},
|
||||
buttonWidth:function (options, select) {
|
||||
return '100%';
|
||||
},
|
||||
onChange: function (element, checked) {
|
||||
var input_value = toggleValue($('#networks').val(), element.val(), checked);
|
||||
$('#networks').val(input_value);
|
||||
|
@ -580,7 +665,7 @@
|
|||
$.each(input_value.split(','), function (index, value) {
|
||||
var li = '<li>eth' + counter +
|
||||
' -> ' + value + ' ' +
|
||||
'<a class="btn-link" onclick="javascript:$(\'#network-control\').multiselect(\'deselect\', \'' + value + '\')">x</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;
|
||||
counter++;
|
||||
});
|
||||
|
@ -589,7 +674,43 @@
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
function get_cust_vols(compute_id, pool) {
|
||||
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
||||
$.getJSON(get_vol_url, function (data) {
|
||||
$("#image-control").find('option').remove();
|
||||
$.each(data['vols'], function(i, item) {
|
||||
$("#image-control").append('<option value=' + item +'>' + item + '</option>');
|
||||
});
|
||||
$('#image-control').multiselect('rebuild');
|
||||
});
|
||||
}
|
||||
|
||||
function get_template_vols(compute_id, pool) {
|
||||
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
||||
$.getJSON(get_vol_url, function (data) {
|
||||
$("#template").find('option').remove();
|
||||
$.each(data['vols'], function(i, item) {
|
||||
$("#template").append('<option value=' + item +'>' + item + '</option>');
|
||||
});
|
||||
});
|
||||
$("#template").removeAttr("disabled");
|
||||
}
|
||||
|
||||
function get_disk_bus_choices(compute_id, dev_idx, disk_type){
|
||||
get_diskBus_url = "/computes/" + compute_id + "/disk/" + disk_type + "/buses";
|
||||
|
||||
$.getJSON(get_diskBus_url, function (data) {
|
||||
$("#bus" + dev_idx).find('option').remove();
|
||||
$.each(data['bus'], function(i, item) {
|
||||
$("#bus" + dev_idx).append('<option value=' + item +'>' + item + '</option>');
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="{% static "js/ace.js" %}"></script>
|
||||
<script>
|
||||
var editor = ace.edit("editor");
|
||||
|
|
|
@ -12,7 +12,10 @@ from vrtManager import util
|
|||
from libvirt import libvirtError
|
||||
from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES
|
||||
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_CACHE
|
||||
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_BUS
|
||||
from django.contrib import messages
|
||||
from logs.views import addlogmsg
|
||||
|
||||
|
||||
@login_required
|
||||
def create_instance(request, compute_id):
|
||||
|
@ -47,7 +50,9 @@ def create_instance(request, compute_id):
|
|||
default_cache = INSTANCE_VOLUME_DEFAULT_CACHE
|
||||
listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES
|
||||
mac_auto = util.randomMAC()
|
||||
get_images = sorted(conn.get_storages_images())
|
||||
disk_devices = conn.get_disk_device_types()
|
||||
disk_buses = conn.get_disk_bus_types()
|
||||
default_bus = INSTANCE_VOLUME_DEFAULT_BUS
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
||||
|
@ -91,7 +96,9 @@ def create_instance(request, compute_id):
|
|||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err.message)
|
||||
if 'create' in request.POST:
|
||||
volumes = {}
|
||||
volume_list = []
|
||||
|
||||
clone_path = ""
|
||||
form = NewVMForm(request.POST)
|
||||
if form.is_valid():
|
||||
data = form.cleaned_data
|
||||
|
@ -112,7 +119,13 @@ def create_instance(request, compute_id):
|
|||
try:
|
||||
path = conn.create_volume(data['storage'], data['name'], data['hdd_size'],
|
||||
metadata=meta_prealloc)
|
||||
volumes[path] = conn.get_volume_type(path)
|
||||
volume = dict()
|
||||
volume['path'] = path
|
||||
volume['type'] = conn.get_volume_type(path)
|
||||
volume['device'] = 'disk'
|
||||
volume['bus'] = 'virtio'
|
||||
volume_list.append(volume)
|
||||
#volumes[path] = conn.get_volume_type(path)
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err.message)
|
||||
elif data['template']:
|
||||
|
@ -123,16 +136,31 @@ def create_instance(request, compute_id):
|
|||
error_messages.append(error_msg)
|
||||
else:
|
||||
clone_path = conn.clone_from_template(data['name'], templ_path, metadata=meta_prealloc)
|
||||
volumes[clone_path] = conn.get_volume_type(clone_path)
|
||||
volume = dict()
|
||||
volume['path'] = clone_path
|
||||
volume['type'] = conn.get_volume_type(clone_path)
|
||||
volume['device'] = 'disk'
|
||||
volume['bus'] = 'virtio'
|
||||
volume_list.append(volume)
|
||||
#volumes[clone_path] = conn.get_volume_type(clone_path)
|
||||
else:
|
||||
if not data['images']:
|
||||
error_msg = _("First you need to create or select an image")
|
||||
error_messages.append(error_msg)
|
||||
else:
|
||||
for vol in data['images'].split(','):
|
||||
for idx, vol in enumerate(data['images'].split(',')):
|
||||
try:
|
||||
|
||||
path = conn.get_volume_path(vol)
|
||||
volumes[path] = conn.get_volume_type(path)
|
||||
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), '')
|
||||
volume_list.append(volume)
|
||||
|
||||
#volumes[path] = conn.get_volume_type(path)
|
||||
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err.message)
|
||||
if data['cache_mode'] not in conn.get_cache_modes():
|
||||
|
@ -142,17 +170,19 @@ def create_instance(request, compute_id):
|
|||
uuid = util.randomUUID()
|
||||
try:
|
||||
conn.create_instance(data['name'], data['memory'], data['vcpu'], data['host_model'],
|
||||
uuid, volumes, data['cache_mode'], data['networks'], data['virtio'],
|
||||
uuid, volume_list, data['cache_mode'], data['networks'], data['virtio'],
|
||||
data["listener_addr"], data["nwfilter"], data["video"], data["console_pass"],
|
||||
data['mac'])
|
||||
data['mac'], data['qemu_ga'])
|
||||
create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
|
||||
create_instance.save()
|
||||
messages.success(request, _("Instance is created."))
|
||||
msg = _("Instance is created.")
|
||||
messages.success(request, msg)
|
||||
addlogmsg(request.user.username, create_instance.name, msg)
|
||||
return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']]))
|
||||
except libvirtError as lib_err:
|
||||
if data['hdd_size'] or volumes[clone_path]:
|
||||
conn.delete_volume(volumes.keys()[0])
|
||||
if data['hdd_size'] or volume_list.count() > 0:
|
||||
for vol in volume_list:
|
||||
conn.delete_volume(vol['path'])
|
||||
error_messages.append(lib_err)
|
||||
conn.close()
|
||||
|
||||
return render(request, 'create_instance.html', locals())
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
<p style="font-weight:bold;">{% trans "Volume parameters" %}</p>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Storage" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Storage" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="storage" class="form-control image-format">
|
||||
{% for storage in storages %}
|
||||
|
@ -35,13 +35,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Name" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Name" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" name="name" placeholder="{% trans "Name" %}" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Format" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Format" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="format" class="form-control image-format">
|
||||
{% for format in formats %}
|
||||
|
@ -51,14 +51,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Size" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Size" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" name="size" value="10" maxlength="3" required pattern="[0-9]+">
|
||||
<input type="text" class="form-control" name="size" value="10" maxlength="5" required pattern="[0-9]+">
|
||||
</div>
|
||||
<label class="col-sm-1 control-label">{% trans "GB" %}</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Bus" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Bus" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="bus" class="form-control image-format">
|
||||
{% for bus in busses %}
|
||||
|
@ -68,7 +68,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Cache" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Cache" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="cache" class="form-control image-format">
|
||||
{% for mode, name in cache_modes %}
|
||||
|
@ -78,14 +78,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group meta-prealloc">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Metadata" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Metadata" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="meta_prealloc" value="true">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{% ifequal status 5 %}
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="addnewvol">{% trans "Add Volume" %}</button>
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_new_vol">{% trans "Add Volume" %}</button>
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Add Volume" %}</button>
|
||||
{% endifequal %}
|
||||
|
@ -97,7 +97,7 @@
|
|||
<div class="modal-body">
|
||||
<p style="font-weight:bold;">{% trans "Volume parameters" %}</p>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Storage" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Storage" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="dropdown">
|
||||
<button id="select_storage" class="btn btn-default dropdown-toggle form-control" type="button" data-toggle="dropdown">{% trans 'Select Pool...' %}
|
||||
|
@ -112,7 +112,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Volume" %}</label>
|
||||
<label class="col-sm-3 control-label" >{% trans "Volume" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select id="vols" name="vols" class="form-control" disabled>
|
||||
<option value="" selected>{% trans 'None' %}</option>
|
||||
|
@ -121,7 +121,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Bus" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Bus" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="bus" class="form-control image-format">
|
||||
{% for bus in busses %}
|
||||
|
@ -131,7 +131,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Cache" %}</label>
|
||||
<label class="col-sm-3 control-label">{% trans "Cache" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="cache" class="form-control image-format">
|
||||
{% for mode, name in cache_modes %}
|
||||
|
@ -143,7 +143,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
{% ifequal status 5 %}
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="addexistingvol">{% trans "Add Volume" %}</button>
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_existing_vol">{% trans "Add Volume" %}</button>
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Add Volume" %}</button>
|
||||
{% endifequal %}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
<table class="table table-hover table-striped sortable-theme-bootstrap">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th><a href="#" id="hide_all_instances" onclick="hide_all_host_instances()">#</a> </th>
|
||||
<th>{% trans "Name" %}<br>{% trans "Description" %}</th></th>
|
||||
<th>{% trans "User"%}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "VCPU" %}</th>
|
||||
<th>{% trans "Memory" %}</th>
|
||||
<th data-sortable="false" style="width:205px;">{% trans "Actions & Mem Usage" %}</th>
|
||||
<th style="width:205px;">{% trans "Actions & Mem Usage" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
|
@ -17,7 +17,10 @@
|
|||
<td>
|
||||
<span id="collapse_host_instances_{{ host.1 }}" class="glyphicon glyphicon-chevron-up" onclick="hide_host_instances('{{ host.1 }}');"></span>
|
||||
</td>
|
||||
<td><a href="{% url 'overview' host.0 %}">{{ host.1 }}</a></td>
|
||||
<td>
|
||||
<a href="{% url 'overview' host.0 %}">{{ host.1 }}</a>
|
||||
<span id="inst_count_badge_{{ host.1 }}" class="badge hidden">{{ inst.items|length }}</span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
{% ifequal host.2 1 %}<span class="label label-success">{% trans "Active" %}</span>{% endifequal %}
|
||||
|
@ -124,12 +127,19 @@
|
|||
</table>
|
||||
{% block script %}
|
||||
<script>
|
||||
function hide_all_host_instances() {
|
||||
var rows = $('table tr');
|
||||
all_host_rows = rows.filter('[host]');
|
||||
all_host_rows.toggle();
|
||||
$('span[id^=collapse_host_instances_]').toggleClass("glyphicon-chevron-down").toggleClass("glyphicon-chevron-up");
|
||||
$('span[id^=inst_count_badge_]').toggleClass("hidden");
|
||||
}
|
||||
function hide_host_instances(host) {
|
||||
var rows = $('table tr');
|
||||
|
||||
host_rows = rows.filter("[host='"+host+"']");
|
||||
host_rows.toggle();
|
||||
$("span[id='collapse_host_instances_"+host+"']").toggleClass("glyphicon-chevron-down").toggleClass("glyphicon-chevron-up");
|
||||
$("span[id='inst_count_badge_"+host+"']").toggleClass("hidden");
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<th>Status</th>
|
||||
<th>VCPU</th>
|
||||
<th>Memory</th>
|
||||
<th data-sortable="false" style="width:205px;">Actions</th>
|
||||
<th data-sortable="false" style="width:205px;">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
{% trans "Resize" %}
|
||||
</a>
|
||||
</li>
|
||||
{% if request.user.is_superuser or request.user.is_staff or not userinstance.is_template %}
|
||||
{% if allow_admin_or_not_template %}
|
||||
<li role="presentation">
|
||||
<a href="#snapshots" class="action-button" aria-controls="snapshots" role="tab" data-toggle="tab">
|
||||
<span id="action-block" class="glyphicon glyphicon-camera" aria-hidden="true"></span>
|
||||
|
@ -416,7 +416,7 @@
|
|||
{% ifequal status 5 %}
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="resize">{% trans "Resize" %}</button>
|
||||
{% else %}
|
||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Resize" %}</button>
|
||||
<button class="btn btn-lg btn-success pull-right disabled" name="resize">{% trans "Resize" %}</button>
|
||||
{% endifequal %}
|
||||
</form>
|
||||
{% else %}
|
||||
|
@ -594,10 +594,30 @@
|
|||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane tab-pane-bordered active" id="media">
|
||||
{% if request.user.is_superuser and status == 5 %}
|
||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="submit" name="add_cdrom" type="button" class="btn btn-success pull-right">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% for cd in media %}
|
||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{% trans "CDROM" %} {{ forloop.counter }}</label>
|
||||
<a class="col-sm-2 control-label"
|
||||
name="details"
|
||||
title="{% trans "Details" %}"
|
||||
tabindex="0"
|
||||
data-trigger="focus"
|
||||
data-toggle="popover"
|
||||
data-html="true"
|
||||
data-content="<strong>Bus:</strong> {{ cd.bus }} <br/> <strong>Dev:</strong> {{ cd.dev }}">
|
||||
{% trans "CDROM" %} {{ forloop.counter }}
|
||||
</a>
|
||||
{% if not cd.image %}
|
||||
<div class="col-sm-6">
|
||||
<select name="media" class="form-control">
|
||||
|
@ -611,19 +631,22 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
{% if media_iso and request.user.is_superuser or request.user.is_staff or not userinstance.is_template %}
|
||||
{% if media_iso and allow_admin_or_not_template %}
|
||||
<button type="submit" class="btn btn-sm btn-success pull-left" name="mount_iso" value="{{ cd.dev }}" style="margin-top: 2px;">{% trans "Mount" %}</button>
|
||||
{% if status == 5 %}
|
||||
<button type="submit" class="btn btn-sm btn-danger pull-left" name="detach_cdrom" value="{{ cd.dev }}" style="margin-top: 2px;"><i class="glyphicon glyphicon-remove-circle"></i></button>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-success pull-left disabled" name="mount_iso" style="margin-top: 2px;">{% trans "Mount" %}</button>
|
||||
<button class="btn btn-sm btn-success pull-left disabled" style="margin-top: 2px;">{% trans "Mount" %}</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-sm-5">
|
||||
<p>{{ cd.image }}</p>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control" value="{{ cd.image }}" disabled/>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<input type="hidden" name="path" value="{{ cd.path }}">
|
||||
{% if request.user.is_superuser or request.user.is_staff or not userinstance.is_template %}
|
||||
{% if allow_admin_or_not_template %}
|
||||
<button type="submit" class="btn btn-sm btn-success pull-left" value="{{ cd.dev }}" name="umount_iso" style="margin-top: 2px;">{% trans "Umount" %}</button>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-success pull-left disabled" value="{{ cd.dev }}" name="umount_iso" style="margin-top: 2px;">{% trans "Umount" %}</button>
|
||||
|
@ -677,18 +700,20 @@
|
|||
<form action="" method="post" style="height:10px" role="form">{% csrf_token %}
|
||||
<input type="hidden" name="path" value="{{ disk.path }}">
|
||||
<input type="hidden" name="dev" value="{{ disk.dev }}">
|
||||
<input type="hidden" name="storage" value="{{ disk.storage }}">
|
||||
<input type="hidden" name="name" value="{{ disk.image }}">
|
||||
{% ifequal status 5 %}
|
||||
<button type="submit" class="btn btn-sm btn-default" name="detachvolume" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume?" %}')">
|
||||
<button type="submit" class="btn btn-sm btn-default" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume?" %}')">
|
||||
<i class="fa fa-eject"></i>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-sm btn-default" name="delvolume" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure to delete volume?" %}')">
|
||||
<button type="submit" class="btn btn-sm btn-default" name="delete_vol" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure to delete volume?" %}')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-default disabled" name="detachvolume" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume after shutdown?" %}')">
|
||||
<button class="btn btn-sm btn-default disabled" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure to detach volume after shutdown?" %}')">
|
||||
<i class="fa fa-eject"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" name="delvolume" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure to delete after shutdown?" %}')">
|
||||
<button class="btn btn-sm btn-default disabled" name="delete_vol" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure to delete after shutdown?" %}')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
|
@ -1243,13 +1268,20 @@
|
|||
{% block script %}
|
||||
<script src="{% static "js/ace.js" %}" type="text/javascript" charset="utf-8"></script>
|
||||
<script>
|
||||
function get_volumes(comp_id, pool) {
|
||||
vol_url = "/computes/" + comp_id + "/storage/" + pool + "/?get_volumes";
|
||||
var select = document.getElementById("vols");
|
||||
function get_volumes(compute_id, pool) {
|
||||
|
||||
while (select.options.length){
|
||||
select.removeChild(select.options[0]);
|
||||
}
|
||||
|
||||
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
||||
$.getJSON(get_vol_url, function (data) {
|
||||
$("#vols").find('option').remove();
|
||||
$("#vols").removeAttr("disabled");
|
||||
|
||||
$.each(data['vols'], function(i, item) {
|
||||
$("#vols").append('<option value=' + item +'>' + item + '</option>');
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var sto_drop = document.getElementById('select_storage');
|
||||
sto_drop.value = pool;
|
||||
|
@ -1259,22 +1291,6 @@
|
|||
sto_input.value = pool;
|
||||
sto_input.innerHTML = pool;
|
||||
|
||||
$.getJSON(vol_url, function(data) {
|
||||
if (data.length > 0) {
|
||||
select.disabled = false;
|
||||
}
|
||||
var opt = document.createElement('option');
|
||||
opt.value = '';
|
||||
opt.innerHTML = 'None';
|
||||
select.appendChild(opt);
|
||||
for (i = 0; i < data.length; i++){
|
||||
var opt = document.createElement('option');
|
||||
opt.value = data[i]['name'];
|
||||
opt.innerHTML = data[i]['name'];
|
||||
select.appendChild(opt);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1420,6 +1436,13 @@
|
|||
});
|
||||
{% endif %}
|
||||
</script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('[data-toggle="popover"]').popover({
|
||||
placement : 'top'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$(function () {
|
||||
$('.js-custom__checkbox').change(function () {
|
||||
|
@ -1640,12 +1663,5 @@
|
|||
$("#logs_table > tbody").html(logs);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$('[data-toggle="popover"]').popover({
|
||||
placement : 'top'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -197,12 +197,18 @@ def instance(request, compute_id, vname):
|
|||
def get_new_disk_dev(disks, bus):
|
||||
if bus == "virtio":
|
||||
dev_base = "vd"
|
||||
elif bus == "ide":
|
||||
dev_base = "hd"
|
||||
elif bus == "fdc":
|
||||
dev_base = "fd"
|
||||
else:
|
||||
dev_base = "sd"
|
||||
existing_devs = [disk['dev'] for disk in disks]
|
||||
existing_disk_devs = [disk['dev'] for disk in disks]
|
||||
# cd-rom bus could be virtio/sata, because of that we should check it also
|
||||
existing_media_devs = [disk['dev'] for disk in media]
|
||||
for l in string.lowercase:
|
||||
dev = dev_base + l
|
||||
if dev not in existing_devs:
|
||||
if dev not in existing_disk_devs and dev not in existing_media_devs:
|
||||
return dev
|
||||
raise Exception(_('None available device name'))
|
||||
|
||||
|
@ -265,7 +271,7 @@ def instance(request, compute_id, vname):
|
|||
networks = conn.get_net_device()
|
||||
|
||||
vcpu_range = conn.get_max_cpus()
|
||||
memory_range = [256, 512, 768, 1024, 2048, 4096, 6144, 8192, 16384]
|
||||
memory_range = [256, 512, 768, 1024, 2048, 3072, 4096, 6144, 8192, 16384]
|
||||
if memory not in memory_range:
|
||||
insort(memory_range, memory)
|
||||
if cur_memory not in memory_range:
|
||||
|
@ -290,7 +296,7 @@ def instance(request, compute_id, vname):
|
|||
default_owner = settings.INSTANCE_VOLUME_DEFAULT_OWNER
|
||||
formats = conn.get_image_formats()
|
||||
|
||||
busses = conn.get_busses()
|
||||
busses = conn.get_disk_bus_types()
|
||||
default_bus = settings.INSTANCE_VOLUME_DEFAULT_BUS
|
||||
show_access_root_password = settings.SHOW_ACCESS_ROOT_PASSWORD
|
||||
show_access_ssh_keys = settings.SHOW_ACCESS_SSH_KEYS
|
||||
|
@ -310,6 +316,7 @@ def instance(request, compute_id, vname):
|
|||
addlogmsg(request.user.username, instance.name, msg)
|
||||
|
||||
userinstances = UserInstance.objects.filter(instance=instance).order_by('user__username')
|
||||
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'poweron' in request.POST:
|
||||
|
@ -444,7 +451,7 @@ def instance(request, compute_id, vname):
|
|||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
||||
|
||||
if 'addnewvol' in request.POST and (request.user.is_superuser or userinstance.is_change):
|
||||
if 'add_new_vol' in request.POST and allow_admin_or_not_template:
|
||||
connCreate = wvmCreate(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
|
@ -460,11 +467,11 @@ def instance(request, compute_id, vname):
|
|||
|
||||
path = connCreate.create_volume(storage, name, size, format, meta_prealloc, default_owner)
|
||||
conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus)
|
||||
msg = _('Attach new disk')
|
||||
msg = _('Attach new disk: ' + target)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
||||
if 'addexistingvol' in request.POST and (request.user.is_superuser or userinstance.is_change):
|
||||
if 'add_existing_vol' in request.POST and allow_admin_or_not_template:
|
||||
storage = request.POST.get('selected_storage', '')
|
||||
name = request.POST.get('vols', '')
|
||||
bus = request.POST.get('bus', default_bus)
|
||||
|
@ -482,68 +489,83 @@ def instance(request, compute_id, vname):
|
|||
source = path + "/" + name;
|
||||
|
||||
conn.attach_disk(source, target, subdriver=format, cache=cache, targetbus=bus)
|
||||
msg = _('Attach Existing disk')
|
||||
msg = _('Attach Existing disk: ' + target)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
||||
if 'delvolume' in request.POST and (request.user.is_superuser or userinstance.is_change):
|
||||
connDelete = wvmCreate(compute.hostname,
|
||||
if 'delete_vol' in request.POST and allow_admin_or_not_template:
|
||||
storage = request.POST.get('storage', '')
|
||||
connDelete = wvmStorage(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
compute.type,
|
||||
storage)
|
||||
dev = request.POST.get('dev', '')
|
||||
path = request.POST.get('path', '')
|
||||
name = request.POST.get('name', '')
|
||||
|
||||
conn.detach_disk(dev, path)
|
||||
connDelete.delete_volume(path)
|
||||
conn.detach_disk(dev)
|
||||
connDelete.del_volume(name)
|
||||
|
||||
msg = _('Delete disk')
|
||||
msg = _('Delete disk: ' + dev)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
||||
if 'detachvolume' in request.POST and (request.user.is_superuser or userinstance.is_change):
|
||||
connDelete = wvmCreate(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
dev = request.POST.get('dev', '')
|
||||
if 'detach_vol' in request.POST and allow_admin_or_not_template:
|
||||
dev = request.POST.get('detach_vol', '')
|
||||
path = request.POST.get('path', '')
|
||||
conn.detach_disk(dev, path)
|
||||
msg = _('Detach disk')
|
||||
conn.detach_disk(dev)
|
||||
msg = _('Detach disk: ' + dev)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
||||
if 'umount_iso' in request.POST and (request.user.is_superuser or request.user.is_staff or not userinstance.is_template):
|
||||
if 'add_cdrom' in request.POST and allow_admin_or_not_template:
|
||||
bus = request.POST.get('bus', 'ide')
|
||||
target = get_new_disk_dev(media, bus)
|
||||
conn.attach_disk("", target, device='cdrom', cache='none', targetbus=bus)
|
||||
msg = _('Add CD-Rom: ' + target)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
||||
|
||||
if 'detach_cdrom' in request.POST and allow_admin_or_not_template:
|
||||
dev = request.POST.get('detach_cdrom', '')
|
||||
path = request.POST.get('path', '')
|
||||
conn.detach_disk(dev)
|
||||
msg = _('Detach CD-Rom: ' + dev)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
||||
|
||||
if 'umount_iso' in request.POST and allow_admin_or_not_template:
|
||||
image = request.POST.get('path', '')
|
||||
dev = request.POST.get('umount_iso', '')
|
||||
conn.umount_iso(dev, image)
|
||||
msg = _("Mount media")
|
||||
msg = _("Mount media: " + dev)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
||||
|
||||
if 'mount_iso' in request.POST and (request.user.is_superuser or request.user.is_staff or not userinstance.is_template):
|
||||
if 'mount_iso' in request.POST and allow_admin_or_not_template:
|
||||
image = request.POST.get('media', '')
|
||||
dev = request.POST.get('mount_iso', '')
|
||||
conn.mount_iso(dev, image)
|
||||
msg = _("Umount media")
|
||||
msg = _("Umount media: " + dev)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#media')
|
||||
|
||||
if 'snapshot' in request.POST and (request.user.is_superuser or request.user.is_staff or not userinstance.is_template):
|
||||
if 'snapshot' in request.POST and allow_admin_or_not_template:
|
||||
name = request.POST.get('name', '')
|
||||
conn.create_snapshot(name)
|
||||
msg = _("New snapshot")
|
||||
msg = _("New snapshot :" + name)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#managesnapshot')
|
||||
|
||||
if 'delete_snapshot' in request.POST and (request.user.is_superuser or request.user.is_staff or not userinstance.is_template):
|
||||
if 'delete_snapshot' in request.POST and allow_admin_or_not_template:
|
||||
snap_name = request.POST.get('name', '')
|
||||
conn.snapshot_delete(snap_name)
|
||||
msg = _("Delete snapshot")
|
||||
msg = _("Delete snapshot :" + snap_name)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#managesnapshot')
|
||||
|
||||
if 'revert_snapshot' in request.POST and (request.user.is_superuser or request.user.is_staff or not userinstance.is_template):
|
||||
if 'revert_snapshot' in request.POST and allow_admin_or_not_template:
|
||||
snap_name = request.POST.get('name', '')
|
||||
conn.snapshot_revert(snap_name)
|
||||
msg = _("Successful revert snapshot: ")
|
||||
|
|
39
static/css/bootstrap-multiselect.css
vendored
39
static/css/bootstrap-multiselect.css
vendored
|
@ -1,38 +1 @@
|
|||
|
||||
.multiselect-container {
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.multiselect-container .input-group {
|
||||
margin: 5px;
|
||||
}
|
||||
.multiselect-container > li {
|
||||
padding: 0;
|
||||
}
|
||||
.multiselect-container > li > a.multiselect-all label {
|
||||
font-weight: bold;
|
||||
}
|
||||
.multiselect-container > li > label.multiselect-group {
|
||||
margin: 0;
|
||||
padding: 3px 20px 3px 20px;
|
||||
height: 100%;
|
||||
}
|
||||
.multiselect-container > li > a > label {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
font-weight: normal;
|
||||
}
|
||||
.multiselect-container > li > a > label.radio,
|
||||
.multiselect-container > li > a > label.checkbox {
|
||||
margin: 0;
|
||||
}
|
||||
.multiselect-container > li > a > label > input[type="checkbox"] {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.btn-group > .btn-group:nth-child(2) > .multiselect.btn {
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
span.multiselect-native-select{position:relative}span.multiselect-native-select select{border:0!important;clip:rect(0 0 0 0)!important;height:1px!important;margin:-1px -1px -1px -3px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;left:50%;top:30px}.multiselect-container{position:absolute;list-style-type:none;margin:0;padding:0}.multiselect-container .input-group{margin:5px}.multiselect-container .multiselect-reset .input-group{width:93%}.multiselect-container>li{padding:0}.multiselect-container>li>a.multiselect-all label{font-weight:700}.multiselect-container>li.multiselect-group label{margin:0;padding:3px 20px;height:100%;font-weight:700}.multiselect-container>li.multiselect-group-clickable label{cursor:pointer}.multiselect-container>li>a{padding:0}.multiselect-container>li>a>label{margin:0;height:100%;cursor:pointer;font-weight:400;padding:3px 20px 3px 40px}.multiselect-container>li>a>label.checkbox,.multiselect-container>li>a>label.radio{margin:0}.multiselect-container>li>a>label>input[type=checkbox]{margin-bottom:5px}.btn-group>.btn-group:nth-child(2)>.multiselect.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.form-inline .multiselect-container label.checkbox,.form-inline .multiselect-container label.radio{padding:3px 20px 3px 40px}.form-inline .multiselect-container li a label.checkbox input[type=checkbox],.form-inline .multiselect-container li a label.radio input[type=radio]{margin-left:-20px;margin-right:0}
|
6
static/js/Chart.min.js
vendored
6
static/js/Chart.min.js
vendored
File diff suppressed because one or more lines are too long
1559
static/js/bootstrap-multiselect.js
vendored
1559
static/js/bootstrap-multiselect.js
vendored
File diff suppressed because it is too large
Load diff
|
@ -205,12 +205,23 @@ def storage(request, compute_id, pool):
|
|||
else:
|
||||
for msg_err in form.errors.values():
|
||||
error_messages.append(msg_err.as_text())
|
||||
if request.method == 'GET':
|
||||
if 'get_volumes' in request.GET:
|
||||
conn.close()
|
||||
return HttpResponse(json.dumps(sorted(volumes)))
|
||||
|
||||
conn.close()
|
||||
|
||||
return render(request, 'storage.html', locals())
|
||||
|
||||
|
||||
@login_required
|
||||
def get_volumes(request, compute_id, pool):
|
||||
data = {}
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
try:
|
||||
conn = wvmStorage(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
pool)
|
||||
except libvirtError as liberr:
|
||||
pass
|
||||
data['vols'] = sorted(conn.get_volumes())
|
||||
return HttpResponse(json.dumps(data))
|
|
@ -361,6 +361,24 @@ class wvmConnect(object):
|
|||
virttype = self.hypervisor_type()[arch][0]
|
||||
return self.wvm.getDomainCapabilities(emulatorbin, arch, machine, virttype)
|
||||
|
||||
def get_version(self):
|
||||
ver = self.wvm.getVersion()
|
||||
major = ver / 1000000
|
||||
ver = ver % 1000000
|
||||
minor = ver / 1000
|
||||
ver = ver % 1000
|
||||
release = ver
|
||||
return "%s.%s.%s" % (major,minor,release)
|
||||
|
||||
def get_lib_version(self):
|
||||
ver = self.wvm.getLibVersion()
|
||||
major = ver / 1000000
|
||||
ver %= 1000000
|
||||
minor = ver / 1000
|
||||
ver %= 1000
|
||||
release = ver
|
||||
return "%s.%s.%s" % (major,minor,release)
|
||||
|
||||
def is_kvm_supported(self):
|
||||
"""Return KVM capabilities."""
|
||||
return util.is_kvm_available(self.get_cap_xml())
|
||||
|
@ -436,8 +454,8 @@ class wvmConnect(object):
|
|||
""" Return machine type of emulation"""
|
||||
return util.get_xml_path(self.get_cap_xml(), "/capabilities/guest/arch[@name='{}']/machine".format(arch))
|
||||
|
||||
def get_busses(self):
|
||||
"""Get available busses"""
|
||||
def get_disk_bus_types(self):
|
||||
"""Get available disk bus types list"""
|
||||
|
||||
def get_bus_list(ctx):
|
||||
result = []
|
||||
|
@ -449,6 +467,18 @@ class wvmConnect(object):
|
|||
# return [ 'ide', 'scsi', 'usb', 'virtio' ]
|
||||
return util.get_xml_path(self.get_dom_cap_xml(), func=get_bus_list)
|
||||
|
||||
def get_disk_device_types(self):
|
||||
"""Get available disk device type list"""
|
||||
|
||||
def get_device_list(ctx):
|
||||
result = []
|
||||
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 util.get_xml_path(self.get_dom_cap_xml(), func=get_device_list)
|
||||
|
||||
def get_image_formats(self):
|
||||
"""Get available image formats"""
|
||||
|
|
|
@ -93,7 +93,7 @@ class wvmCreate(wvmConnect):
|
|||
def get_volume_type(self, path):
|
||||
vol = self.get_volume_by_path(path)
|
||||
vol_type = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||
if vol_type == 'unknown':
|
||||
if vol_type == 'unknown' or vol_type == 'iso':
|
||||
return 'raw'
|
||||
if vol_type:
|
||||
return vol_type
|
||||
|
@ -154,7 +154,7 @@ class wvmCreate(wvmConnect):
|
|||
vol = self.get_volume_by_path(path)
|
||||
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):
|
||||
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):
|
||||
"""
|
||||
Create VM function
|
||||
"""
|
||||
|
@ -189,11 +189,18 @@ class wvmCreate(wvmConnect):
|
|||
<on_crash>restart</on_crash>
|
||||
<devices>"""
|
||||
|
||||
disk_letters = list(string.lowercase)
|
||||
for image, img_type in images.items():
|
||||
stg = self.get_storage_by_vol_path(image)
|
||||
vd_disk_letters = list(string.lowercase)
|
||||
fd_disk_letters = list(string.lowercase)
|
||||
hd_disk_letters = list(string.lowercase)
|
||||
sd_disk_letters = list(string.lowercase)
|
||||
add_cd = True
|
||||
#for image, img_type in images.items():
|
||||
for volume in images:
|
||||
stg = self.get_storage_by_vol_path(volume['path'])
|
||||
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
|
||||
|
||||
if volume['device'] == 'cdrom': add_cd = False
|
||||
|
||||
if stg_type == 'rbd':
|
||||
ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg)
|
||||
xml += """<disk type='network' device='disk'>
|
||||
|
@ -201,7 +208,7 @@ class wvmCreate(wvmConnect):
|
|||
<auth username='%s'>
|
||||
<secret type='ceph' uuid='%s'/>
|
||||
</auth>
|
||||
<source protocol='rbd' name='%s'>""" % (img_type, cache_mode, ceph_user, secret_uuid, image)
|
||||
<source protocol='rbd' name='%s'>""" % (volume['type'], cache_mode, ceph_user, secret_uuid, volume['path'])
|
||||
if isinstance(ceph_hosts, list):
|
||||
for host in ceph_hosts:
|
||||
if host.get('port'):
|
||||
|
@ -213,23 +220,26 @@ class wvmCreate(wvmConnect):
|
|||
xml += """
|
||||
</source>"""
|
||||
else:
|
||||
xml += """<disk type='file' device='disk'>
|
||||
xml += """<disk type='file' device='%s'>
|
||||
<driver name='qemu' type='%s' cache='%s'/>
|
||||
<source file='%s'/>""" % (img_type, cache_mode, image)
|
||||
<source file='%s'/>""" % (volume['device'], volume['type'], cache_mode, volume['path'])
|
||||
|
||||
if virtio:
|
||||
xml += """<target dev='vd%s' bus='virtio'/>""" % (disk_letters.pop(0),)
|
||||
if volume['bus'] == 'virtio':
|
||||
xml += """<target dev='vd%s' bus='%s'/>""" % (vd_disk_letters.pop(0), volume['bus'])
|
||||
elif volume['bus'] == 'ide':
|
||||
xml += """<target dev='hd%s' bus='%s'/>""" % (hd_disk_letters.pop(0), volume['bus'])
|
||||
elif volume['bus'] == 'fdc':
|
||||
xml += """<target dev='fd%s' bus='%s'/>""" % (fd_disk_letters.pop(0), volume['bus'])
|
||||
else:
|
||||
xml += """<target dev='sd%s' bus='ide'/>""" % (disk_letters.pop(0),)
|
||||
xml += """<target dev='sd%s' bus='%s'/>""" % (sd_disk_letters.pop(0), volume['bus'])
|
||||
xml += """</disk>"""
|
||||
|
||||
if add_cd:
|
||||
xml += """ <disk type='file' device='cdrom'>
|
||||
<driver name='qemu' type='raw'/>
|
||||
<source file=''/>
|
||||
<target dev='hda' bus='ide'/>
|
||||
<target dev='hd%s' bus='ide'/>
|
||||
<readonly/>
|
||||
<address type='drive' controller='0' bus='1' target='0' unit='1'/>
|
||||
</disk>"""
|
||||
</disk>""" % (hd_disk_letters.pop(0),)
|
||||
for net in networks.split(','):
|
||||
xml += """<interface type='network'>"""
|
||||
if mac:
|
||||
|
@ -250,11 +260,21 @@ class wvmCreate(wvmConnect):
|
|||
xml += """ <input type='mouse' bus='ps2'/>
|
||||
<input type='tablet' bus='usb'/>
|
||||
<graphics type='%s' port='-1' autoport='yes' %s listen='%s'/>
|
||||
<console type='pty'/>
|
||||
<video>
|
||||
<console type='pty'/> """ % (QEMU_CONSOLE_DEFAULT_TYPE, console_pass, listen_addr)
|
||||
|
||||
if qemu_ga:
|
||||
xml += """ <channel type='unix'>
|
||||
<target type='virtio' name='org.qemu.guest_agent.0'/>
|
||||
</channel>"""
|
||||
|
||||
xml += """ <video>
|
||||
<model type='%s'/>
|
||||
</video>
|
||||
<memballoon model='virtio'/>
|
||||
</devices>
|
||||
</domain>""" % (QEMU_CONSOLE_DEFAULT_TYPE, console_pass, listen_addr, video)
|
||||
</domain>""" % video
|
||||
|
||||
|
||||
|
||||
|
||||
self._defineXML(xml)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import time
|
||||
import os.path
|
||||
try:
|
||||
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE, VIR_MIGRATE_UNSAFE
|
||||
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE, VIR_MIGRATE_UNSAFE, VIR_DOMAIN_RUNNING, \
|
||||
VIR_DOMAIN_AFFECT_LIVE, VIR_DOMAIN_AFFECT_CONFIG
|
||||
except:
|
||||
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE
|
||||
from vrtManager import util
|
||||
|
@ -252,6 +253,7 @@ class wvmInstance(wvmConnect):
|
|||
storage = None
|
||||
src_fl = None
|
||||
disk_format = None
|
||||
used_size = None
|
||||
disk_size = None
|
||||
|
||||
for disk in doc.xpath('/domain/devices/disk'):
|
||||
|
@ -297,6 +299,7 @@ class wvmInstance(wvmConnect):
|
|||
if device == 'cdrom':
|
||||
try:
|
||||
dev = media.xpath('target/@dev')[0]
|
||||
bus = media.xpath('target/@bus')[0]
|
||||
try:
|
||||
src_fl = media.xpath('source/@file')[0]
|
||||
vol = self.get_volume_by_path(src_fl)
|
||||
|
@ -309,7 +312,7 @@ class wvmInstance(wvmConnect):
|
|||
except:
|
||||
pass
|
||||
finally:
|
||||
result.append({'dev': dev, 'image': volume, 'storage': storage, 'path': src_fl})
|
||||
result.append({'dev': dev, 'image': volume, 'storage': storage, 'path': src_fl, 'bus': bus})
|
||||
return result
|
||||
|
||||
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
||||
|
@ -363,7 +366,7 @@ class wvmInstance(wvmConnect):
|
|||
xmldom = ElementTree.tostring(tree)
|
||||
self._defineXML(xmldom)
|
||||
|
||||
def attach_disk(self, source, target, sourcetype='file', type='disk', driver='qemu', subdriver='raw', cache='none', targetbus='ide'):
|
||||
def attach_disk(self, source, target, sourcetype='file', device='disk', driver='qemu', subdriver='raw', cache='none', targetbus='ide'):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
xml_disk = """
|
||||
<disk type='%s' device='%s'>
|
||||
|
@ -371,7 +374,7 @@ class wvmInstance(wvmConnect):
|
|||
<source file='%s'/>
|
||||
<target dev='%s' bus='%s'/>
|
||||
</disk>
|
||||
""" % (sourcetype, type, driver, subdriver, cache, source, target, targetbus)
|
||||
""" % (sourcetype, device, driver, subdriver, cache, source, target, targetbus)
|
||||
if self.get_status() == 5:
|
||||
devices = tree.find('devices')
|
||||
elm_disk = ElementTree.fromstring(xml_disk)
|
||||
|
@ -379,19 +382,18 @@ class wvmInstance(wvmConnect):
|
|||
xmldom = ElementTree.tostring(tree)
|
||||
self._defineXML(xmldom)
|
||||
|
||||
def detach_disk(self, dev, image):
|
||||
def detach_disk(self, dev):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
|
||||
for disk in tree.findall("./devices/disk[@device='disk']"):
|
||||
source = disk.find("source")
|
||||
for disk in tree.findall("./devices/disk"):
|
||||
target = disk.find("target")
|
||||
if source.get("file") == image and target.get("dev") == dev:
|
||||
if target.get("dev") == dev:
|
||||
devices = tree.find('devices')
|
||||
devices.remove(disk)
|
||||
|
||||
if self.get_status() == 1:
|
||||
xml_disk = ElementTree.tostring(disk)
|
||||
yyy = self.instance.detachDevice(xml_disk)
|
||||
ret = self.instance.detachDevice(xml_disk)
|
||||
xmldom = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||
if self.get_status() == 5:
|
||||
xmldom = ElementTree.tostring(tree)
|
||||
|
@ -613,8 +615,14 @@ class wvmInstance(wvmConnect):
|
|||
"""
|
||||
Function change ram and cpu on vds.
|
||||
"""
|
||||
|
||||
memory = int(memory) * 1024
|
||||
cur_memory = int(cur_memory) * 1024
|
||||
# if dom is running change only ram
|
||||
if self.get_status() == VIR_DOMAIN_RUNNING:
|
||||
self.set_memory(cur_memory, VIR_DOMAIN_AFFECT_LIVE)
|
||||
self.set_memory(cur_memory, VIR_DOMAIN_AFFECT_CONFIG)
|
||||
return
|
||||
|
||||
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||
tree = ElementTree.fromstring(xml)
|
||||
|
@ -905,3 +913,6 @@ class wvmInstance(wvmConnect):
|
|||
new_xml = ElementTree.tostring(tree)
|
||||
self._defineXML(new_xml)
|
||||
|
||||
def set_memory(self, size, flags=0):
|
||||
self.instance.setMemoryFlags(size, flags)
|
||||
|
||||
|
|
Loading…
Reference in a new issue