mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-24 15:15:22 +00:00
Add 'Adding, deleting and detaching disk volumes' to instances
This commit is contained in:
parent
8f5cc5755a
commit
ea5e9cfead
4 changed files with 123 additions and 92 deletions
|
@ -1,5 +1,5 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% if request.user.is_superuser and status == 5 %}
|
{% if request.user.is_superuser %}
|
||||||
<a href="#addvol" type="button" class="btn btn-success pull-right" data-toggle="modal">
|
<a href="#addvol" type="button" class="btn btn-success 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>
|
||||||
|
|
|
@ -342,11 +342,6 @@
|
||||||
{% trans "Resize Instance" %}
|
{% trans "Resize Instance" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="presentation">
|
|
||||||
<a href="#addvolume" aria-controls="addvolume" role="tab" data-toggle="tab">
|
|
||||||
{% trans "Add New Volume" %}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<!-- Tab panes -->
|
<!-- Tab panes -->
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -428,81 +423,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="addvolume">
|
|
||||||
{% if request.user.is_superuser or userinstance.is_change %}
|
|
||||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
|
||||||
<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>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<select name="storage" class="form-control image-format">
|
|
||||||
{% for storage in storages %}
|
|
||||||
<option value="{{ storage }}">{{ storage }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% 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>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<select name="format" class="form-control image-format">
|
|
||||||
{% for format in formats %}
|
|
||||||
<option value="{{ format }}" {% if format == default_format %}selected{% endif %}>{% trans format %}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Size" %}</label>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<input type="text" class="form-control" name="size" value="10" maxlength="3" 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>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<select name="bus" class="form-control image-format">
|
|
||||||
{% for bus in busses %}
|
|
||||||
<option value="{{ bus }}" {% if bus == default_bus %}selected{% endif %}>{% trans bus %}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Cache" %}</label>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<select name="cache" class="form-control image-format">
|
|
||||||
{% for mode, name in cache_modes %}
|
|
||||||
<option value="{{ mode }}" {% if mode == default_cache %}selected{% endif %}>{% trans name %}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group meta-prealloc">
|
|
||||||
<label class="col-sm-3 control-label" style="font-weight:normal;">{% trans "Metadata" %}</label>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<input type="checkbox" name="meta_prealloc" value="true">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% ifequal status 5 %}
|
|
||||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="addvolume">{% trans "Add volume" %}</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Add volume" %}</button>
|
|
||||||
{% endifequal %}
|
|
||||||
</form>
|
|
||||||
{% else %}
|
|
||||||
{% trans "You don't have permission for resizing instance" %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Add volume" %}</button>
|
|
||||||
{% endif %}
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -607,6 +528,11 @@
|
||||||
{% trans "Media" %}
|
{% trans "Media" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li role="presentation">
|
||||||
|
<a href="#disks" aria-controls="disks" role="tab" data-toggle="tab">
|
||||||
|
{% trans "Disk" %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<a href="#autostart" aria-controls="autostart" role="tab" data-toggle="tab">
|
<a href="#autostart" aria-controls="autostart" role="tab" data-toggle="tab">
|
||||||
|
@ -614,6 +540,7 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if request.user.is_superuser or userinstance.is_vnc %}
|
{% if request.user.is_superuser or userinstance.is_vnc %}
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<a href="#vncsettings" aria-controls="vncsettings" role="tab" data-toggle="tab">
|
<a href="#vncsettings" aria-controls="vncsettings" role="tab" data-toggle="tab">
|
||||||
|
@ -702,6 +629,64 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="disks">
|
||||||
|
<p style="font-weight:bold;">
|
||||||
|
{% trans "Instance Volumes" %}
|
||||||
|
{% include 'add_instance_volume.html' %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="col-xs-12 col-sm-12">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<th>{% trans "Device" %}</th>
|
||||||
|
<th>{% trans "Format" %}</th>
|
||||||
|
<th>{% trans "Used" %}</th>
|
||||||
|
<th>{% trans "Capacity" %}</th>
|
||||||
|
<th>{% trans "Bus" %}</th>
|
||||||
|
<th>{% trans "Storage" %}</th>
|
||||||
|
<th>{% trans "Source" %}</th>
|
||||||
|
<th style="width:100px;">{% trans "Action" %}</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for disk in disks %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ disk.dev }}<br>{{ disk.target }}</td>
|
||||||
|
<td>{{ disk.format }}</td>
|
||||||
|
<td>{{ disk.used | filesizeformat}}</td>
|
||||||
|
<td>{{ disk.size | filesizeformat }}</td>
|
||||||
|
<td>{{ disk.bus }}</td>
|
||||||
|
<td>{{ disk.storage }}</td>
|
||||||
|
<td>{{ disk.path }}</td>
|
||||||
|
<td style="width:30px;">
|
||||||
|
<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 }}">
|
||||||
|
{% ifequal status 5 %}
|
||||||
|
<button type="submit" class="btn btn-sm btn-default" name="detachvolume" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<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?" %}')">
|
||||||
|
<i class="fa fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="btn btn-sm btn-default disabled" name="detachvolume" title="{% trans "Detach" %}">
|
||||||
|
<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?" %}')">
|
||||||
|
<i class="fa fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
{% endifequal %}
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="autostart">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="autostart">
|
||||||
<p>{% trans "Autostart your instance when host server is power on" %}</p>
|
<p>{% trans "Autostart your instance when host server is power on" %}</p>
|
||||||
|
@ -884,9 +869,6 @@
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
@ -950,7 +932,7 @@
|
||||||
<input id="disk_name-{{ disk.dev }}" type="text" class="form-control" name="disk-{{ disk.dev }}" value="{{ disk.image }}"/>
|
<input id="disk_name-{{ disk.dev }}" type="text" class="form-control" name="disk-{{ disk.dev }}" value="{{ disk.image }}"/>
|
||||||
</div>
|
</div>
|
||||||
{% ifequal disk.format 'qcow2' %}
|
{% ifequal disk.format 'qcow2' %}
|
||||||
<label class="col-sm-2 control-label" style="font-weight:normal;margin-left:-35px;">Metadata</label>
|
<label class="col-sm-2 control-label" style="font-weight:normal;margin-left:-35px;">{% trans 'Metadata' %}</label>
|
||||||
<div class="col-sm-1">
|
<div class="col-sm-1">
|
||||||
<input type="checkbox" name="meta-{{ disk.dev }}" value="true" style="margin-top: 10px;">
|
<input type="checkbox" name="meta-{{ disk.dev }}" value="true" style="margin-top: 10px;">
|
||||||
</div>
|
</div>
|
||||||
|
@ -1561,7 +1543,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (~$.inArray(hash, ['#media', '#network', '#clone', '#autostart', '#xmledit', '#vncsettings', '#migrate', '#options', '#users'])) {
|
if (~$.inArray(hash, ['#media', "#disks", '#network', '#clone', '#autostart', '#xmledit', '#vncsettings', '#migrate', '#options', '#users'])) {
|
||||||
var btnsect = $('#navbtn>li>a');
|
var btnsect = $('#navbtn>li>a');
|
||||||
$(btnsect).each(function () {
|
$(btnsect).each(function () {
|
||||||
if ($(this).attr('href') === '#settings') {
|
if ($(this).attr('href') === '#settings') {
|
||||||
|
|
|
@ -342,7 +342,7 @@ def instance(request, compute_id, vname):
|
||||||
if request.POST.get('delete_disk', ''):
|
if request.POST.get('delete_disk', ''):
|
||||||
for snap in snapshots:
|
for snap in snapshots:
|
||||||
conn.snapshot_delete(snap['name'])
|
conn.snapshot_delete(snap['name'])
|
||||||
conn.delete_disk()
|
conn.delete_all_disks()
|
||||||
conn.delete()
|
conn.delete()
|
||||||
|
|
||||||
instance = Instance.objects.get(compute_id=compute_id, name=vname)
|
instance = Instance.objects.get(compute_id=compute_id, name=vname)
|
||||||
|
@ -457,7 +457,34 @@ def instance(request, compute_id, vname):
|
||||||
conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus)
|
conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus)
|
||||||
msg = _('Attach new disk')
|
msg = _('Attach new disk')
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
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,
|
||||||
|
compute.login,
|
||||||
|
compute.password,
|
||||||
|
compute.type)
|
||||||
|
dev = request.POST.get('dev', '')
|
||||||
|
path = request.POST.get('path', '')
|
||||||
|
|
||||||
|
conn.detach_disk(dev, path)
|
||||||
|
connDelete.delete_volume(path)
|
||||||
|
|
||||||
|
msg = _('Delete disk')
|
||||||
|
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', '')
|
||||||
|
path = request.POST.get('path', '')
|
||||||
|
conn.detach_disk(dev, path)
|
||||||
|
msg = _('Detach disk')
|
||||||
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
|
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||||
|
|
||||||
if 'umount_iso' in request.POST:
|
if 'umount_iso' in request.POST:
|
||||||
image = request.POST.get('path', '')
|
image = request.POST.get('path', '')
|
||||||
|
@ -1154,7 +1181,7 @@ def delete_instance(instance, delete_disk=False):
|
||||||
print("Deleting snapshot {}".format(snap['name']))
|
print("Deleting snapshot {}".format(snap['name']))
|
||||||
conn.snapshot_delete(snap['name'])
|
conn.snapshot_delete(snap['name'])
|
||||||
print("Deleting disks")
|
print("Deleting disks")
|
||||||
conn.delete_disk()
|
conn.delete_all_disks()
|
||||||
|
|
||||||
conn.delete()
|
conn.delete()
|
||||||
instance.delete()
|
instance.delete()
|
||||||
|
|
|
@ -259,6 +259,7 @@ class wvmInstance(wvmConnect):
|
||||||
if device == 'disk':
|
if device == 'disk':
|
||||||
try:
|
try:
|
||||||
dev = disk.xpath('target/@dev')[0]
|
dev = disk.xpath('target/@dev')[0]
|
||||||
|
bus = disk.xpath('target/@bus')[0]
|
||||||
src_fl = disk.xpath('source/@file|source/@dev|source/@name|source/@volume')[0]
|
src_fl = disk.xpath('source/@file|source/@dev|source/@name|source/@volume')[0]
|
||||||
try:
|
try:
|
||||||
disk_format = disk.xpath('driver/@type')[0]
|
disk_format = disk.xpath('driver/@type')[0]
|
||||||
|
@ -267,7 +268,9 @@ class wvmInstance(wvmConnect):
|
||||||
try:
|
try:
|
||||||
vol = self.get_volume_by_path(src_fl)
|
vol = self.get_volume_by_path(src_fl)
|
||||||
volume = vol.name()
|
volume = vol.name()
|
||||||
|
|
||||||
disk_size = vol.info()[1]
|
disk_size = vol.info()[1]
|
||||||
|
used_size = vol.info()[2]
|
||||||
stg = vol.storagePoolLookupByVolume()
|
stg = vol.storagePoolLookupByVolume()
|
||||||
storage = stg.name()
|
storage = stg.name()
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
|
@ -276,8 +279,8 @@ class wvmInstance(wvmConnect):
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
result.append(
|
result.append(
|
||||||
{'dev': dev, 'image': volume, 'storage': storage, 'path': src_fl,
|
{'dev': dev, 'bus': bus, 'image': volume, 'storage': storage, 'path': src_fl,
|
||||||
'format': disk_format, 'size': disk_size})
|
'format': disk_format, 'size': disk_size, 'used': used_size})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
return util.get_xml_path(self._XMLDesc(0), func=disks)
|
||||||
|
@ -376,6 +379,25 @@ class wvmInstance(wvmConnect):
|
||||||
xmldom = ElementTree.tostring(tree)
|
xmldom = ElementTree.tostring(tree)
|
||||||
self._defineXML(xmldom)
|
self._defineXML(xmldom)
|
||||||
|
|
||||||
|
def detach_disk(self, dev, image):
|
||||||
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
|
||||||
|
for disk in tree.findall("./devices/disk[@device='disk']"):
|
||||||
|
source = disk.find("source")
|
||||||
|
target = disk.find("target")
|
||||||
|
if source.get("file") == image and 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)
|
||||||
|
xmldom = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||||
|
if self.get_status() == 5:
|
||||||
|
xmldom = ElementTree.tostring(tree)
|
||||||
|
break
|
||||||
|
self._defineXML(xmldom)
|
||||||
|
|
||||||
def cpu_usage(self):
|
def cpu_usage(self):
|
||||||
cpu_usage = {}
|
cpu_usage = {}
|
||||||
if self.get_status() == 1:
|
if self.get_status() == 1:
|
||||||
|
@ -628,7 +650,7 @@ class wvmInstance(wvmConnect):
|
||||||
iso.append(img)
|
iso.append(img)
|
||||||
return iso
|
return iso
|
||||||
|
|
||||||
def delete_disk(self):
|
def delete_all_disks(self):
|
||||||
disks = self.get_disk_device()
|
disks = self.get_disk_device()
|
||||||
for disk in disks:
|
for disk in disks:
|
||||||
vol = self.get_volume_by_path(disk.get('path'))
|
vol = self.get_volume_by_path(disk.get('path'))
|
||||||
|
|
Loading…
Reference in a new issue