On 02/05/2016 09:03 AM, Paulo Ricardo Paz Vital wrote:
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

The extension '.iso' is for ISO files. In this case, we should use the extension given by the selected format, ie, in your case ubuntu15.10-vm-11454669512074.qcow2

Socorro, following Paulo's suggestion, please, append the ".<format>" to the end of the file name.

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@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>

_______________________________________________
Kimchi-devel mailing list
Kimchi-devel@ovirt.org
http://lists.ovirt.org/mailman/listinfo/kimchi-devel