[Kimchi-devel] [PATCH V2] [Kimchi] Create new volume with .img extension and attach to VM
Aline Manera
alinefm at linux.vnet.ibm.com
Fri Feb 5 19:25:20 UTC 2016
On 02/05/2016 02:14 PM, Socorro Stoppler wrote:
> Signed-off-by: Socorro Stoppler <socorro at 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"];
Place 'qcow2' as the first option, so we implicitly guide user to use it.
> + 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')) {
I don't know why it is not working, but the kimchi_isos pool is being
listed to me in the combo box.
> + 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>
More information about the Kimchi-devel
mailing list