[PATCH] [Kimchi] Create logical pool from existing VG

From: peterpennings <peterpnns@gmail.com> This patch adds an option to create logical pools from existing VG. peterpennings (1): Create logical pool from existing VG ui/js/src/kimchi.api.js | 13 ++++ ui/js/src/kimchi.storagepool_add_main.js | 103 +++++++++++++++++++++++++++---- ui/pages/storagepool-add.html.tmpl | 39 ++++++++---- 3 files changed, 132 insertions(+), 23 deletions(-) -- 2.5.0

From: peterpennings <peterpnns@gmail.com> Signed-off-by: peterpennings <peterpnns@gmail.com> --- ui/js/src/kimchi.api.js | 13 ++++ ui/js/src/kimchi.storagepool_add_main.js | 103 +++++++++++++++++++++++++++---- ui/pages/storagepool-add.html.tmpl | 39 ++++++++---- 3 files changed, 132 insertions(+), 23 deletions(-) diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 3519196..b780875 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -711,6 +711,19 @@ var kimchi = { }); }, + getHostVgs: function(suc, err) { + var url = 'plugins/kimchi/host/vgs/'; + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + timeout: 2000, + dataType : 'json', + success : suc, + error : err + }); + }, + addVMStorage : function(settings, suc, err) { var vm = encodeURIComponent(settings['vm']); delete settings['vm']; diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js index 0e9654a..a1b2aeb 100644 --- a/ui/js/src/kimchi.storagepool_add_main.js +++ b/ui/js/src/kimchi.storagepool_add_main.js @@ -18,6 +18,7 @@ kimchi.storagepool_add_main = function() { kimchi.initStorageAddPage(); + sessionStorage.clear(); $('#form-pool-add').on('submit', kimchi.addPool); $('#pool-doAdd').on('click', kimchi.addPool); // 'pool-doAdd' button starts as disabled. @@ -126,13 +127,15 @@ kimchi.initStorageAddPage = function() { kimchi.listHostPartitions(function(data) { if (data.length > 0) { var deviceHtml = $('#partitionTmpl').html(); - var listHtml = ''; + var listHtml = '<table class="table table-hover"><thead><tr><th></th><th>device</th><th>path</th><th>size (GiB)</th></tr></thead><tbody>'; valid_types = ['part', 'disk', 'mpath']; $.each(data, function(index, value) { if (valid_types.indexOf(value.type) !== -1) { + value.size = (value.size / 1000000000).toFixed(2); listHtml += wok.substitute(deviceHtml, value); } }); + listHtml += '</tbody></table>'; $('.host-partition', '#form-pool-add').html(listHtml); } else { $('.host-partition').html(i18n['KCHPOOL6011M']); @@ -143,6 +146,26 @@ kimchi.initStorageAddPage = function() { $('.host-partition').addClass('text-help'); }); + kimchi.getHostVgs(function(data){ + if (data.length > 0) { + var deviceHtml = $('#existingLvmTmpl').html(); + var listHtml = '<table class="table table-hover"><thead><tr><th></th><th>device</th><th>size (GiB)</th><th>free size (GiB)</th></tr></thead><tbody>'; + $.each(data, function(index, value) { + value.size = (value.size / 1000000000).toFixed(2); + value.free = (value.free / 1000000000).toFixed(2); + listHtml += wok.substitute(deviceHtml, value); + }); + listHtml += '</tbody></table>'; + $('.lvm-partition').html(listHtml); + } else { + $('.lvm-partition').html(i18n['KCHPOOL6011M']); + $('.lvm-partition').addClass('text-help'); + } + }, function(err) { + $('.lvm-partition').html(i18n['KCHPOOL6013M'] + '<br/>(' + err.responseJSON.reason + ')'); + $('.lvm-partition').addClass('text-help'); + }); + kimchi.getHostFCDevices(function(data){ $scsiSelect = $('#scsiAdapter'); if(data.length>0){ @@ -238,6 +261,14 @@ kimchi.initStorageAddPage = function() { }); $('#poolTypeInputId').change(function() { + + kimchi.cleanLogicalForm(); + $('#poolId').css("background-color", "#ffffff").attr('readonly', false); + $('[name="logicalRadioSelection"]')[1].checked = true; + $('.lvm-group').addClass('hidden'); + $('.disk-group').removeClass('hidden'); + kimchi.setOldStorageName(); + var poolObject = {'dir': ".path-section", 'netfs': '.nfs-section', 'iscsi': '.iscsi-section', 'scsi': '.scsi-section', 'logical': '.logical-section'}; @@ -265,9 +296,50 @@ kimchi.initStorageAddPage = function() { }).change(function(event) { $(this).toggleClass("invalid-field",!wok.isServer($(this).val().trim())); }); + + $('[name="logicalRadioSelection"]').change(function(){ + kimchi.cleanLogicalForm(); + kimchi.setOldStorageName(); + var selectedRadio = ($(this).val()); + var logicalObject = {'existingLvm' : '.lvm-group', 'rawDisk' : '.disk-group'}; + + if(selectedRadio === 'existingLvm') { + $('[name="lvmTmplRadioSelection"]').change(function(){ + $('#poolId').css("background-color", "#EEE").val($(this).val()).attr('readonly', true); + }); + } else { + $('#poolId').css("background-color", "#ffffff").attr('readonly', false); + } + + $.each(logicalObject, function(type, value) { + if(selectedRadio === type){ + $(value).removeClass('hidden'); + } else { + $(value).addClass('hidden'); + } + }); + }); + + $('#poolId').blur(function() { + sessionStorage.setItem('oldStorageName', $('#poolId').val()); + }) + kimchi.setupISCSI(); }; +kimchi.setOldStorageName = function() { + if(sessionStorage.getItem('oldStorageName') !== ''){ + $('#poolId').val(sessionStorage.getItem('oldStorageName')); + } else { + $('#poolId').val(''); + } +} + +kimchi.cleanLogicalForm = function() { + $("input[name=devices]").attr('checked', false); + $("input[name=lvmTmplRadioSelection]").attr('checked', false); +} + /* Returns 'true' if all form fields were filled, 'false' if * any field is left blank. The function takes into account * the current poolType selected. @@ -288,7 +360,7 @@ kimchi.inputsNotBlank = function() { if (!$('#iscsiserverId').val()) { return false; } if (!$('#iscsiTargetId').val()) { return false; } } else if (poolType === "logical") { - if ($("input[name=devices]:checked").length === 0){ + if ($("input[name=devices]:checked").length === 0 && $("input[name=lvmTmplRadioSelection]:checked").length === 0){ return false; } } @@ -351,7 +423,7 @@ kimchi.validateServer = function(serverField) { }; kimchi.validateLogicalForm = function () { - if ($("input[name=devices]:checked").length === 0) { + if ($("input[name=devices]:checked").length === 0 && $("input[name=lvmTmplRadioSelection]:checked").length === 0) { wok.message.error.code('KCHPOOL6006E'); return false; } else { @@ -363,21 +435,28 @@ kimchi.addPool = function(event) { if (kimchi.validateForm()) { var formData = $('#form-pool-add').serializeObject(); delete formData.authname; + delete formData.logicalRadioSelection; + delete formData.lvmTmplRadioSelection; var poolType = $('#poolTypeInputId').val(); formData.type = poolType; if (poolType === 'dir') { formData.path = $('#pathId').val(); } else if (poolType === 'logical') { - var source = {}; - if (!$.isArray(formData.devices)) { - var deviceObj = []; - deviceObj[0] = formData.devices; - source.devices = deviceObj; - } else { - source.devices = formData.devices; + var logicalrRadioSelected = $("input[name='logicalRadioSelection']:checked").val(); + if (logicalrRadioSelected === 'rawDisk') { + var source = {}; + if (!$.isArray(formData.devices)) { + var deviceObj = []; + deviceObj[0] = formData.devices; + source.devices = deviceObj; + } else { + source.devices = formData.devices; + } + delete formData.devices; + formData.source = source; + } else if (logicalrRadioSelected === 'existingLvm') { + formData.from_vg = true; } - delete formData.devices; - formData.source = source; } else if (poolType === 'netfs'){ var source = {}; source.path = $('#nfspathId').val(); diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl index f7f9b29..b3084fd 100644 --- a/ui/pages/storagepool-add.html.tmpl +++ b/ui/pages/storagepool-add.html.tmpl @@ -82,8 +82,18 @@ </div> </div> <div class="logical-section hidden row"> - <div class="form-group storageType"> - <label>$_("Device path")</label> + <div> + <input type="radio" class="wok-radio" id="existingLvm" name="logicalRadioSelection" value="existingLvm" /> + <label for="existingLvm">$_("Create from existing LVM")</label> + <input type="radio" class="wok-radio" id="rawDisk" name="logicalRadioSelection" value="rawDisk" checked /> + <label for="rawDisk">$_("Create from raw disk")</label> + </div> + <div class="lvm-group hidden"> + <div class="lvm-partition"> + <span class="wok-loading-icon"></span><span>$_("Looking for existing lvms ...")</span> + </div> + </div> + <div class="form-group disk-group storageType"> <div class="host-partition"> <span class="wok-loading-icon"></span><span>$_("Looking for available partitions ...")</span> </div> @@ -156,16 +166,23 @@ <script> kimchi.storagepool_add_main(); </script> + <script id="partitionTmpl" type="html/text"> - <div> - <input type="checkbox" class="wok-checkbox" id="{name}" value="{path}" name="devices"> - <label for="{name}"> - <div> - <span class="device-name">{name}</span> - <span class="device-path">{path}</span> - </div> - </label> - </div> + <tr> + <td><input type="checkbox" class="wok-checkbox" id="{name}" value="{path}" name="devices"><label for="{name}"></label></td> + <td>{name}</td> + <td>{path}</td> + <td>{size}</td> + </tr> + </script> + + <script id="existingLvmTmpl" type="html/text"> + <tr> + <td><input type="radio" class="wok-radio" id="{name}" name="lvmTmplRadioSelection" value="{name}" /><label for="{name}"></label></td> + <td>{name}</td> + <td>{size}</td> + <td>{free}</td> + </tr> </script> </body> </html> -- 2.5.0

Hi Peter, The API to create a new logical pool from existing VG is: POST /plugins/kimchi/storagepools {type: logical, name: <vg-name>, source: {from_vg: true}} With this patch the 'from_vg' parameter is not aligned with 'source' which is raising an error (see below): Also when no VG is found in the system the message should be updated. Instead of "No available partitions found." use "No LVM found in the system." On 02/15/2016 08:35 AM, peterpnns@gmail.com wrote:
From: peterpennings <peterpnns@gmail.com>
Signed-off-by: peterpennings <peterpnns@gmail.com> --- ui/js/src/kimchi.api.js | 13 ++++ ui/js/src/kimchi.storagepool_add_main.js | 103 +++++++++++++++++++++++++++---- ui/pages/storagepool-add.html.tmpl | 39 ++++++++---- 3 files changed, 132 insertions(+), 23 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 3519196..b780875 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -711,6 +711,19 @@ var kimchi = { }); },
+ getHostVgs: function(suc, err) { + var url = 'plugins/kimchi/host/vgs/'; + wok.requestJSON({ + url : url, + type : 'GET', + contentType : 'application/json', + timeout: 2000, + dataType : 'json', + success : suc, + error : err + }); + }, + addVMStorage : function(settings, suc, err) { var vm = encodeURIComponent(settings['vm']); delete settings['vm']; diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js index 0e9654a..a1b2aeb 100644 --- a/ui/js/src/kimchi.storagepool_add_main.js +++ b/ui/js/src/kimchi.storagepool_add_main.js @@ -18,6 +18,7 @@
kimchi.storagepool_add_main = function() { kimchi.initStorageAddPage(); + sessionStorage.clear(); $('#form-pool-add').on('submit', kimchi.addPool); $('#pool-doAdd').on('click', kimchi.addPool); // 'pool-doAdd' button starts as disabled. @@ -126,13 +127,15 @@ kimchi.initStorageAddPage = function() { kimchi.listHostPartitions(function(data) { if (data.length > 0) { var deviceHtml = $('#partitionTmpl').html(); - var listHtml = ''; + var listHtml = '<table class="table table-hover"><thead><tr><th></th><th>device</th><th>path</th><th>size (GiB)</th></tr></thead><tbody>'; valid_types = ['part', 'disk', 'mpath']; $.each(data, function(index, value) { if (valid_types.indexOf(value.type) !== -1) { + value.size = (value.size / 1000000000).toFixed(2); listHtml += wok.substitute(deviceHtml, value); } }); + listHtml += '</tbody></table>'; $('.host-partition', '#form-pool-add').html(listHtml); } else { $('.host-partition').html(i18n['KCHPOOL6011M']); @@ -143,6 +146,26 @@ kimchi.initStorageAddPage = function() { $('.host-partition').addClass('text-help'); });
+ kimchi.getHostVgs(function(data){ + if (data.length > 0) { + var deviceHtml = $('#existingLvmTmpl').html(); + var listHtml = '<table class="table table-hover"><thead><tr><th></th><th>device</th><th>size (GiB)</th><th>free size (GiB)</th></tr></thead><tbody>'; + $.each(data, function(index, value) { + value.size = (value.size / 1000000000).toFixed(2); + value.free = (value.free / 1000000000).toFixed(2); + listHtml += wok.substitute(deviceHtml, value); + }); + listHtml += '</tbody></table>'; + $('.lvm-partition').html(listHtml); + } else { + $('.lvm-partition').html(i18n['KCHPOOL6011M']); + $('.lvm-partition').addClass('text-help'); + } + }, function(err) { + $('.lvm-partition').html(i18n['KCHPOOL6013M'] + '<br/>(' + err.responseJSON.reason + ')'); + $('.lvm-partition').addClass('text-help'); + }); + kimchi.getHostFCDevices(function(data){ $scsiSelect = $('#scsiAdapter'); if(data.length>0){ @@ -238,6 +261,14 @@ kimchi.initStorageAddPage = function() { });
$('#poolTypeInputId').change(function() { + + kimchi.cleanLogicalForm(); + $('#poolId').css("background-color", "#ffffff").attr('readonly', false); + $('[name="logicalRadioSelection"]')[1].checked = true; + $('.lvm-group').addClass('hidden'); + $('.disk-group').removeClass('hidden'); + kimchi.setOldStorageName(); + var poolObject = {'dir': ".path-section", 'netfs': '.nfs-section', 'iscsi': '.iscsi-section', 'scsi': '.scsi-section', 'logical': '.logical-section'}; @@ -265,9 +296,50 @@ kimchi.initStorageAddPage = function() { }).change(function(event) { $(this).toggleClass("invalid-field",!wok.isServer($(this).val().trim())); }); + + $('[name="logicalRadioSelection"]').change(function(){ + kimchi.cleanLogicalForm(); + kimchi.setOldStorageName(); + var selectedRadio = ($(this).val()); + var logicalObject = {'existingLvm' : '.lvm-group', 'rawDisk' : '.disk-group'}; + + if(selectedRadio === 'existingLvm') { + $('[name="lvmTmplRadioSelection"]').change(function(){ + $('#poolId').css("background-color", "#EEE").val($(this).val()).attr('readonly', true); + }); + } else { + $('#poolId').css("background-color", "#ffffff").attr('readonly', false); + } + + $.each(logicalObject, function(type, value) { + if(selectedRadio === type){ + $(value).removeClass('hidden'); + } else { + $(value).addClass('hidden'); + } + }); + }); + + $('#poolId').blur(function() { + sessionStorage.setItem('oldStorageName', $('#poolId').val()); + }) + kimchi.setupISCSI(); };
+kimchi.setOldStorageName = function() { + if(sessionStorage.getItem('oldStorageName') !== ''){ + $('#poolId').val(sessionStorage.getItem('oldStorageName')); + } else { + $('#poolId').val(''); + } +} + +kimchi.cleanLogicalForm = function() { + $("input[name=devices]").attr('checked', false); + $("input[name=lvmTmplRadioSelection]").attr('checked', false); +} + /* Returns 'true' if all form fields were filled, 'false' if * any field is left blank. The function takes into account * the current poolType selected. @@ -288,7 +360,7 @@ kimchi.inputsNotBlank = function() { if (!$('#iscsiserverId').val()) { return false; } if (!$('#iscsiTargetId').val()) { return false; } } else if (poolType === "logical") { - if ($("input[name=devices]:checked").length === 0){ + if ($("input[name=devices]:checked").length === 0 && $("input[name=lvmTmplRadioSelection]:checked").length === 0){ return false; } } @@ -351,7 +423,7 @@ kimchi.validateServer = function(serverField) { };
kimchi.validateLogicalForm = function () { - if ($("input[name=devices]:checked").length === 0) { + if ($("input[name=devices]:checked").length === 0 && $("input[name=lvmTmplRadioSelection]:checked").length === 0) { wok.message.error.code('KCHPOOL6006E'); return false; } else { @@ -363,21 +435,28 @@ kimchi.addPool = function(event) { if (kimchi.validateForm()) { var formData = $('#form-pool-add').serializeObject(); delete formData.authname; + delete formData.logicalRadioSelection; + delete formData.lvmTmplRadioSelection; var poolType = $('#poolTypeInputId').val(); formData.type = poolType; if (poolType === 'dir') { formData.path = $('#pathId').val(); } else if (poolType === 'logical') { - var source = {}; - if (!$.isArray(formData.devices)) { - var deviceObj = []; - deviceObj[0] = formData.devices; - source.devices = deviceObj; - } else { - source.devices = formData.devices; + var logicalrRadioSelected = $("input[name='logicalRadioSelection']:checked").val(); + if (logicalrRadioSelected === 'rawDisk') { + var source = {}; + if (!$.isArray(formData.devices)) { + var deviceObj = []; + deviceObj[0] = formData.devices; + source.devices = deviceObj; + } else { + source.devices = formData.devices; + } + delete formData.devices; + formData.source = source; + } else if (logicalrRadioSelected === 'existingLvm') { + formData.from_vg = true; } - delete formData.devices; - formData.source = source; } else if (poolType === 'netfs'){ var source = {}; source.path = $('#nfspathId').val(); diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl index f7f9b29..b3084fd 100644 --- a/ui/pages/storagepool-add.html.tmpl +++ b/ui/pages/storagepool-add.html.tmpl @@ -82,8 +82,18 @@ </div> </div> <div class="logical-section hidden row"> - <div class="form-group storageType"> - <label>$_("Device path")</label> + <div> + <input type="radio" class="wok-radio" id="existingLvm" name="logicalRadioSelection" value="existingLvm" /> + <label for="existingLvm">$_("Create from existing LVM")</label> + <input type="radio" class="wok-radio" id="rawDisk" name="logicalRadioSelection" value="rawDisk" checked /> + <label for="rawDisk">$_("Create from raw disk")</label> + </div> + <div class="lvm-group hidden"> + <div class="lvm-partition"> + <span class="wok-loading-icon"></span><span>$_("Looking for existing lvms ...")</span> + </div> + </div> + <div class="form-group disk-group storageType"> <div class="host-partition"> <span class="wok-loading-icon"></span><span>$_("Looking for available partitions ...")</span> </div> @@ -156,16 +166,23 @@ <script> kimchi.storagepool_add_main(); </script> + <script id="partitionTmpl" type="html/text"> - <div> - <input type="checkbox" class="wok-checkbox" id="{name}" value="{path}" name="devices"> - <label for="{name}"> - <div> - <span class="device-name">{name}</span> - <span class="device-path">{path}</span> - </div> - </label> - </div> + <tr> + <td><input type="checkbox" class="wok-checkbox" id="{name}" value="{path}" name="devices"><label for="{name}"></label></td> + <td>{name}</td> + <td>{path}</td> + <td>{size}</td> + </tr> + </script> + + <script id="existingLvmTmpl" type="html/text"> + <tr> + <td><input type="radio" class="wok-radio" id="{name}" name="lvmTmplRadioSelection" value="{name}" /><label for="{name}"></label></td> + <td>{name}</td> + <td>{size}</td> + <td>{free}</td> + </tr> </script> </body> </html>

Hi Peter, I was not able to test it due a JS error when loading the new Storage Pool dialog: TypeError: $(...).combobox is not a function Could you take a look on it, please? Regards, Aline Manera On 02/15/2016 08:35 AM, peterpnns@gmail.com wrote:
From: peterpennings <peterpnns@gmail.com>
This patch adds an option to create logical pools from existing VG.
peterpennings (1): Create logical pool from existing VG
ui/js/src/kimchi.api.js | 13 ++++ ui/js/src/kimchi.storagepool_add_main.js | 103 +++++++++++++++++++++++++++---- ui/pages/storagepool-add.html.tmpl | 39 ++++++++---- 3 files changed, 132 insertions(+), 23 deletions(-)

Hi, The combobox() and filterselect() calls in the next line were part of the JS widgets that were removed from Wok in "Remove legacy code under ui/js/widgets". I was going to replace them by typeahead.js but due the limited amount of time we are going to skip that for now and we'll replace them for Typeahead.js later as an enhancement. I've sent a new patch reverting these two widgets and the page works as expected. Regards, Samuel -----Original Message----- From: kimchi-devel-bounces@ovirt.org [mailto:kimchi-devel-bounces@ovirt.org] On Behalf Of Aline Manera Sent: quarta-feira, 17 de fevereiro de 2016 17:24 To: peterpnns@gmail.com; Kimchi Devel <kimchi-devel@ovirt.org> Subject: Re: [Kimchi-devel] [PATCH] [Kimchi] Create logical pool from existing VG Hi Peter, I was not able to test it due a JS error when loading the new Storage Pool dialog: TypeError: $(...).combobox is not a function Could you take a look on it, please? Regards, Aline Manera On 02/15/2016 08:35 AM, peterpnns@gmail.com wrote:
From: peterpennings <peterpnns@gmail.com>
This patch adds an option to create logical pools from existing VG.
peterpennings (1): Create logical pool from existing VG
ui/js/src/kimchi.api.js | 13 ++++ ui/js/src/kimchi.storagepool_add_main.js | 103 +++++++++++++++++++++++++++---- ui/pages/storagepool-add.html.tmpl | 39 ++++++++---- 3 files changed, 132 insertions(+), 23 deletions(-)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
participants (3)
-
Aline Manera
-
peterpnns@gmail.com
-
Samuel Henrique De Oliveira Guimaraes