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:
parent
caefeb0e37
commit
94e0b4bd91
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"){
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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}}">
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
});
|
||||
}
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user