1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

Feature #4620: Add NIC pci passthrough to vm template create/update

This commit is contained in:
Carlos Martín 2016-07-15 16:59:50 +02:00
parent caefeb0e37
commit 94e0b4bd91
9 changed files with 281 additions and 86 deletions

View File

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

View File

@ -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"){

View File

@ -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) {

View File

@ -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);
}
});

View File

@ -130,6 +130,14 @@
<fieldset>
<legend>{{tr "Hardware"}}</legend>
<div class="row">
<div class="small-12 columns">
<label>
<input type="checkbox" class="pci-type-nic"/>
{{tr "PCI passthrough"}}
</label>
</div>
</div>
<div class="row nic-model-row">
<div class="medium-6 columns">
<label for="MODEL">
{{tr "Hardware model to emulate"}}
@ -137,8 +145,24 @@
<input type="text" wizard_field="MODEL" id="MODEL" name="MODEL" />
</div>
</div>
<div class="row pci-row">
<div class="small-12 columns">
<table>
<thead>
<tr>
<th style="width:50%">{{tr "Device name"}}</th>
<th>{{tr "Vendor"}}</th>
<th>{{tr "Device"}}</th>
<th>{{tr "Class"}}</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</fieldset>
<br>
<fieldset>
<legend>{{tr "Security Groups"}}</legend>
<div name="str_nic_tab_id" str_nic_tab_id="{{nicTabId}}">

View File

@ -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 = "<select>";
html += '<option device="" class="" vendor="">'+Locale.tr("Please select")+'</option>';
$.each(pciDevices, function(i,pci){
html += '<option device="'+pci['device']+'" '+
'class="'+pci['class']+'" '+
'vendor="'+pci['vendor']+'">'+
pci.device_name+
'</option>';
});
html += '</select>';
$(".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) {

View File

@ -38,7 +38,14 @@
</fieldset>
<fieldset class="hypervisor only_kvm vm_updateconf_hide">
<legend>{{tr "PCI Devices"}}</legend>
<div>
<div class="row">
<div class="large-12 columns text-center">
<span class="radius secondary label">
<i class="fa fa-warning"/> {{tr "PCI passthrough of network devices is configured per NIC, in the \"Network\" tab. Do not add network devices here"}}
</span>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<table class="dataTable pci_devices">
<thead>

View File

@ -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 = "<select>";
html += '<option device="" class="" vendor="">'+Locale.tr("Please select")+'</option>';
$.each(pciDevices, function(i,pci){
html += '<option device="'+pci['device']+'" '+
'class="'+pci['class']+'" '+
'vendor="'+pci['vendor']+'">'+
pci.device_name+
'</option>';
});
html += '</select>';
$(".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();
});
}
});