
Reviewed-by: Paulo Vital <pvital@linux.vnet.ibm.com> On 02/05/2016 02:14 PM, Socorro Stoppler wrote:
Signed-off-by: Socorro Stoppler <socorro@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..9c71486 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 + ".img"; + //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>