[Kimchi-devel] [PATCH v3] [Kimchi] 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).

Jose Ricardo Ziviani joserz at linux.vnet.ibm.com
Mon Jul 25 18:58:42 UTC 2016


From: Samuel Guimarães <sguimaraes943 at gmail.com>

Signed-off-by: Samuel Guimarães <sguimaraes943 at gmail.com>
Signed-off-by: Jose Ricardo Ziviani <joserz at linux.vnet.ibm.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  | 204 +++++++++++++++++++++--------------
 ui/js/src/kimchi.guest_main.js       |  10 +-
 ui/pages/guest-edit.html.tmpl        |  20 ++--
 ui/pages/i18n.json.tmpl              |   2 +
 7 files changed, 148 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 34347c2..59d96e1 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..cabd497 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,8 +491,109 @@ 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(task) {
+        kimchi.trackTask(task.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();
+        });
     };
+    var getOngoingDetachingDevices = function(task) {
+        kimchi.trackTask(task.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();
+        });
+    };
+    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(task) {
+                    getOngoingDetachingDevices(task);
+                }, function(err) {
+                    wok.message.error(err.responseJSON.reason, '#alert-modal-container');
+                });
+            } else {
+                kimchi.addVMPCIDevice(kimchi.selectedGuest, {
+                    name: id
+                }, function(task) {
+                    getOngoingAttachingDevices(task);
+                }, function(err) {
+                    wok.message.error(err.responseJSON.reason, '#alert-modal-container');
+                });
+            }
+        });
+    };
+
+    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;
diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js
index 0e11aa1..605cd2d 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");
@@ -431,13 +431,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() {});
                     }
                 }
 
@@ -446,8 +446,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.")",
-- 
2.7.4




More information about the Kimchi-devel mailing list