[Kimchi-devel] [PATCH] [Kimchi] [RFC] Create new volume and attach to VM
Aline Manera
alinefm at linux.vnet.ibm.com
Fri Feb 5 12:35:13 UTC 2016
On 02/05/2016 10:27 AM, Paulo Ricardo Paz Vital wrote:
> On 02/05/2016 10:03 AM, Aline Manera wrote:
>>
>> 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.
>
> Ooops, I mean '.img' instead of '.iso', but if add the '.<format>' is
> not a big issue, would be better than.
Yeap! So I'd suggest to use .img (instead the format) as Template is
using that way and we keep consistence.
>> *
>> *
>>> 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 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..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 at ovirt.org
>>> http://lists.ovirt.org/mailman/listinfo/kimchi-devel
>>>
More information about the Kimchi-devel
mailing list