[PATCH] [Kimchi] Issue #956: Unable to assign pci passthrough devices through kimchi

From: Samuel Guimarães <sguimaraes943@gmail.com> This commit fixes an issue with PCI passthrough devices through Kimchi. It also addresses an enhancement to display success messages when some actions doesn't require the Save button and there's no UI feedback to the user (Issue #975). Samuel Guimarães (1): Issue #956: Unable to assign pci passthrough devices through kimchi model/vmhostdevs.py | 2 +- ui/css/kimchi.css | 5 + ui/css/src/modules/_edit-guests.scss | 4 + ui/js/src/kimchi.guest_edit_main.js | 232 ++++++++++++++++++++++------------- ui/js/src/kimchi.guest_main.js | 10 +- ui/pages/guest-edit.html.tmpl | 20 ++- ui/pages/i18n.json.tmpl | 2 + 7 files changed, 176 insertions(+), 99 deletions(-) -- 1.9.3

From: Samuel Guimarães <sguimaraes943@gmail.com> This commit fixes an issue with PCI passthrough devices through Kimchi. It also addresses an enhancement to display success messages when some actions doesn't require the Save button and there's no UI feedback to the user (Issue #975). Signed-off-by: Samuel Guimarães <sguimaraes943@gmail.com> --- model/vmhostdevs.py | 2 +- ui/css/kimchi.css | 5 + ui/css/src/modules/_edit-guests.scss | 4 + ui/js/src/kimchi.guest_edit_main.js | 232 ++++++++++++++++++++++------------- ui/js/src/kimchi.guest_main.js | 10 +- ui/pages/guest-edit.html.tmpl | 20 ++- ui/pages/i18n.json.tmpl | 2 + 7 files changed, 176 insertions(+), 99 deletions(-) diff --git a/model/vmhostdevs.py b/model/vmhostdevs.py index 2130ac4..b57cbf0 100644 --- a/model/vmhostdevs.py +++ b/model/vmhostdevs.py @@ -510,7 +510,7 @@ class VMHostDevModel(object): return self.task.lookup(taskid) def _detach_device(self, cb, params): - cb('Detaching device.') + cb('Detaching device') vmid = params['vmid'] dev_name = params['dev_name'] dom = params['dom'] diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css index 261d203..9a3a417 100644 --- a/ui/css/kimchi.css +++ b/ui/css/kimchi.css @@ -1039,6 +1039,11 @@ body.wok-gallery { width: 22%; } +#guest-edit-window #form-guest-edit-pci .wok-mask { + top: 0 !important; + z-index: 2 !important; +} + #guest-edit-window #form-guest-edit-pci .column-actions { width: 4.47%; } diff --git a/ui/css/src/modules/_edit-guests.scss b/ui/css/src/modules/_edit-guests.scss index 6196ed9..b7e6941 100644 --- a/ui/css/src/modules/_edit-guests.scss +++ b/ui/css/src/modules/_edit-guests.scss @@ -62,6 +62,10 @@ } } #form-guest-edit-pci { + .wok-mask { + top: 0 !important; + z-index: 2 !important; + } .column-actions { width: 4.47%; } diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js index fc67d82..583a25c 100644 --- a/ui/js/src/kimchi.guest_edit_main.js +++ b/ui/js/src/kimchi.guest_edit_main.js @@ -425,16 +425,16 @@ kimchi.guest_edit_main = function() { var filterPCINodes = function(group, text) { text = text.trim().split(" "); var rows = $('.body', '#form-guest-edit-pci').find('div'); - if(text === ""){ + if (text === "") { rows.show(); return; } rows.hide(); - rows.filter(function(index, value){ + rows.filter(function(index, value) { var $span = $(this); var $itemGroup = $('button i', this); - for (var i = 0; i < text.length; ++i){ + for (var i = 0; i < text.length; ++i) { if ($span.is(":containsNC('" + text[i] + "')")) { if (group === 'all') { return true; @@ -448,87 +448,26 @@ kimchi.guest_edit_main = function() { return false; }).show(); }; - var setupPCIDevice = function() { - kimchi.getAvailableHostPCIDevices(function(hostPCIs) { - kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) { - setupNode(hostPCIs, 'fa-power-off'); - setupNode(vmPCIs, 'fa-ban'); - }); - }); - $('select', '#form-guest-edit-pci').change(function() { - filterPCINodes($(this).val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); - }); - $('select', '#form-guest-edit-pci').selectpicker(); - $('input#guest-edit-pci-filter', '#form-guest-edit-pci').on('keyup', function() { - filterPCINodes($('select', '#form-guest-edit-pci').val(), $(this).val()); - }); - }; - var setupNode = function(arrPCIDevices, iconClass) { + + var _generatePciDeviceHtml = function(devices, pciType) { var pciEnabled = kimchi.capabilities.kernel_vfio; - var pciDeviceName, pciDeviceProduct, pciDeviceProductDesc, pciDeviceVendor, pciDeviceVendorDesc, pciDeviceStatus; - for (var i = 0; i < arrPCIDevices.length; i++) { - pciDeviceName = arrPCIDevices[i].name; - pciDeviceProduct = arrPCIDevices[i].product; - pciDeviceVendor = arrPCIDevices[i].vendor; - pciDeviceStatus = (iconClass === 'fa-ban') ? 'enabled' : 'disabled'; - if (pciDeviceProduct !== null) { - pciDeviceProductDesc = pciDeviceProduct.description; - } - if (pciDeviceVendor !== null) { - pciDeviceVendorDesc = pciDeviceVendor.description; - } - var itemNode = $.parseHTML(wok.substitute($('#pci-tmpl').html(), { - status: pciDeviceStatus, - name: pciDeviceName, - product: pciDeviceProductDesc, - vendor: pciDeviceVendorDesc + var deviceHTml = devices.map(function(device, index) { + device.iconClass = (pciType === 'hostPCIs' ? 'fa-power-off' : (pciType === 'vmPCIs' ? 'fa-ban' : 'fa-power-off')); + device.status = (pciType === 'vmPCIs' ? 'enabled' : 'disabled'); + device.product = (device.product !== null ? device.product.description : ''); + device.vendor = (device.vendor !== null ? device.vendor.description : ''); + deviceHtml = $.parseHTML(wok.substitute($('#pci-tmpl').html(), { + status: device.status, + name: device.name, + product: device.product, + vendor: device.vendor })); - $('.body', '#form-guest-edit-pci').append(itemNode); - pciEnabled || $('button', itemNode).remove(); - $('button i', itemNode).addClass(iconClass); - if (kimchi.thisVMState === "running" && arrPCIDevices[i].vga3d) { - $('button', itemNode).prop("disabled", true); + pciEnabled || $('button', deviceHtml).remove(); + $('button > i', deviceHtml).addClass(device.iconClass); + if (kimchi.thisVMState === "running" && device.vga3d) { + $('button', deviceHtml).prop("disabled", true); } - $('button', itemNode).on('click', function(event) { - event.preventDefault(); - var obj = $(this); - var objIcon = obj.find('i'); - var id = obj.parent().parent().attr('id'); - if (objIcon.hasClass('fa-ban')) { - kimchi.removeVMPCIDevice(kimchi.selectedGuest, id, function() { - kimchi.getAvailableHostPCIDevices(function(arrPCIDevices) { - kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) { - for (var k = 0; k < arrPCIDevices.length; k++) { - $('#' + arrPCIDevices[k].name + '.item').removeClass('enabled').addClass('disabled'); - $('#' + arrPCIDevices[k].name + ' .action-area button i').removeClass('fa-ban').addClass('fa-power-off'); - } - for (var k = 0; k < vmPCIs.length; k++) { - $('#' + arrPCIDevices[k].name + '.item').removeClass('disabled').addClass('enabled'); - $('#' + arrPCIDevices[k].name + ' .action-area button i').removeClass('fa-power-off').addClass('fa-ban'); - } - }); - }); - //id is for the object that is being added back to the available PCI devices - filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); - }, null); - } else { - kimchi.addVMPCIDevice(kimchi.selectedGuest, { - name: id - }, function() { - kimchi.getAvailableHostPCIDevices(function(arrPCIDevices) { - kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) { - for (var k = 0; k < vmPCIs.length; k++) { - $('#' + vmPCIs[k].name + '.item').removeClass('disabled').addClass('enabled'); - $('#' + vmPCIs[k].name + ' .action-area button i').removeClass('fa-power-off').addClass('fa-ban'); - } - }); - }); - //id is for the object that is being removed from the available PCI devices - filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); - }, null); - } - }); - kimchi.getPCIDeviceCompanions(pciDeviceName, function(infoData) { + kimchi.getPCIDeviceCompanions(device.name, function(infoData) { var pciTitle = i18n['KCHVMED6007M'] + '\n'; var haveCompanions = false; for (var p = 0; p < infoData.length; p++) { @@ -552,9 +491,138 @@ kimchi.guest_edit_main = function() { haveCompanions && $('.vendor', '#' + infoData[q].parent).attr('title', pciTitle); } }); - } + device = deviceHtml[0].outerHTML; + $('.body', '#form-guest-edit-pci').append(device); + }); + }; + var getOngoingAttachingDevices = function() { + var result = {}; + var devices = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/vms/' + kimchi.selectedGuest + '/hostdevs'); + kimchi.getTasksByFilter(devices, function(tasks) { + for (var i = 0; i < tasks.length; i++) { + if (tasks[i].message === 'Attaching PCI device') { + var selectedVm = tasks[i].target_uri.split('/'); + selectedVm = selectedVm[4]; + result[selectedVm] = tasks[i]; + + if (kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { + continue; + } + + kimchi.trackTask(tasks[i].id, function(result) { + kimchi.getAvailableHostPCIDevices(function(arrPCIDevices) { + kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) { + for (var k = 0; k < vmPCIs.length; k++) { + $('#' + vmPCIs[k].name + '.item').removeClass('disabled').addClass('enabled'); + $('#' + vmPCIs[k].name + ' .action-area button i').removeClass('fa-power-off').addClass('fa-ban'); + } + }); + }); + $('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {}); + wok.message.success(i18n['KCHVMED6010M'], '#alert-modal-container'); + filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); + }, function(result) { + if (result['message']) { + var errText = result['message']; + } else { + var errText = result['responseJSON']['reason']; + } + $('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {}); + filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); + result && wok.message.error(errText, '#alert-modal-container'); + }, function(result) { + $('#form-guest-edit-pci > .wok-mask').show(); + }); + } + } + }, null, true); + }; + var getOngoingDetachingDevices = function() { + var result = {}; + var devices = 'status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/vms/' + kimchi.selectedGuest + '/hostdevs'); + kimchi.getTasksByFilter(devices, function(tasks) { + for (var i = 0; i < tasks.length; i++) { + if (tasks[i].message === 'Detaching device') { + var selectedVm = tasks[i].target_uri.split('/'); + selectedVm = selectedVm[4]; + result[selectedVm] = tasks[i]; + + if (kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { + continue; + } + + kimchi.trackTask(tasks[i].id, function(result) { + kimchi.getAvailableHostPCIDevices(function(arrPCIDevices) { + kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) { + for (var k = 0; k < arrPCIDevices.length; k++) { + $('#' + arrPCIDevices[k].name + '.item').removeClass('enabled').addClass('disabled'); + $('#' + arrPCIDevices[k].name + ' .action-area button i').removeClass('fa-ban').addClass('fa-power-off'); + } + for (var k = 0; k < vmPCIs.length; k++) { + $('#' + arrPCIDevices[k].name + '.item').removeClass('disabled').addClass('enabled'); + $('#' + arrPCIDevices[k].name + ' .action-area button i').removeClass('fa-power-off').addClass('fa-ban'); + } + }); + }); + $('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {}); + wok.message.success(i18n['KCHVMED6011M'], '#alert-modal-container'); + //id is for the object that is being added back to the available PCI devices + filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); + }, function(result) { + if (result['message']) { + var errText = result['message']; + } else { + var errText = result['responseJSON']['reason']; + } + $('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {}); + filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); + result && wok.message.error(errText, '#alert-modal-container'); + }, function(result) { + $('#form-guest-edit-pci > .wok-mask').show(); + }); + } + } + }, null, true); + }; + var pciDeviceButtonHandler = function() { + $('button', '#form-guest-edit-pci').on('click', function(event) { + event.preventDefault(); + var obj = $(this); + var objIcon = obj.find('i'); + var id = obj.parent().parent().attr('id'); + if (objIcon.hasClass('fa-ban')) { + kimchi.removeVMPCIDevice(kimchi.selectedGuest, id, function() { + getOngoingDetachingDevices(); + }, null); + } else { + kimchi.addVMPCIDevice(kimchi.selectedGuest, { + name: id + }, function() { + getOngoingAttachingDevices(); + }, null); + } + }); + }; + + var setupPCIDevice = function() { + kimchi.getAvailableHostPCIDevices(function(hostPCIs) { + kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) { + _generatePciDeviceHtml(hostPCIs, 'hostPCIs'); + _generatePciDeviceHtml(vmPCIs, 'vmPCIs'); + pciDeviceButtonHandler(); + $('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {}); + }); + }); + $('select', '#form-guest-edit-pci').change(function() { + filterPCINodes($(this).val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val()); + }); + $('select', '#form-guest-edit-pci').selectpicker(); + $('input#guest-edit-pci-filter', '#form-guest-edit-pci').on('keyup', function() { + filterPCINodes($('select', '#form-guest-edit-pci').val(), $(this).val()); + }); }; + var setupSnapshot = function() { var currentSnapshot; var setCurrentSnapshot = function(aSnapshot) { diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 8e12fb2..15e127b 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -315,7 +315,7 @@ kimchi.initClone = function() { kimchi.listVmsAuto = function() { - $('.wok-mask').removeClass('hidden'); + $('#guests-root-container > .wok-mask').removeClass('hidden'); //Check if the actions button is opened or not, //if opended stop the reload of the itens until closed var $isDropdownOpened = $('[name="guest-actions"] ul.dropdown-menu').is(":visible"); @@ -418,13 +418,13 @@ kimchi.listVmsAuto = function() { }); }); } - $('.wok-mask').fadeOut(300, function() { + $('#guests-root-container > .wok-mask').fadeOut(300, function() { }); } else { $('.grid-control').addClass('hidden'); $('#guestListField').hide(); $('#noGuests').show(); - $('.wok-mask').fadeOut(300, function() {}); + $('#guests-root-container > .wok-mask').fadeOut(300, function() {}); } } @@ -433,8 +433,8 @@ kimchi.listVmsAuto = function() { function(errorResponse, textStatus, errorThrown) { if (errorResponse.responseJSON && errorResponse.responseJSON.reason) { wok.message.error(errorResponse.responseJSON.reason); - $('.wok-mask').fadeOut(300, function() { - $('.wok-mask').addClass('hidden'); + $('#guests-root-container > .wok-mask').fadeOut(300, function() { + $('#guests-root-container > .wok-mask').addClass('hidden'); }); } kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl index f18d42c..a9a468e 100644 --- a/ui/pages/guest-edit.html.tmpl +++ b/ui/pages/guest-edit.html.tmpl @@ -160,6 +160,14 @@ </div> <div class="body"></div> </div> + <div class="wok-mask" role="presentation" class="hidden"> + <div class="wok-mask-loader-container"> + <div class="wok-mask-loading"> + <div class="wok-mask-loading-icon"></div> + <div class="wok-mask-loading-text">$_("Loading")...</div> + </div> + </div> + </div> </form> <form role="tabpanel" id="form-guest-edit-snapshot" class="guest-edit-snapshot tab-pane"> <div class="btn-group"> @@ -273,17 +281,7 @@ <label>{val}</label> </div> </script> -<script id="pci-tmpl" type="text/html"> -<div class="item {status}" id="{name}"> - <span class="cell status column-pci-status"> - <i class="fa fa-power-off"></i> - </span> - <span class="cell name column-pci-name" title="{name}">{name}</span> - <span class="cell product column-product" title="{product}">{product}</span> - <span class="cell vendor column-vendor" title="{vendor}">{vendor}</span> - <span class="cell column-actions action-area"><button class="btn btn-link"><i class="fa"></i></button></span> -</div> -</script> +<script id="pci-tmpl" type="text/html"><div class="item {status}" id="{name}"><span class="cell status column-pci-status"><i class="fa fa-power-off"></i></span><span class="cell name column-pci-name" title="{name}">{name}</span><span class="cell product column-product" title="{product}">{product}</span><span class="cell vendor column-vendor" title="{vendor}">{vendor}</span><span class="cell column-actions action-area"><button class="btn btn-link"><i class="fa"></i></button></span></div></script> <script id="snapshot-tmpl" type="text/html"> <div class="item" id="{name}"> <span class="cell column-sel"> diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl index 4efc1ec..610debc 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -84,6 +84,8 @@ "KCHVMED6007M": "$_("Affected devices:")", "KCHVMED6008M": "$_("More")", "KCHVMED6009M": "$_("Less")", + "KCHVMED6010M": "$_("Successfully attached device to VM")", + "KCHVMED6011M": "$_("Successfully detached device from VM")", "KCHNET6001M": "$_("unavailable")", "KCHNET6002M": "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", -- 1.9.3

Reviewed-by: Jose Ricardo Ziviani Tested-by: Jose Ricardo Ziviani On Mon, Jul 18, 2016 at 12:21:04PM -0300, sguimaraes943@gmail.com wrote:
From: Samuel Guimarães <sguimaraes943@gmail.com>
This commit fixes an issue with PCI passthrough devices through Kimchi. It also addresses an enhancement to display success messages when some actions doesn't require the Save button and there's no UI feedback to the user (Issue #975).
Samuel Guimarães (1): Issue #956: Unable to assign pci passthrough devices through kimchi
model/vmhostdevs.py | 2 +- ui/css/kimchi.css | 5 + ui/css/src/modules/_edit-guests.scss | 4 + ui/js/src/kimchi.guest_edit_main.js | 232 ++++++++++++++++++++++------------- ui/js/src/kimchi.guest_main.js | 10 +- ui/pages/guest-edit.html.tmpl | 20 ++- ui/pages/i18n.json.tmpl | 2 + 7 files changed, 176 insertions(+), 99 deletions(-)
-- 1.9.3
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

Hi Samuel! Hi Ziviani! I could not see that patch working as proposed. I tried to attach a PCI device to a VM and I see the request returned a Task but no requests to track the Task is made. Why Am I doing wrong? How should I test that patch? Regards, Aline Manera On 07/18/2016 12:21 PM, sguimaraes943@gmail.com wrote:
From: Samuel Guimarães <sguimaraes943@gmail.com>
This commit fixes an issue with PCI passthrough devices through Kimchi. It also addresses an enhancement to display success messages when some actions doesn't require the Save button and there's no UI feedback to the user (Issue #975).
Samuel Guimarães (1): Issue #956: Unable to assign pci passthrough devices through kimchi
model/vmhostdevs.py | 2 +- ui/css/kimchi.css | 5 + ui/css/src/modules/_edit-guests.scss | 4 + ui/js/src/kimchi.guest_edit_main.js | 232 ++++++++++++++++++++++------------- ui/js/src/kimchi.guest_main.js | 10 +- ui/pages/guest-edit.html.tmpl | 20 ++- ui/pages/i18n.json.tmpl | 2 + 7 files changed, 176 insertions(+), 99 deletions(-)

On Thu, Jul 21, 2016 at 04:56:08PM -0300, Aline Manera wrote:
Hi Samuel! Hi Ziviani!
I could not see that patch working as proposed.
I tried to attach a PCI device to a VM and I see the request returned a Task but no requests to track the Task is made.
Why Am I doing wrong? How should I test that patch?
Regards, Aline Manera
Hello Aline, After applied you only need to rebuild Kimchi to update the javascript files. After you click on 'attach button', what happens? Does your VM get updated (with that device)? Did you get any feedback (success/failure)? Anything in the logfiles? Thanks

On 07/21/2016 05:15 PM, joserz@linux.vnet.ibm.com wrote:
On Thu, Jul 21, 2016 at 04:56:08PM -0300, Aline Manera wrote:
Hi Samuel! Hi Ziviani!
I could not see that patch working as proposed.
I tried to attach a PCI device to a VM and I see the request returned a Task but no requests to track the Task is made.
Why Am I doing wrong? How should I test that patch?
Regards, Aline Manera Hello Aline,
After applied you only need to rebuild Kimchi to update the javascript files.
After you click on 'attach button', what happens? Does your VM get updated (with that device)? Did you get any feedback (success/failure)? Anything in the logfiles?
Samuel identified the problem. An error might have occurred before Task creation and it is not being treated on UI. Samuel will send a V2 to cover that.
Thanks

I'm adding an error check before starting to track tasks as some errors may not be captured from kimchi.addVMPCIDevice() or kimchi.removeVMPCIDevice() functions but if the request returned without an error message on Wok, it means that it is working. Samuel -----Original Message----- From: kimchi-devel-bounces@ovirt.org [mailto:kimchi-devel-bounces@ovirt.org] On Behalf Of joserz@linux.vnet.ibm.com Sent: quinta-feira, 21 de julho de 2016 17:16 To: Aline Manera <alinefm@linux.vnet.ibm.com> Cc: Kimchi Devel <kimchi-devel@ovirt.org> Subject: Re: [Kimchi-devel] [PATCH] [Kimchi] Issue #956: Unable to assign pci passthrough devices through kimchi On Thu, Jul 21, 2016 at 04:56:08PM -0300, Aline Manera wrote:
Hi Samuel! Hi Ziviani!
I could not see that patch working as proposed.
I tried to attach a PCI device to a VM and I see the request returned a Task but no requests to track the Task is made.
Why Am I doing wrong? How should I test that patch?
Regards, Aline Manera
Hello Aline, After applied you only need to rebuild Kimchi to update the javascript files. After you click on 'attach button', what happens? Does your VM get updated (with that device)? Did you get any feedback (success/failure)? Anything in the logfiles? Thanks _______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
participants (4)
-
Aline Manera
-
joserz@linux.vnet.ibm.com
-
Samuel Henrique De Oliveira Guimaraes
-
sguimaraes943@gmail.com