mirror of
https://github.com/retspen/webvirtcloud
synced 2025-07-31 12:41:08 +00:00
Add editing disk capability to instance. Add instance disk options like io, discard, detect zeroes. rewrite detach disk
This commit is contained in:
parent
c05729158a
commit
f2ba2b58b0
4 changed files with 244 additions and 157 deletions
|
@ -1,151 +1,126 @@
|
|||
{% load i18n %}
|
||||
{% if request.user.is_superuser %}
|
||||
<a href="#addvol" type="button" class="btn btn-success pull-right" data-toggle="modal" title="Add Volume">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||
</a>
|
||||
<button href="#editvol{{ id }}" type="button" class="btn btn-sm btn-default" data-toggle="modal" title="Edit Volume">
|
||||
<i class="glyphicon glyphicon-edit" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
<!-- Modal pool -->
|
||||
<div class="modal fade" id="addvol" tabindex="-1" role="dialog" aria-labelledby="addInstanceVolumeLabel" aria-hidden="true">
|
||||
<div class="modal fade" id="editvol{{ id }}" tabindex="-1" role="dialog" aria-labelledby="editInstanceVolumeLabel{{ id }}" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">{% trans "Add Instance Volume" %}</h4>
|
||||
<h4 class="modal-title">{% trans "Edit Instance Volume" %}</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li role="presentation" class="active"><a href="#NewDisk" data-toggle="tab">{% trans 'New Disk' %}</a></li>
|
||||
<li role="presentation"><a href="#ExistingDisk" data-toggle="tab">{% trans 'Existing Disk' %}</a></li>
|
||||
<li role="presentation" class="active"><a href="#VirtualDisk{{ id }}" data-toggle="tab">{% trans 'Virtual Disk' %}</a></li>
|
||||
<li role="presentation"><a href="#PerformanceVolume{{ id }}" data-toggle="tab">{% trans 'Performance' %}</a></li>
|
||||
<li role="presentation"><a href="#AdvancedVolume{{ id }}" data-toggle="tab">{% trans 'Advanced' %}</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="NewDisk">
|
||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||
|
||||
<p style="font-weight:bold;">{% trans "Volume parameters" %}</p>
|
||||
<div class="tab-pane active" id="VirtualDisk{{ id }}">
|
||||
<div class="form-group">
|
||||
<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_host %}
|
||||
<option value="{{ storage }}">{{ storage }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<label class="col-sm-4 control-label">{% trans 'Volume Path' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" name="vol_path" value="{{ disk.path }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<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\.\-_]+">
|
||||
<label class="col-sm-4 control-label">{% trans 'Readonly' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control-static" type="checkbox" name="vol_readonly" value="True" {% if disk.readonly %}checked{% endif %}/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<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 %}
|
||||
<option value="{{ format }}" {% if format == default_format %}selected{% endif %}>{% trans format %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<label class="col-sm-4 control-label">{% trans 'Shareable' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control-static" type="checkbox" name="vol_shareable" value="True" {% if disk.shareable %}checked{% endif %}/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<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="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">{% trans "Bus" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<select name="bus" class="form-control image-format">
|
||||
{% for bus in bus_host %}
|
||||
<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">{% 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">{% trans "Metadata" %}</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="checkbox" name="meta_prealloc" value="true">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_new_vol">{% trans "Add Volume" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="ExistingDisk">
|
||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<p style="font-weight:bold;">{% trans "Volume parameters" %}</p>
|
||||
<div class="form-group">
|
||||
<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...' %}
|
||||
<span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
{% for storage in storages_host %}
|
||||
<li><a href="#" onclick="get_volumes({{ compute_id }}, '{{ storage }}')">{{ storage }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<input id="selected_storage" name="selected_storage" hidden/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<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>
|
||||
<!-- populate with javascript -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<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 bus_host %}
|
||||
<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">{% 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 class="tab-pane" id="AdvancedVolume{{ id }}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans 'Bus' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<select class="form-control" name="vol_bus">
|
||||
{% for bus in bus_host %}
|
||||
<option value="{{ bus }}" {% if bus == disk.bus %}selected{% endif %}>{{ bus }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="add_existing_vol">{% trans "Add Volume" %}</button>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans 'Serial Number' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" name="vol_serial" value="{{ disk.serial }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans 'Storage Format' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" name="vol_format" value="{{ disk.format }}"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- row -->
|
||||
|
||||
<div class="tab-pane" id="PerformanceVolume{{ id }}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans 'Cache mode' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<select class="form-control" name="vol_cache">
|
||||
{% for key, val in cache_modes %}
|
||||
<option value="{{ key }}" {% if key == disk.cache %}selected{% endif %}>{{ val }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans 'IO mode' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<select class="form-control" name="vol_io_mode">
|
||||
{% for key, val in io_modes %}
|
||||
<option value="{{ key }}" {% if key == disk.io %}selected{% endif %}>{{ val }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans 'Discard mode' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<select class="form-control" name="vol_discard_mode">
|
||||
{% for key, val in discard_modes %}
|
||||
<option value="{{ key }}" {% if key == disk.discard %}selected{% endif %}>{{ val }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans 'Detect zeroes' %}</label>
|
||||
<div class="col-sm-8">
|
||||
<select class="form-control" name="vol_detect_zeroes">
|
||||
{% for key, val in detect_zeroes_modes %}
|
||||
<option value="{{ key }}" {% if key == disk.detect_zeroes %}selected{% endif %}>{{ val }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.tabpane-content -->
|
||||
</div><!-- /.tab-content -->
|
||||
</div> <!-- /.modal-body -->
|
||||
<div class="clearfix"></div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="submit" class="btn btn-success" name="edit_volume">{% trans "Save" %}</button>
|
||||
</div><!-- /.modal-footer -->
|
||||
|
||||
</div> <!-- /.modal-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
|
||||
</div> <!-- /.modal -->
|
||||
{% endif %}
|
||||
|
|
|
@ -823,14 +823,14 @@
|
|||
<th>{% trans "Capacity" %}</th>
|
||||
<th>{% trans "Storage" %}</th>
|
||||
<th>{% trans "Source" %}</th>
|
||||
<th style="width:100px;">{% trans "Action" %}</th>
|
||||
<th>{% trans "Action" %}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for disk in disks %}
|
||||
<tr>
|
||||
<td>
|
||||
<button type="submit" class="btn btn-sm btn-default"
|
||||
name="details"
|
||||
name="details{{ forloop.counter0 }}"
|
||||
title="{% trans "Details" %}"
|
||||
tabindex="0"
|
||||
data-trigger="focus"
|
||||
|
@ -838,7 +838,13 @@
|
|||
data-html="true"
|
||||
data-content="<strong>Bus:</strong> {{ disk.bus }} <br/>
|
||||
<strong>Format:</strong> {{ disk.format }} <br/>
|
||||
<strong>Cache:</strong> {{ disk.cache }}">
|
||||
<strong>Cache:</strong> {{ disk.cache }} <br/>
|
||||
<strong>Serial:</strong> {{ disk.serial }} <br/>
|
||||
<strong>Readonly:</strong> {{ disk.readonly }} <br/>
|
||||
<strong>Shareable:</strong> {{ disk.shareable }}</br>
|
||||
<strong>IO Mode:</strong> {{ disk.io }} <br/>
|
||||
<strong>Discard:</strong> {{ disk.discard }} <br/>
|
||||
<strong>Detect Zeroes:</strong> {{ disk.detect_zeroes }}">
|
||||
<i class="fa fa-info"></i>
|
||||
</button>
|
||||
{{ disk.dev }}
|
||||
|
@ -850,11 +856,12 @@
|
|||
<td>{{ disk.storage }}</td>
|
||||
<td>{{ disk.path }}</td>
|
||||
<td>
|
||||
<form action="" method="post" style="height:10px" role="form">{% csrf_token %}
|
||||
<form action="" method="post" 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 }}">
|
||||
{% include 'edit_instance_volume.html' with id=forloop.counter0 %}
|
||||
{% ifequal status 5 %}
|
||||
<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>
|
||||
|
@ -863,14 +870,15 @@
|
|||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
{% else %}
|
||||
<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?" %}')">
|
||||
<button class="btn btn-sm btn-default disabled" name="detach_vol" value="{{ disk.dev }}" title="{% trans "Detach" %}" onclick="return confirm('{% trans "Are you sure? This may lead data corruption!" %}')">
|
||||
<i class="fa fa-eject"></i>
|
||||
</button>
|
||||
<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?" %}')">
|
||||
<button class="btn btn-sm btn-default disabled" name="delete_vol" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure? This may lead data corruption!" %}')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
</form>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -313,6 +313,12 @@ def instance(request, compute_id, vname):
|
|||
clone_free_names = get_clone_free_names()
|
||||
user_quota_msg = check_user_quota(0, 0, 0, 0)
|
||||
cache_modes = sorted(conn.get_cache_modes().items())
|
||||
io_modes = sorted(conn.get_io_modes().items())
|
||||
discard_modes = sorted(conn.get_discard_modes().items())
|
||||
detect_zeroes_modes = sorted(conn.get_detect_zeroes_modes().items())
|
||||
default_io = settings.INSTANCE_VOLUME_DEFAULT_IO
|
||||
default_discard = settings.INSTANCE_VOLUME_DEFAULT_DISCARD
|
||||
default_zeroes = settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES
|
||||
default_cache = settings.INSTANCE_VOLUME_DEFAULT_CACHE
|
||||
default_format = settings.INSTANCE_VOLUME_DEFAULT_FORMAT
|
||||
default_owner = settings.INSTANCE_VOLUME_DEFAULT_OWNER
|
||||
|
@ -563,10 +569,10 @@ def instance(request, compute_id, vname):
|
|||
meta_prealloc = True if request.POST.get('meta_prealloc', False) else False
|
||||
bus = request.POST.get('bus', default_bus)
|
||||
cache = request.POST.get('cache', default_cache)
|
||||
target = get_new_disk_dev(media, disks, bus)
|
||||
target_dev = get_new_disk_dev(media, disks, bus)
|
||||
|
||||
path = conn_create.create_volume(storage, name, size, format, meta_prealloc, default_owner)
|
||||
conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus)
|
||||
source = conn_create.create_volume(storage, name, size, format, meta_prealloc, default_owner)
|
||||
conn.attach_disk(source, target_dev, target_bus=bus, driver_type=format, cache_mode=cache)
|
||||
msg = _('Attach new disk {} ({})'.format(name, format))
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
@ -583,16 +589,43 @@ def instance(request, compute_id, vname):
|
|||
compute.type,
|
||||
storage)
|
||||
|
||||
format = conn_create.get_volume_type(name)
|
||||
driver_type = conn_create.get_volume_type(name)
|
||||
path = conn_create.get_target_path()
|
||||
target = get_new_disk_dev(media, disks, bus)
|
||||
target_dev = get_new_disk_dev(media, disks, bus)
|
||||
source = path + "/" + name
|
||||
|
||||
conn.attach_disk(source, target, subdriver=format, cache=cache, targetbus=bus)
|
||||
msg = _('Attach Existing disk: ' + target)
|
||||
conn.attach_disk(source, target_dev, target_bus=bus, driver_type=driver_type, cache_mode=cache)
|
||||
msg = _('Attach Existing disk: ' + target_dev)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
||||
if 'edit_volume' in request.POST and allow_admin_or_not_template:
|
||||
target_dev = request.POST.get('dev', '')
|
||||
|
||||
new_path = request.POST.get('vol_path', '')
|
||||
shareable = bool(request.POST.get('vol_shareable', False))
|
||||
readonly = bool(request.POST.get('vol_readonly', False))
|
||||
bus = request.POST.get('vol_bus', '')
|
||||
serial = request.POST.get('vol_serial', '')
|
||||
format = request.POST.get('vol_format', '')
|
||||
cache = request.POST.get('vol_cache', default_cache)
|
||||
io = request.POST.get('vol_io_mode', default_io)
|
||||
discard = request.POST.get('vol_discard_mode', default_discard)
|
||||
zeroes = request.POST.get('vol_detect_zeroes', default_zeroes)
|
||||
|
||||
conn.edit_disk(target_dev, new_path, readonly, shareable, bus, serial, format,
|
||||
cache, io, discard, zeroes)
|
||||
|
||||
if not conn.get_status() == 5:
|
||||
messages.success(request, _("Disk changes changes are applied. " +
|
||||
"But it will be activated after shutdown"))
|
||||
else:
|
||||
messages.success(request, _("Disk is changed successfully."))
|
||||
msg = _('Edit disk: ' + target_dev)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
|
||||
return HttpResponseRedirect(request.get_full_path() + '#disks')
|
||||
|
||||
if 'delete_vol' in request.POST and allow_admin_or_not_template:
|
||||
storage = request.POST.get('storage', '')
|
||||
conn_delete = wvmStorage(compute.hostname,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue