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

joserz at linux.vnet.ibm.com joserz at linux.vnet.ibm.com
Fri Jul 22 19:40:01 UTC 2016


Hello Samuel,

I found something that can help, please read my comments below

Thank you

On Thu, Jul 21, 2016 at 05:49:35PM -0300, sguimaraes943 at gmail.com wrote:
> From: Samuel Guimarães <sguimaraes943 at 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 at 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  | 236 +++++++++++++++++++++++------------
>  ui/js/src/kimchi.guest_main.js       |  10 +-
>  ui/pages/guest-edit.html.tmpl        |  20 ++-
>  ui/pages/i18n.json.tmpl              |   2 +
>  7 files changed, 180 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..d1d6335 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,142 @@ kimchi.guest_edit_main = function() {
>                      haveCompanions && $('.vendor', '#' + infoData[q].parent).attr('title', pciTitle);
>                  }
>              });
> -        }
> +            device = deviceHtml[0].outerHTML;
> +            $('.body', '#form-guest-edit-pci').append(device);
> +        });
> +    };

You can receive the task as parameter here
like 'var getOngoingAttachingDevices = function(task) {

> +    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;
> +                    }
> +

I think this code above can be removed since we can get the task id from
the function argument. Suppose we call the argument 'task', we can
simply pass task.id

> +                    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() {

the same

> +        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() {

Here you can pass the task returned by remove device, like
                kimchi.removeVMPCIDevice(kimchi.selectedGuest, id, function(task) {
                    getOngoingDetachingDevices(task);


> +                    getOngoingDetachingDevices();
> +                }, function(err) {
> +                    wok.message.error(err.responseJSON.reason, '#alert-modal-container');
> +                });
> +            } else {
> +                kimchi.addVMPCIDevice(kimchi.selectedGuest, {
> +                    name: id
> +                }, function() {

like I said above:
}, function(task) {
 getOngoingAttachingDevices(task);
 }

> +                    getOngoingAttachingDevices();
> +                }, 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;
>          var setCurrentSnapshot = function(aSnapshot) {
> 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.")",
> -- 
> 1.9.3
> 
> _______________________________________________
> 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