Looks good! I tested the patch and could create a new volume and attach
it to the VM I was editing.
Just only one suggestion. Add the extension iso in the end of the
filename of the volume when creating. The volume I added to my VM
'ubuntu15.10-vm-1' was created with this info:
$ sudo qemu-img info /var/lib/libvirt/images/ubuntu15.10-vm-11454669512074
image: /var/lib/libvirt/images/ubuntu15.10-vm-11454669512074
file format: qcow2
virtual size: 10K (10240 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
compat: 0.10
refcount bits: 16
Would be nice, that the file has the name
ubuntu15.10-vm-11454669512074.iso
On 02/05/2016 12:41 AM, Socorro Stoppler wrote:
This is the initial checkin for creating a new volume and attaching
to VM when editing a guest.
Not sure of all the supported cases, but certainly tried default pool and qcow2 format
per the
example provided and it was successful.
Known issue - which currently exists in the code already in master - code is broken when
VM
is running. This patch does not address that. It will get addressed separately.
Signed-off-by: Socorro Stoppler <socorro(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.guest_storage_add.main.js | 320 ++++++++++++++++++++++++-----
ui/pages/guest-storage-add.html.tmpl | 58 ++++--
2 files changed, 315 insertions(+), 63 deletions(-)
diff --git a/ui/js/src/kimchi.guest_storage_add.main.js
b/ui/js/src/kimchi.guest_storage_add.main.js
index 6e1926b..9c3f6e4 100644
--- a/ui/js/src/kimchi.guest_storage_add.main.js
+++ b/ui/js/src/kimchi.guest_storage_add.main.js
@@ -15,6 +15,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+kimchi.switchPage = function(fromPageId, toPageId, direction) {
+ $('.tab-content').css('overflow', 'hidden');
+ direction = direction || 'left';
+ var toLeftBegin;
+ var fromLeftEnd;
+ if ('left' === direction) {
+ toLeftBegin = '100%';
+ fromLeftEnd = '-100%';
+ } else if ('right' === direction) {
+ toLeftBegin = '-100%';
+ fromLeftEnd = '100%';
+ }
+ var formPage = $('#' + fromPageId);
+ var toPage = $('#' + toPageId);
+ toPage.css({
+ left: toLeftBegin
+ });
+ formPage.animate({
+ left: fromLeftEnd,
+ opacity: 0.1
+ }, 400, function() {
+ $('.tab-content').css('overflow', 'visible');
+ });
+ toPage.animate({
+ left: '0',
+ opacity: 1
+ }, 400, function() {
+ $('.tab-content').css('overflow', 'visible');
+ });
+};
+
kimchi.guest_storage_add_main = function() {
var types = [{
label: 'cdrom',
@@ -35,9 +66,27 @@ kimchi.guest_storage_add_main = function() {
var pathTextbox = $('input[name="path"]', storageAddForm);
var poolTextbox = $('select#guest-disk-pool', storageAddForm);
var volTextbox = $('select#guest-disk-vol', storageAddForm);
+ var newPoolTextbox = $('select#guest-disk-pool-new', storageAddForm);
+ var capacityTextbox = $('input[name="capacity"]',
storageAddForm);
+ var formatTextbox = $('select#guest-disk-format-new', storageAddForm);
var selectStorageTypeHTML = '';
var selectStoragePoolHTML = '';
var selectStorageVolHTML = '';
+ var rbExisting = 'false';
+
+ var getFormatList = function() {
+ var format = ["bochs", "cloop", "cow",
"dmg", "qcow", "qcow2", "qed", "raw",
"vmdk", "vpc"];
+ var selectFormatHTML = '';
+ var i;
+ for (i = 0; i < format.length; i++) {
+ selectFormatHTML += '<option value="'+ format[i] +
'">' + format[i] + '</option>';
+ }
+ formatTextbox.empty();
+ formatTextbox.append(selectFormatHTML);
+ $(formatTextbox).change();
+ formatTextbox.selectpicker();
+ $('.selectpicker').selectpicker('refresh');
+ };
typeTextbox.change(function() {
var pathObject = {'cdrom': ".path-section", 'disk':
'.volume-section'};
@@ -45,41 +94,82 @@ kimchi.guest_storage_add_main = function() {
$.each(pathObject, function(type, value) {
if(selectType === type){
$(value).removeClass('hidden');
+ } else if ((selectType === null) && (type === 'disk')) {
+ $(value).removeClass('hidden');
} else {
$(value).addClass('hidden');
}
});
-
if ($(".path-section").hasClass('hidden')) {
- $(poolTextbox).val('default');
- $(poolTextbox).change();
$(pathTextbox).val("");
- }
- else {
+ if ($('#new-disk').checked) {
+ $('#existing-disk-box').addClass('hidden');
+ $(newPoolTextbox).val('default');
+ $(newPoolTextbox).change();
+ } else if ($('#existing-disk').checked) {
+ $('#new-disk-box').addClass('hidden');
+ $(poolTextbox).val('default');
+ $(poolTextbox).change();
+ } else {
+ if (rbExisting === 'true') {
+ $('#new-disk-box').addClass('hidden');
+ } else {
+ $('#existing-disk-box').addClass('hidden');
+ }
+ }
+ } else {
$(poolTextbox).val("");
$(volTextbox).val("");
+ $(newPoolTextbox).val("");
+ $(capacityTextbox).val("");
+ $(formatTextbox).val("");
}
$('.selectpicker').selectpicker('refresh');
});
- kimchi.listStoragePools(function(result) {
- var options = [];
- if (result && result.length) {
- $.each(result, function(index, storagePool) {
- if ((storagePool.state==="active") &&
(storagePool.type !== 'kimchi-iso')) {
- options.push({
- label: storagePool.name,
- value: storagePool.name
- });
- selectStoragePoolHTML += '<option value="'+
storagePool.name + '">' + storagePool.name + '</option>';
+ var getStoragePools = function(radioButton) {
+ kimchi.listStoragePools(function(result) {
+ var options = [];
+ selectStoragePoolHTML = ''; //reset string
+ if (result && result.length) {
+ $.each(result, function(index, storagePool) {
+ if (radioButton === 'existing') {
+ if ((storagePool.state==="active") &&
(storagePool.type !== 'kimchi-iso')) {
+ options.push({
+ label: storagePool.name,
+ value: storagePool.name
+ });
+ selectStoragePoolHTML += '<option value="'+
storagePool.name + '">' + storagePool.name + '</option>';
+ }
+ } else { //new disk
+ if ((storagePool.type != 'iscsi') &&
(storagePool.type != 'scsi')) {
+ options.push({
+ label: storagePool.name,
+ value: storagePool.name
+ });
+ selectStoragePoolHTML += '<option value="'+
storagePool.name + '">' + storagePool.name + '</option>';
+ }
}
-
});
- poolTextbox.append(selectStoragePoolHTML);
- poolTextbox.val(options[0].value);
- poolTextbox.selectpicker();
- }
- });
+ if (radioButton === 'existing') {
+ poolTextbox.empty();
+ poolTextbox.append(selectStoragePoolHTML);
+ $(poolTextbox).change();
+ poolTextbox.selectpicker();
+ $('.selectpicker').selectpicker('refresh');
+ } else if (radioButton === 'new') { //new disk
+ newPoolTextbox.empty();
+ newPoolTextbox.append(selectStoragePoolHTML);
+ $(newPoolTextbox).val(options[0].value);
+ newPoolTextbox.selectpicker();
+ getFormatList();
+ }
+ }
+ });
+ };
+
+ //First time retrieving list of Storage Pools - defaulting to new disk
+ getStoragePools('new');
poolTextbox.change(function() {
var options = [];
@@ -109,13 +199,15 @@ kimchi.guest_storage_add_main = function() {
$(volTextbox).prop('disabled',true);
$(submitButton).prop('disabled', true);
}
- volTextbox.selectpicker();
- $('.selectpicker').selectpicker('refresh');
+ } else {
+ $(volTextbox).prop('disabled',true);
+ $(submitButton).prop('disabled', true);
}
+ volTextbox.selectpicker();
+ $('.selectpicker').selectpicker('refresh');
}, null, false);
});
-
typeTextbox.change(function() {
var pathObject = {'cdrom': ".path-section", 'disk':
'.volume-section'};
var selectType = $(this).val();
@@ -128,6 +220,47 @@ kimchi.guest_storage_add_main = function() {
});
});
+ var currentPage = 'new-disk-box';
+ $('#existing-disk').change(function() {
+ if (this.checked) {
+ rbExisting = 'true';
+ if (currentPage === 'new-disk-box') {
+ kimchi.switchPage(currentPage, 'existing-disk-box',
'right');
+ }
+ currentPage = 'existing-disk-box';
+ $('#existing-disk-box').removeClass('hidden');
+ $('#new-disk-box').addClass('hidden');
+ $('#guest-storage-add-window .modal-body
.template-pager').animate({
+ height: "200px"
+ }, 300);
+ getStoragePools('existing');
+ $(pathTextbox).val("");
+ $(newPoolTextbox).val("");
+ $(capacityTextbox).val("");
+ $(formatTextbox).val("");
+ }
+ });
+
+ $('#new-disk').change(function() {
+ if (this.checked) {
+ rbExisting = 'false';
+ if (currentPage === 'existing-disk-box') {
+ kimchi.switchPage(currentPage, 'new-disk-box',
'right');
+ } else if($(capacityTextbox).is(":visible") === false ) {
+ kimchi.switchPage(currentPage, 'new-disk-box',
'right');
+ }
+ currentPage = 'new-disk-box';
+ $('#existing-disk-box').addClass('hidden');
+ $('#new-disk-box').removeClass('hidden');
+ $('#guest-storage-add-window .modal-body
.template-pager').animate({
+ height: "300px"
+ }, 400);
+ $(pathTextbox).val("");
+ $(poolTextbox).val("");
+ $(volTextbox).val("");
+ }
+ });
+
if (kimchi.thisVMState === 'running') {
types =typesRunning;
$(typeTextbox).val('disk');
@@ -155,15 +288,104 @@ kimchi.guest_storage_add_main = function() {
}
};
+ var onError = function(result) {
+ if(!result) {
+ return;
+ }
+ var msg = result['message'] || (
+ result['responseJSON'] &&
result['responseJSON']['reason']
+ );
+ wok.message.error(msg);
+ };
+
+ var addStorage = function(settings) {
+ kimchi.addVMStorage(settings, function(result) {
+ wok.window.close();
+ wok.topic('kimchi/vmCDROMAttached').publish({
+ result: result
+ });
+ }, function(result) {
+ var errText = result['reason'] ||
+ result['responseJSON']['reason'];
+ wok.message.error(errText, '#alert-modal-container2');
+ $.each([submitButton, pathTextbox, poolTextbox, volTextbox, newPoolTextbox,
capacityTextbox, formatTextbox], function(i, c) {
+ $(c).prop('disabled', false);
+ });
+ });
+ }
+
+ var createVol = function(settings, addVolSettings) {
+ kimchi.createVolumeWithCapacity('default', {
+ name: settings['vol'],
+ format: settings['format'],
+ capacity: settings['capacity']
+ }, function(result) {
+ var taskId = result.id;
+ function monitorTask() {
+ kimchi.getTask(taskId, function(result) {
+ var status = result.status;
+ if (status === "finished") {
+ //Now add newly created volume to VM
+ addStorage(addVolSettings);
+ } else if (status === "running") {
+ setTimeout(monitorTask, 2000);
+ $(submitButton).prop('disabled', true);
+ } else if (status === "failed") {
+ var errText = result['reason'] ||
+ result['responseJSON']['reason'];
+ $(submitButton).prop('disabled', true);
+ wok.message.error(errText, '#alert-modal-container2');
+ }
+ });
+ }
+ setTimeout(monitorTask, 2000);
+ }, onError);
+ };
+
+ var bNewDisk = 'false';
+
var validateDisk = function(settings) {
- if (settings['pool'] && settings['vol']){
- // Delete path property since it's not needed for disk
- delete settings['path'];
- return true;
+ // Determine whether it's existing disk or new disk
+ if($(capacityTextbox).is(":visible") === true ) {
+ bNewDisk = 'true';
}
- else {
-
wok.message.error(i18n['KCHVMSTOR0002E'],'#alert-modal-container2');
- return false;
+ if (bNewDisk === 'true') {
+ if (settings['newpool'] && settings['capacity']
&& settings['format']){
+ //Change settings['newpool'] to settings['pool']
+ settings['pool']=settings['newpool'];
+ var vmname = settings['vm'];
+ vmname = vmname + new Date().getTime();
+ //Unique vol name to be created
+ settings['vol']=vmname;
+ //This is all that is needed for attaching newly created volume to VM
+ var addVolSettings = {
+ vm: settings['vm'],
+ type: settings['type'],
+ vol: settings['vol'],
+ pool: settings['pool']
+ };
+ var sizeInMB = parseInt(settings['capacity']) * 1024;
+ settings['capacity'] = sizeInMB;
+ //These need to be deleted so they don't get passed to backend
+ delete settings['path'];
+ delete settings['newpool'];
+ //Create an empty storage volume and attach to VM if successful
+ createVol(settings, addVolSettings);
+ return true;
+ } else {
+
wok.message.error(i18n['KCHVMSTOR0002E'],'#alert-modal-container2');
+ return false;
+ }
+ } else {
+ if (settings['pool'] && settings['vol']){
+ // Delete path property since it's not needed for disk
+ delete settings['path'];
+ return true;
+ }
+ else {
+
wok.message.error(i18n['KCHVMSTOR0002E'],'#alert-modal-container2');
+ return false;
+ }
}
};
@@ -172,6 +394,11 @@ kimchi.guest_storage_add_main = function() {
if (submitButton.prop('disabled')) {
return false;
}
+ var bNewDisk = 'false';
+ // Determine whether it's existing disk or new disk
+ if($(capacityTextbox).is(":visible") === true ) {
+ bNewDisk = 'true';
+ }
var formData = storageAddForm.serializeObject();
var settings = {
@@ -179,40 +406,30 @@ kimchi.guest_storage_add_main = function() {
type: typeTextbox.val(),
path: pathTextbox.val(),
pool: poolTextbox.val(),
- vol: volTextbox.val()
+ vol: volTextbox.val(),
+ newpool: newPoolTextbox.val(),
+ format: formatTextbox.val(),
+ capacity: capacityTextbox.val()
};
$(submitButton).prop('disabled', true);
- $.each([pathTextbox, poolTextbox, volTextbox], function(i, c) {
+ $.each([pathTextbox, poolTextbox, volTextbox, newPoolTextbox, capacityTextbox,
formatTextbox], function(i, c) {
$(c).prop('disabled', true);
});
// Validate form for cdrom and disk
validateSpecifiedForm = validator[settings['type']];
if (!validateSpecifiedForm(settings)) {
$(submitButton).prop('disabled', false);
- $.each([submitButton, pathTextbox, poolTextbox, volTextbox], function(i, c)
{
+ $.each([submitButton, pathTextbox, poolTextbox, volTextbox, newPoolTextbox,
capacityTextbox, formatTextbox], function(i, c) {
$(c).prop('disabled', false);
});
return false;
}
$(submitButton).addClass('loading').text(i18n['KCHVMCD6003M']);
- kimchi.addVMStorage(settings, function(result) {
- wok.window.close();
- wok.topic('kimchi/vmCDROMAttached').publish({
- result: result
- });
- }, function(result) {
- var errText = result['reason'] ||
- result['responseJSON']['reason'];
- wok.message.error(errText, '#alert-modal-container2');
-
- $.each([submitButton, pathTextbox, poolTextbox, volTextbox], function(i, c)
{
- $(c).prop('disabled', false);
- });
-
$(submitButton).removeClass('loading').text(i18n['KCHVMCD6002M']);
- });
-
+ if(bNewDisk === 'false'){
+ addStorage(settings);
+ }
event.preventDefault();
};
@@ -224,5 +441,8 @@ kimchi.guest_storage_add_main = function() {
volTextbox.on('change propertychange', function (event) {
$(submitButton).prop('disabled', $(this).val() === '');
});
+ capacityTextbox.on('change input propertychange', function(event) {
+ $(submitButton).prop('disabled', $(this).val() === '');
+ });
};
diff --git a/ui/pages/guest-storage-add.html.tmpl b/ui/pages/guest-storage-add.html.tmpl
index bde0eee..660c274 100644
--- a/ui/pages/guest-storage-add.html.tmpl
+++ b/ui/pages/guest-storage-add.html.tmpl
@@ -1,7 +1,7 @@
#*
* Project Kimchi
*
- * Copyright IBM, Corp. 2014
+ * Copyright IBM, Corp. 2014-2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,18 +41,50 @@
</select>
<p class="help-block"><i class="fa
fa-info-circle"></i> $_("The device type. Currently,
\"cdrom\" and \"disk\" are supported.")</p>
</div>
- <div class="volume-section hidden">
- <div class="form-group">
- <label>$_("Storage Pool")</label>
- <select id="guest-disk-pool"
class="selectpicker col-md-12 col-lg-12">
- </select>
- <p class="help-block"><i class="fa
fa-info-circle"></i> $_("Storage pool which volume located
in")</p>
+ <div class="volume-section hidden form-group">
+ <div class="template-modal-container">
+ <div>
+ <span
id="alert-modal-container"></span>
+ <input type="radio" checked="checked"
name="disk-btn" id="new-disk" value="new-disk"
class="wok-radio">
+ <label for="new-disk">$_("Create a new
disk")</label>
+ <input type="radio" name="disk-btn"
id="existing-disk" value="existing-disk"
class="wok-radio">
+ <label for="existing-disk">$_("Select
an existing disk")</label>
+ </div>
</div>
- <div class="form-group">
- <label>$_("Storage Volume")</label>
- <select id="guest-disk-vol"
class="selectpicker col-md-12 col-lg-12">
- </select>
- <p class="help-block"><i class="fa
fa-info-circle"></i> $_("Storage volume to be
attached")</p>
+ <div class="template-pager">
+ <div class="page" id="new-disk-box">
+ <div class="form-group">
+ <label>$_("Storage Pool")</label>
+ <select id="guest-disk-pool-new"
class="selectpicker col-md-12 col-lg-12">
+ </select>
+ <p class="help-block"><i
class="fa fa-info-circle"></i> $_("Storage pool to create the
volume in")</p>
+ </div>
+ <div class="form-group">
+ <label>$_("Disk Size
(GB)")</label>
+ <input type="number"
class="form-control" name="capacity" min="1"
id="capacity" />
+ <p class="help-block"><i
class="fa fa-info-circle"></i> $_("New disk size to be
created")</p>
+ </div>
+ <div class="form-group">
+ <label>$_("Format")</label>
+ <select id="guest-disk-format-new"
class="selectpicker col-md-12 col-lg-12">
+ </select>
+ <p class="help-block"><i
class="fa fa-info-circle"></i> $_("Format of the new disk to be
created")</p>
+ </div>
+ </div>
+ <div class="page"
id="existing-disk-box">
+ <div class="form-group">
+ <label>$_("Storage Pool")</label>
+ <select id="guest-disk-pool"
class="selectpicker col-md-12 col-lg-12">
+ </select>
+ <p class="help-block"><i
class="fa fa-info-circle"></i> $_("Storage pool in which the
volume is located in")</p>
+ </div>
+ <div class="form-group">
+ <label>$_("Storage
Volume")</label>
+ <select id="guest-disk-vol"
class="selectpicker col-md-12 col-lg-12">
+ </select>
+ <p class="help-block"><i
class="fa fa-info-circle"></i> $_("Storage volume to be
attached")</p>
+ </div>
+ </div>
</div>
</div>
<div class="path-section form-group">
@@ -72,4 +104,4 @@
kimchi.guest_storage_add_main();
</script>
</body>
-</html>
\ No newline at end of file
+</html>