From 94e0b4bd91b8da90c55f14e8fe979c6b51469009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn?= Date: Fri, 15 Jul 2016 16:59:50 +0200 Subject: [PATCH] Feature #4620: Add NIC pci passthrough to vm template create/update --- .../form-panels/create-common.js | 14 +++ .../form-panels/create/wizard-tabs/general.js | 12 +- .../form-panels/create/wizard-tabs/network.js | 78 +++++++++--- .../create/wizard-tabs/network/nic-tab.js | 49 ++++++-- .../wizard-tabs/network/nic-tab/html.hbs | 26 +++- .../form-panels/create/wizard-tabs/other.js | 61 +-------- .../create/wizard-tabs/other/html.hbs | 9 +- .../form-panels/create/wizard-tabs/utils.js | 118 ++++++++++++++++++ .../wizard-tabs/{other => utils}/pciRow.hbs | 0 9 files changed, 281 insertions(+), 86 deletions(-) create mode 100644 src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/utils.js rename src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/{other => utils}/pciRow.hbs (100%) diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js index 3e4ca24887..6ebf501774 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js @@ -174,6 +174,20 @@ define(function(require) { delete templateJSON["VCENTER_PUBLIC_CLOUD"]; } + // PCI with TYPE=NIC is not defined in the 'other' tab. Because it is + // part of an array, and it is filled in different tabs, the $.extend deep + // merge can't work. We define an auxiliary attribute for it. + + if (templateJSON["NIC_PCI"] != undefined) { + if (templateJSON['PCI'] == undefined) { + templateJSON['PCI'] = []; + } + + templateJSON['PCI'] = templateJSON['PCI'].concat(templateJSON["NIC_PCI"]); + + delete templateJSON["NIC_PCI"]; + } + return templateJSON; } diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js index d7549470bd..fa23fe92cf 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general.js @@ -75,11 +75,15 @@ define(function(require) { function _onShow(context, panelForm) { if (panelForm.action == 'create') { - $('#NAME', context).removeAttr('disabled'); - $('#NAME', context).attr("required", ""); + $('#NAME', context) + .removeAttr('disabled') + .attr("required", "") + .prop('wizard_field_disabled', false); } else if (panelForm.action == 'update') { - $('#NAME', context).attr("disabled", "disabled"); - $('#NAME', context).removeAttr("required"); + $('#NAME', context) + .attr("disabled", "disabled") + .removeAttr("required") + .prop('wizard_field_disabled', true); } if (panelForm.resource == "VirtualRouterTemplate"){ diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js index 6297c90d3b..e9b76d4aee 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network.js @@ -113,13 +113,24 @@ define(function(require) { function _retrieve(context) { var templateJSON = {} var nicsJSON = []; - var nicJSON; + var pcisJSON = []; + + var tmpJSON; $.each(this.nicTabObjects, function(id, nicTab) { - nicJSON = nicTab.retrieve($('#' + nicTab.nicTabId, context)) - if (!$.isEmptyObject(nicJSON)) {nicsJSON.push(nicJSON)}; + tmpJSON = nicTab.retrieve($('#' + nicTab.nicTabId, context)) + if (!$.isEmptyObject(tmpJSON)) { + if (tmpJSON["NIC_PCI"] == true){ + delete tmpJSON["NIC_PCI"]; + tmpJSON["TYPE"] = "NIC"; + pcisJSON.push(tmpJSON); + } else { + nicsJSON.push(tmpJSON); + } + }; }) if (nicsJSON.length > 0) { templateJSON['NIC'] = nicsJSON; }; + if (pcisJSON.length > 0) { templateJSON['NIC_PCI'] = pcisJSON; }; var nicDefault = WizardFields.retrieveInput($('#DEFAULT_MODEL', context)); if (nicDefault) { @@ -133,27 +144,64 @@ define(function(require) { function _fill(context, templateJSON) { var that = this; - var nics = templateJSON.NIC; - if (nics instanceof Array) { - $.each(nics, function(nicId, nicJSON) { - if (nicId > 0) { - that.addNicTab(context); - } + var nics = []; - var nicTab = that.nicTabObjects[that.numberOfNics]; - var nicContext = $('#' + nicTab.nicTabId, context); - nicTab.fill(nicContext, nicJSON); + if (templateJSON.NIC != undefined){ + nics = templateJSON.NIC; + } + + if (!(nics instanceof Array)) { + nics = [nics]; + } + + if (templateJSON.PCI != undefined){ + var pcis = templateJSON.PCI; + + if (!(pcis instanceof Array)) { + pcis = [pcis]; + } + + $.each(pcis, function(){ + if (this["TYPE"] == "NIC"){ + nics.push(this); + } }); - } else if (nics instanceof Object) { + } + + $.each(nics, function(nicId, nicJSON) { + if (nicId > 0) { + that.addNicTab(context); + } + var nicTab = that.nicTabObjects[that.numberOfNics]; var nicContext = $('#' + nicTab.nicTabId, context); - nicTab.fill(nicContext, nics); - } + nicTab.fill(nicContext, nicJSON); + }); if (templateJSON.NIC) { delete templateJSON.NIC; } + if (templateJSON.PCI != undefined) { + var pcis = templateJSON.PCI; + + if (!(pcis instanceof Array)) { + pcis = [pcis]; + } + + pcis = pcis.filter(function(pci){ + return pci["TYPE"] != "NIC" + }); + + delete templateJSON.PCI; + + if (pcis.length == 1){ + templateJSON.PCI = pcis[0]; + } else if (pcis.length > 1) { + templateJSON.PCI = pcis; + } + } + var nicDefault = templateJSON.NIC_DEFAULT if (nicDefault != undefined) { if (nicDefault.MODEL) { diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js index f3a786ba91..0a08e3c008 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab.js @@ -26,6 +26,7 @@ define(function(require) { var SecgroupsTable = require('tabs/secgroups-tab/datatable'); var WizardFields = require('utils/wizard-fields'); var UniqueId = require('utils/unique-id'); + var CreateUtils = require('../utils'); /* TEMPLATES @@ -41,7 +42,7 @@ define(function(require) { CONSTRUCTOR */ - function DiskTab(nicTabId) { + function NicTab(nicTabId) { this.nicTabId = 'nicTab' + nicTabId + UniqueId.id(); this.vnetsTable = new VNetsTable(this.nicTabId + 'Table', {'select': true}); @@ -55,14 +56,14 @@ define(function(require) { this.secgroupsTable = new SecgroupsTable(this.nicTabId + 'SGTable', secgroupSelectOptions); } - DiskTab.prototype.constructor = DiskTab; - DiskTab.prototype.html = _html; - DiskTab.prototype.setup = _setup; - DiskTab.prototype.onShow = _onShow; - DiskTab.prototype.retrieve = _retrieve; - DiskTab.prototype.fill = _fill; + NicTab.prototype.constructor = NicTab; + NicTab.prototype.html = _html; + NicTab.prototype.setup = _setup; + NicTab.prototype.onShow = _onShow; + NicTab.prototype.retrieve = _retrieve; + NicTab.prototype.fill = _fill; - return DiskTab; + return NicTab; /* FUNCTION DEFINITIONS @@ -99,6 +100,30 @@ define(function(require) { that.secgroupsTable.initialize(); that.secgroupsTable.refreshResourceTableSelect(); + + $("input.pci-type-nic", context).on("change", function(){ + var tbody = $(".pci-row tbody", context); + + if ($(this).prop('checked')){ + $("input[wizard_field=MODEL]", context).prop("disabled", true).prop('wizard_field_disabled', true); + $(".nic-model-row", context).hide(); + $(".pci-row", context).show(); + + tbody.html( CreateUtils.pciRowHTML() ); + + CreateUtils.fillPCIRow({tr: $('tr', tbody), remove: false}); + } else { + $("input[wizard_field=MODEL]", context).removeAttr('disabled').prop('wizard_field_disabled', false); + $(".nic-model-row", context).show(); + $(".pci-row", context).hide(); + + tbody.html(""); + } + }); + + CreateUtils.setupPCIRows($(".pci-row", context)); + + $("input.pci-type-nic", context).change(); } function _retrieve(context) { @@ -123,6 +148,10 @@ define(function(require) { nicJSON["SECURITY_GROUPS"] = secgroups.join(","); } + if ($("input.pci-type-nic", context).prop("checked")){ + nicJSON["NIC_PCI"] = true; + } + return nicJSON; } @@ -182,6 +211,10 @@ define(function(require) { this.secgroupsTable.refreshResourceTableSelect(); } + if (templateJSON["TYPE"] == "NIC"){ + $("input.pci-type-nic", context).click(); + } + WizardFields.fill(context, templateJSON); } }); diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs index 869e41037f..990b28f6e0 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/network/nic-tab/html.hbs @@ -130,6 +130,14 @@
{{tr "Hardware"}}
+
+ +
+
+
+
+
+ + + + + + + + + + + + +
{{tr "Device name"}}{{tr "Vendor"}}{{tr "Device"}}{{tr "Class"}}
+
+
-
{{tr "Security Groups"}}
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other.js index 574041523c..f686be59df 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other.js +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other.js @@ -27,13 +27,13 @@ define(function(require) { var CustomTagsTable = require('utils/custom-tags-table'); var OpenNebulaHost = require('opennebula/host'); var UniqueId = require('utils/unique-id'); + var CreateUtils = require('./utils'); /* TEMPLATES */ var TemplateHTML = require('hbs!./other/html'); - var RowTemplateHTML = require('hbs!./other/pciRow'); /* CONSTANTS @@ -82,65 +82,12 @@ define(function(require) { context.off("click", ".add_pci"); context.on("click", ".add_pci", function(){ - var tr = $(RowTemplateHTML()).appendTo( $(".pci_devices tbody", context) ); + var tr = $(CreateUtils.pciRowHTML()).appendTo( $(".pci_devices tbody", context) ); - OpenNebulaHost.pciDevices({ - data : {}, - timeout: true, - success: function (request, pciDevices){ - var html = "'; - - $(".device_name", tr).html(html); - - $("input", tr).trigger("change"); - }, - error: function(request, error_json){ - console.error("There was an error requesting the PCI devices: "+ - error_json.error.message); - - $(".device_name", tr).html(""); - } - }); + CreateUtils.fillPCIRow({tr: tr, remove: true}); }); - context.on("change", ".pci_devices td.device_name select", function(){ - var tr = $(this).closest('tr'); - - var option = $("option:selected", this); - - $('input[wizard_field="DEVICE"]', tr).val( option.attr("device") ); - $('input[wizard_field="CLASS"]', tr).val( option.attr("class") ); - $('input[wizard_field="VENDOR"]', tr).val( option.attr("vendor") ); - }); - - context.on("change", ".pci_devices tbody input", function(){ - var tr = $(this).closest('tr'); - - var opt = - $('option'+ - '[device="'+$('input[wizard_field="DEVICE"]', tr).val()+'"]'+ - '[class="'+$('input[wizard_field="CLASS"]', tr).val()+'"]'+ - '[vendor="'+$('input[wizard_field="VENDOR"]', tr).val()+'"]', tr); - - opt.attr('selected', 'selected'); - }); - - context.on("click", ".pci_devices i.remove-tab", function(){ - var tr = $(this).closest('tr'); - tr.remove(); - }); + CreateUtils.setupPCIRows($(".pci_devices", context)); } function _retrieve(context) { diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other/html.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other/html.hbs index 82121592b3..80b7793b62 100644 --- a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other/html.hbs +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other/html.hbs @@ -38,7 +38,14 @@
{{tr "PCI Devices"}} -
+
+
+ + {{tr "PCI passthrough of network devices is configured per NIC, in the \"Network\" tab. Do not add network devices here"}} + +
+
+
diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/utils.js b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/utils.js new file mode 100644 index 0000000000..a01c86329e --- /dev/null +++ b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/utils.js @@ -0,0 +1,118 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2016, OpenNebula Project, OpenNebula Systems */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* DEPENDENCIES */ + + var OpenNebulaHost = require('opennebula/host'); + var Locale = require('utils/locale'); + + var RowTemplateHTML = require('hbs!./utils/pciRow'); + + return { + 'pciRowHTML': _pciRowHTML, + 'fillPCIRow': _fillPCIRow, + 'setupPCIRows': _setupPCIRows + }; + + function _pciRowHTML(){ + return RowTemplateHTML(); + } + + /** + * Fills the PCI row with values taken from an ajax call to oned + * + * @param {Object} opts Options: + * @param {JQuery} opts.tr tr created with pciRowHTML + * @param {bool} opts.remove true (default) to show the remove tr button + * + */ + function _fillPCIRow(opts){ + OpenNebulaHost.pciDevices({ + data : {}, + timeout: true, + success: function (request, pciDevices){ + var tr = opts.tr; + + var html = "'; + + $(".device_name", opts.tr).html(html); + + $("input", opts.tr).trigger("change"); + + if (opts.remove === false){ + $("i.remove-tab", opts.tr).hide(); + } + }, + error: function(request, error_json){ + console.error("There was an error requesting the PCI devices: "+ + error_json.error.message); + + $(".device_name", opts.tr).html(""); + + if (opts.remove === false){ + $("i.remove-tab", opts.tr).hide(); + } + } + }); + } + + /** + * Setups the pci rows. Can be called once, will work for future rows created + * later + */ + function _setupPCIRows(context){ + + context.on("change", "td.device_name select", function(){ + var tr = $(this).closest('tr'); + + var option = $("option:selected", this); + + $('input[wizard_field="DEVICE"]', tr).val( option.attr("device") ); + $('input[wizard_field="CLASS"]', tr).val( option.attr("class") ); + $('input[wizard_field="VENDOR"]', tr).val( option.attr("vendor") ); + }); + + context.on("change", "tbody input", function(){ + var tr = $(this).closest('tr'); + + var opt = + $('option'+ + '[device="'+$('input[wizard_field="DEVICE"]', tr).val()+'"]'+ + '[class="'+$('input[wizard_field="CLASS"]', tr).val()+'"]'+ + '[vendor="'+$('input[wizard_field="VENDOR"]', tr).val()+'"]', tr); + + opt.attr('selected', 'selected'); + }); + + context.on("click", "i.remove-tab", function(){ + var tr = $(this).closest('tr'); + tr.remove(); + }); + } +}); \ No newline at end of file diff --git a/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other/pciRow.hbs b/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/utils/pciRow.hbs similarity index 100% rename from src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/other/pciRow.hbs rename to src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/utils/pciRow.hbs