[Kimchi-devel] [PATCH] [Kimchi] [RFC] Create new volume and attach to VM
Aline Manera
alinefm at linux.vnet.ibm.com
Fri Feb 5 12:03:50 UTC 2016
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 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ovirt.org/pipermail/kimchi-devel/attachments/20160205/7a5ff88c/attachment.html>
More information about the Kimchi-devel
mailing list