mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-06 12:58:18 +03:00
Merge branch 'feature-4620'
This commit is contained in:
commit
ed745428c4
@ -117,6 +117,19 @@ public:
|
||||
static int get_pci_value(const char * name,
|
||||
const VectorAttribute * pci_device,
|
||||
unsigned int& value);
|
||||
/**
|
||||
* Sets the PCI device address in the Virtual Machine as follows;
|
||||
* - VM_DOMAIN: 0x0000
|
||||
* - VM_BUS: dbus or VM_BUS in PCI attribute
|
||||
* - VM_SLOT: PCI_ID + 1
|
||||
* - VM_FUNCTION: 0
|
||||
* - VM_ADDRESS: BUS:SLOT.0
|
||||
* @param pci_device to set the address in
|
||||
* @param default_bus if not set in PCI attribute (PCI_PASSTHROUGH_BUS
|
||||
* in oned.conf)
|
||||
* @return -1 if wrong bus 0 on success
|
||||
*/
|
||||
static int set_pci_address(VectorAttribute * pci_device, const string& dbus);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -1249,10 +1249,16 @@ public:
|
||||
static int release_network_leases(const VectorAttribute * nic, int vmid);
|
||||
|
||||
/**
|
||||
* Returns a set of the security group IDs in use in this VM
|
||||
* Returns a set of the security group IDs in use in this VM. VirtualMachine
|
||||
* and static version.
|
||||
* @param sgs a set of security group IDs
|
||||
*/
|
||||
void get_security_groups(set<int>& sgs) const;
|
||||
void get_security_groups(set<int>& sgs) const
|
||||
{
|
||||
get_security_groups(static_cast<VirtualMachineTemplate *>(obj_template), sgs);
|
||||
}
|
||||
|
||||
static void get_security_groups(VirtualMachineTemplate *tmpl, set<int>& sgs);
|
||||
|
||||
/**
|
||||
* Remove the rules associated to the given security group rules
|
||||
@ -1922,6 +1928,14 @@ private:
|
||||
*/
|
||||
bool generate_network_context(VectorAttribute * context);
|
||||
|
||||
/**
|
||||
* Generate the PCI related CONTEXT setions, i.e. PCI_*. This function
|
||||
* is also adds basic network attributes for pass-through NICs
|
||||
* @param context attribute of the VM
|
||||
* @return true if the net context was generated.
|
||||
*/
|
||||
bool generate_pci_context(VectorAttribute * context);
|
||||
|
||||
/**
|
||||
* Generate the ONE_GATE token & url
|
||||
* @param context attribute of the VM
|
||||
|
@ -199,6 +199,10 @@ DEFAULT_COST = [
|
||||
# for vxlan networks.
|
||||
# start: First VNI to use
|
||||
# NOTE: reserved is not supported by this pool
|
||||
#
|
||||
# PCI_PASSTHROUGH_BUS: Default bus to attach passthrough devices in the guest,
|
||||
# in hex notation. It may be overwritten in the PCI device using the BUS
|
||||
# attribute.
|
||||
#*******************************************************************************
|
||||
|
||||
NETWORK_SIZE = 254
|
||||
@ -214,6 +218,8 @@ VXLAN_IDS = [
|
||||
START = "2"
|
||||
]
|
||||
|
||||
#PCI_PASSTHROUGH_BUS = "0x01"
|
||||
|
||||
#*******************************************************************************
|
||||
# DataStore Configuration
|
||||
#*******************************************************************************
|
||||
|
@ -164,6 +164,10 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
|
||||
vm_nics = [vm["TEMPLATE"]['NIC']].flatten
|
||||
end
|
||||
|
||||
if !vm["TEMPLATE"]["PCI"].nil?
|
||||
vm_nics = [vm_nics, vm["TEMPLATE"]['PCI']].flatten
|
||||
end
|
||||
|
||||
vm_nics.each do |nic|
|
||||
["IP", "IP6_GLOBAL", "IP6_ULA",
|
||||
"VROUTER_IP", "VROUTER_IP6_GLOBAL", "VROUTER_IP6_ULA"].each do |attr|
|
||||
@ -468,6 +472,8 @@ in the frontend machine.
|
||||
|
||||
cluster = nil
|
||||
|
||||
vm_hash = vm.to_hash
|
||||
|
||||
if %w{ACTIVE SUSPENDED POWEROFF}.include? vm.state_str
|
||||
cluster_id = vm['/VM/HISTORY_RECORDS/HISTORY[last()]/CID']
|
||||
else
|
||||
@ -515,7 +521,7 @@ in the frontend machine.
|
||||
|
||||
CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE MONITORING",false)
|
||||
|
||||
vm_monitoring = vm.to_hash['VM']['MONITORING']
|
||||
vm_monitoring = vm_hash['VM']['MONITORING']
|
||||
|
||||
# Find out if it is a hybrid VM to avoid showing local IPs
|
||||
isHybrid=false
|
||||
@ -569,11 +575,11 @@ in the frontend machine.
|
||||
vm_disks = []
|
||||
|
||||
if vm.has_elements?("/VM/TEMPLATE/DISK")
|
||||
vm_disks = [vm.to_hash['VM']['TEMPLATE']['DISK']].flatten
|
||||
vm_disks = [vm_hash['VM']['TEMPLATE']['DISK']].flatten
|
||||
end
|
||||
|
||||
if vm.has_elements?("/VM/TEMPLATE/CONTEXT")
|
||||
context_disk = vm.to_hash['VM']['TEMPLATE']['CONTEXT']
|
||||
context_disk = vm_hash['VM']['TEMPLATE']['CONTEXT']
|
||||
|
||||
context_disk["IMAGE"] = "CONTEXT"
|
||||
context_disk["DATASTORE"] = "-"
|
||||
@ -682,16 +688,21 @@ in the frontend machine.
|
||||
|
||||
sg_nics = []
|
||||
|
||||
if (vm.has_elements?("/VM/TEMPLATE/NIC/SECURITY_GROUPS"))
|
||||
sg_nics = [vm.to_hash['VM']['TEMPLATE']['NIC']].flatten
|
||||
if (vm.has_elements?("/VM/TEMPLATE/NIC/SECURITY_GROUPS") ||
|
||||
vm.has_elements?("/VM/TEMPLATE/PCI[NIC_ID>-1]/SECURITY_GROUPS"))
|
||||
|
||||
sg_nics.each do |nic|
|
||||
sg = nic["SECURITY_GROUPS"]
|
||||
sg_nics = [vm_hash['VM']['TEMPLATE']['NIC']]
|
||||
|
||||
if sg.nil?
|
||||
next
|
||||
sg_pcis = [vm_hash['VM']['TEMPLATE']['PCI']].flatten.compact
|
||||
|
||||
sg_pcis.each do |pci|
|
||||
if !pci['NIC_ID'].nil?
|
||||
sg_nics << pci
|
||||
end
|
||||
end
|
||||
|
||||
sg_nics.flatten!
|
||||
sg_nics.compact!
|
||||
end
|
||||
|
||||
# This variable holds the extra IP's got from monitoring. Right
|
||||
@ -710,7 +721,9 @@ in the frontend machine.
|
||||
|
||||
extra_ips.uniq!
|
||||
|
||||
if vm.has_elements?("/VM/TEMPLATE/NIC") || !extra_ips.empty?
|
||||
if vm.has_elements?("/VM/TEMPLATE/NIC") ||
|
||||
vm.has_elements?("/VM/TEMPLATE/PCI[NIC_ID>-1]") || !extra_ips.empty?
|
||||
|
||||
puts
|
||||
CLIHelper.print_header(str_h1 % "VM NICS",false)
|
||||
|
||||
@ -722,7 +735,19 @@ in the frontend machine.
|
||||
shown_ips = []
|
||||
|
||||
array_id = 0
|
||||
vm_nics = [vm.to_hash['VM']['TEMPLATE']['NIC']].flatten.compact
|
||||
vm_nics = [vm_hash['VM']['TEMPLATE']['NIC']]
|
||||
|
||||
vm_pcis = [vm_hash['VM']['TEMPLATE']['PCI']].flatten.compact
|
||||
|
||||
vm_pcis.each do |pci|
|
||||
if !pci['NIC_ID'].nil?
|
||||
vm_nics << pci
|
||||
end
|
||||
end
|
||||
|
||||
vm_nics.flatten!
|
||||
vm_nics.compact!
|
||||
|
||||
vm_nics.each {|nic|
|
||||
|
||||
next if nic.has_key?("CLI_DONE")
|
||||
@ -809,6 +834,14 @@ in the frontend machine.
|
||||
end
|
||||
end
|
||||
|
||||
column :PCI_ID, "", :left, :size=>8 do |d|
|
||||
if d["DOUBLE_ENTRY"]
|
||||
""
|
||||
else
|
||||
d["PCI_ID"]
|
||||
end
|
||||
end
|
||||
|
||||
end.show(vm_nics,{})
|
||||
|
||||
while vm.has_elements?("/VM/TEMPLATE/NIC")
|
||||
@ -891,7 +924,7 @@ in the frontend machine.
|
||||
d["RANGE"]
|
||||
end
|
||||
|
||||
end.show([vm.to_hash['VM']['TEMPLATE']['SECURITY_GROUP_RULE']].flatten, {})
|
||||
end.show([vm_hash['VM']['TEMPLATE']['SECURITY_GROUP_RULE']].flatten, {})
|
||||
|
||||
while vm.has_elements?("/VM/TEMPLATE/SECURITY_GROUP_RULE")
|
||||
vm.delete_element("/VM/TEMPLATE/SECURITY_GROUP_RULE")
|
||||
@ -920,7 +953,7 @@ in the frontend machine.
|
||||
d["HYPERVISOR_ID"] if !d.nil?
|
||||
end
|
||||
|
||||
end.show([vm.to_hash['VM']['TEMPLATE']['SNAPSHOT']].flatten, {})
|
||||
end.show([vm_hash['VM']['TEMPLATE']['SNAPSHOT']].flatten, {})
|
||||
|
||||
vm.delete_element("/VM/TEMPLATE/SNAPSHOT")
|
||||
end
|
||||
@ -957,7 +990,7 @@ in the frontend machine.
|
||||
column :"MESSAGE", "", :left, :donottruncate, :size=>35 do |d|
|
||||
d["MESSAGE"] if !d.nil?
|
||||
end
|
||||
end.show([vm.to_hash['VM']['USER_TEMPLATE']['SCHED_ACTION']].flatten, {})
|
||||
end.show([vm_hash['VM']['USER_TEMPLATE']['SCHED_ACTION']].flatten, {})
|
||||
end
|
||||
|
||||
if vm.has_elements?("/VM/USER_TEMPLATE")
|
||||
|
@ -267,6 +267,65 @@ int HostSharePCI::get_pci_value(const char * name,
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------*/
|
||||
/* ------------------------------------------------------------------------*/
|
||||
|
||||
int HostSharePCI::set_pci_address(VectorAttribute * pci_device,
|
||||
const string& dbus)
|
||||
{
|
||||
string bus;
|
||||
ostringstream oss;
|
||||
|
||||
unsigned int ibus, slot;
|
||||
|
||||
// ------------------- DOMAIN & FUNCTION -------------------------
|
||||
pci_device->replace("VM_DOMAIN", "0x0000");
|
||||
pci_device->replace("VM_FUNCTION", "0");
|
||||
|
||||
// --------------------------- BUS -------------------------------
|
||||
bus = pci_device->vector_value("VM_BUS");
|
||||
|
||||
if ( bus.empty() )
|
||||
{
|
||||
bus = dbus;
|
||||
}
|
||||
|
||||
istringstream iss(bus);
|
||||
|
||||
iss >> hex >> ibus;
|
||||
|
||||
if (iss.fail() || !iss.eof())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
oss << showbase << internal << setfill('0') << hex << setw(4) << ibus;
|
||||
|
||||
pci_device->replace("VM_BUS", oss.str());
|
||||
|
||||
// --------------------- SLOT (PCI_ID +1) -----------------------
|
||||
oss.str("");
|
||||
|
||||
pci_device->vector_value("PCI_ID", slot);
|
||||
|
||||
slot = slot + 1;
|
||||
|
||||
oss << showbase << internal << setfill('0') << hex << setw(4) << slot;
|
||||
|
||||
pci_device->replace("VM_SLOT", oss.str());
|
||||
|
||||
// ------------------- ADDRESS (BUS:SLOT.0) ---------------------
|
||||
oss.str("");
|
||||
|
||||
oss << noshowbase<<internal<<hex<<setfill('0')<<setw(2) << ibus << ":"
|
||||
<< noshowbase<<internal<<hex<<setfill('0')<<setw(2) << slot << ".0";
|
||||
|
||||
pci_device->replace("VM_ADDRESS", oss.str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------*/
|
||||
/* ------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -22,16 +22,34 @@
|
||||
# A nil filter will retrieve all PCI cards.
|
||||
#
|
||||
# From lspci help:
|
||||
# -d [<vendor>]:[<device>][:<class>]
|
||||
# -d [<vendor>]:[<device>]
|
||||
#
|
||||
# For example
|
||||
#
|
||||
# FILTER = '::0300' # all VGA cards
|
||||
# FILTER = '10de::0300' # all NVIDIA VGA cards
|
||||
# FILTER = '10de:11bf:0300' # only GK104GL [GRID K2]
|
||||
# FILTER = '8086::0300,::0106' # all Intel VGA cards and any SATA controller
|
||||
# FILTER = '10de:*' # all NVIDIA VGA cards
|
||||
# FILTER = '10de:11bf' # only GK104GL [GRID K2]
|
||||
# FILTER = '*:10d3' #Only 82574L Gigabit Network cards
|
||||
# FILTER = '*:*' # all devices
|
||||
# FILTER = '0:0' # no devices
|
||||
#
|
||||
# You can also filter by the SHORT_ADDRESS, to add only devices in a given address
|
||||
#
|
||||
# For example
|
||||
#
|
||||
# SHORT_ADDRESS = [ "07:00.0", "06:00.0" ]
|
||||
#
|
||||
# Finally you can match devices by device name patterns, only those devices that
|
||||
# the pattern will be added to the list.
|
||||
#
|
||||
# For example
|
||||
#
|
||||
# DEVICE_NAME = [ /Virtual Function/, /Gigabit Network/]
|
||||
#
|
||||
# Note that these filters, if defined, are all applied
|
||||
|
||||
FILTER = "0000:0000"
|
||||
FILTER = "0:0"
|
||||
SHORT_ADDRESS = []
|
||||
DEVICE_NAME = []
|
||||
|
||||
require 'shellwords'
|
||||
|
||||
@ -89,6 +107,16 @@ def pval(name, value)
|
||||
end
|
||||
|
||||
devices.each do |dev|
|
||||
next if !SHORT_ADDRESS.empty? && !SHORT_ADDRESS.include?(dev[:short_address])
|
||||
|
||||
if !DEVICE_NAME.empty?
|
||||
matched = DEVICE_NAME.each { |pattern|
|
||||
break true if !(dev[:device_name] =~ pattern).nil?
|
||||
}
|
||||
|
||||
next if matched != true
|
||||
end
|
||||
|
||||
puts "PCI = ["
|
||||
values = [
|
||||
pval('TYPE', dev[:type]),
|
||||
@ -110,5 +138,3 @@ devices.each do |dev|
|
||||
puts "]"
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
@ -451,6 +451,7 @@ void OpenNebulaTemplate::set_conf_default()
|
||||
# MAC_PREFIX
|
||||
# VLAN_ID
|
||||
# VXLAN_ID
|
||||
# PCI_PASSTHROUGH_BUS
|
||||
#*******************************************************************************
|
||||
*/
|
||||
set_conf_single("MAC_PREFIX", "02:00");
|
||||
@ -468,6 +469,8 @@ void OpenNebulaTemplate::set_conf_default()
|
||||
|
||||
vattribute = new VectorAttribute("VXLAN_IDS",vvalue);
|
||||
conf_default.insert(make_pair(vattribute->name(),vattribute));
|
||||
|
||||
set_conf_single("PCI_PASSTHROUGH_BUS", "0x01");
|
||||
/*
|
||||
#*******************************************************************************
|
||||
# Datastore Configuration
|
||||
|
@ -675,6 +675,7 @@ define(function(require) {
|
||||
function ipsStr(element, divider) {
|
||||
var divider = divider || "<br>"
|
||||
var nic = element.TEMPLATE.NIC;
|
||||
var pci = element.TEMPLATE.PCI;
|
||||
var ips = [];
|
||||
|
||||
var monitoring = element.MONITORING;
|
||||
@ -695,21 +696,35 @@ define(function(require) {
|
||||
})
|
||||
}
|
||||
|
||||
if (nic == undefined){
|
||||
nic = [];
|
||||
}
|
||||
|
||||
if (!$.isArray(nic)) {
|
||||
nic = [nic];
|
||||
}
|
||||
|
||||
if (pci != undefined) {
|
||||
if (!$.isArray(pci)) {
|
||||
pci = [pci];
|
||||
}
|
||||
|
||||
$.each(pci, function(){
|
||||
if (this["TYPE"] == "NIC"){
|
||||
nic.push(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(ips.length==0)
|
||||
{
|
||||
if (nic != undefined) {
|
||||
if (!$.isArray(nic)) {
|
||||
nic = [nic];
|
||||
}
|
||||
|
||||
$.each(nic, function(index, value) {
|
||||
$.each(NIC_IP_ATTRS, function(j, attr){
|
||||
if (value[attr]) {
|
||||
ips.push(value[attr]);
|
||||
}
|
||||
});
|
||||
$.each(nic, function(index, value) {
|
||||
$.each(NIC_IP_ATTRS, function(j, attr){
|
||||
if (value[attr]) {
|
||||
ips.push(value[attr]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (ips.length > 0) {
|
||||
|
@ -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
|
||||
@ -80,8 +81,18 @@ define(function(require) {
|
||||
this.vnetsTable.refreshResourceTableSelect();
|
||||
}
|
||||
|
||||
function _setup(context) {
|
||||
/**
|
||||
* @param {Object} context jquery selector
|
||||
* @param {Object} options
|
||||
* options.hide_pci {bool} true to disable the pci checkbox
|
||||
*/
|
||||
function _setup(context, options) {
|
||||
var that = this;
|
||||
|
||||
if (options != undefined && options.hide_pci == true){
|
||||
$("input.pci-type-nic", context).attr('disabled', 'disabled');
|
||||
}
|
||||
|
||||
that.vnetsTable.initialize({
|
||||
'selectOptions': {
|
||||
'select_callback': function(aData, options) {
|
||||
@ -99,6 +110,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 +158,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 +221,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();
|
||||
});
|
||||
}
|
||||
});
|
@ -124,6 +124,8 @@ define(function(require) {
|
||||
}
|
||||
|
||||
function _submitWizard(context) {
|
||||
var that = this;
|
||||
|
||||
if (!this.selected_nodes || this.selected_nodes.length == 0) {
|
||||
Notifier.notifyError(Locale.tr("No template selected"));
|
||||
Sunstone.hideFormPanelLoading(this.tabId);
|
||||
@ -160,11 +162,50 @@ define(function(require) {
|
||||
tmp_json.DISK = disks;
|
||||
}
|
||||
|
||||
var nics = NicsSection.retrieve($(".nicsContext" + template_id, context));
|
||||
var networks = NicsSection.retrieve($(".nicsContext" + template_id, context));
|
||||
|
||||
var nics = [];
|
||||
var pcis = [];
|
||||
|
||||
$.each(networks, function(){
|
||||
if (this.TYPE == "NIC"){
|
||||
pcis.push(this);
|
||||
}else{
|
||||
nics.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
if (nics.length > 0) {
|
||||
tmp_json.NIC = nics;
|
||||
}
|
||||
|
||||
// Replace PCIs of type nic only
|
||||
var original_tmpl = that.template_objects[index].VMTEMPLATE;
|
||||
|
||||
var regular_pcis = [];
|
||||
|
||||
if(original_tmpl.TEMPLATE.PCI != undefined){
|
||||
var original_pcis;
|
||||
|
||||
if ($.isArray(original_tmpl.TEMPLATE.PCI)){
|
||||
original_pcis = original_tmpl.TEMPLATE.PCI;
|
||||
} else if (!$.isEmptyObject(original_tmpl.TEMPLATE.PCI)){
|
||||
original_pcis = [original_tmpl.TEMPLATE.PCI];
|
||||
}
|
||||
|
||||
$.each(original_pcis, function(){
|
||||
if(this.TYPE != "NIC"){
|
||||
regular_pcis.push(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pcis = pcis.concat(regular_pcis);
|
||||
|
||||
if (pcis.length > 0) {
|
||||
tmp_json.PCI = pcis;
|
||||
}
|
||||
|
||||
capacityContext = $(".capacityContext" + template_id, context);
|
||||
$.extend(tmp_json, CapacityInputs.retrieveChanges(capacityContext));
|
||||
|
||||
|
@ -69,7 +69,7 @@ define(function(require) {
|
||||
|
||||
function _setup(context) {
|
||||
var that = this;
|
||||
that.nicTab.setup(context);
|
||||
that.nicTab.setup(context, {hide_pci: true});
|
||||
|
||||
Tips.setup(context);
|
||||
|
||||
|
@ -80,6 +80,7 @@ define(function(require) {
|
||||
<th>' + Locale.tr("Network") + '</th>\
|
||||
<th>' + Locale.tr("IP") + '</th>\
|
||||
<th>' + Locale.tr("MAC") + '</th>\
|
||||
<th>' + Locale.tr("PCI address") + '</th>\
|
||||
<th>' + Locale.tr("IPv6 ULA") + '</th>\
|
||||
<th>' + Locale.tr("IPv6 Global") + '</th>\
|
||||
<th colspan="">' + Locale.tr("Actions") + '</th>\
|
||||
@ -207,15 +208,44 @@ define(function(require) {
|
||||
return html;
|
||||
}
|
||||
|
||||
function _ipTr(nic, attr){
|
||||
var v = "--";
|
||||
|
||||
if (nic[attr] != undefined){
|
||||
v = nic[attr];
|
||||
|
||||
if (nic["VROUTER_"+attr] != undefined){
|
||||
v += ("<br/>" + nic["VROUTER_"+attr] + Locale.tr(" (VRouter)"));
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
function _setup(context) {
|
||||
var that = this;
|
||||
|
||||
var nics = []
|
||||
|
||||
if ($.isArray(that.element.TEMPLATE.NIC))
|
||||
nics = that.element.TEMPLATE.NIC
|
||||
else if (!$.isEmptyObject(that.element.TEMPLATE.NIC))
|
||||
nics = [that.element.TEMPLATE.NIC]
|
||||
if ($.isArray(that.element.TEMPLATE.NIC)){
|
||||
nics = that.element.TEMPLATE.NIC;
|
||||
} else if (!$.isEmptyObject(that.element.TEMPLATE.NIC)){
|
||||
nics = [that.element.TEMPLATE.NIC];
|
||||
}
|
||||
|
||||
var pcis = [];
|
||||
|
||||
if ($.isArray(that.element.TEMPLATE.PCI)){
|
||||
pcis = that.element.TEMPLATE.PCI;
|
||||
} else if (!$.isEmptyObject(that.element.TEMPLATE.PCI)){
|
||||
pcis = [that.element.TEMPLATE.PCI];
|
||||
}
|
||||
|
||||
$.each(pcis, function(){
|
||||
if(this.NIC_ID != undefined){
|
||||
nics.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
var nic_dt_data = [];
|
||||
if (nics.length) {
|
||||
@ -224,22 +254,18 @@ define(function(require) {
|
||||
for (var i = 0; i < nics.length; i++) {
|
||||
var nic = nics[i];
|
||||
|
||||
var actions;
|
||||
// Attach / Detach
|
||||
if (
|
||||
(
|
||||
that.element.STATE == OpenNebulaVM.STATES.ACTIVE) &&
|
||||
(
|
||||
that.element.LCM_STATE == OpenNebulaVM.LCM_STATES.HOTPLUG_NIC) &&
|
||||
(
|
||||
nic.ATTACH == "YES")
|
||||
) {
|
||||
actions = Locale.tr("attach/detach in progress")
|
||||
} else {
|
||||
actions = '';
|
||||
var is_pci = (nic.PCI_ID != undefined);
|
||||
|
||||
if (Config.isTabActionEnabled("vms-tab", "VM.detachnic")) {
|
||||
if (StateActions.enabledStateAction("VM.detachnic", that.element.STATE, that.element.LCM_STATE)) {
|
||||
var actions = '';
|
||||
// Attach / Detach
|
||||
if (!is_pci){
|
||||
if ( (that.element.STATE == OpenNebulaVM.STATES.ACTIVE) &&
|
||||
(that.element.LCM_STATE == OpenNebulaVM.LCM_STATES.HOTPLUG_NIC) &&
|
||||
(nic.ATTACH == "YES") ) {
|
||||
actions = Locale.tr("attach/detach in progress")
|
||||
} else {
|
||||
if ( (Config.isTabActionEnabled("vms-tab", "VM.detachnic")) &&
|
||||
(StateActions.enabledStateAction("VM.detachnic", that.element.STATE, that.element.LCM_STATE))) {
|
||||
actions += '<a href="VM.detachnic" class="detachnic" ><i class="fa fa-times"/>' + Locale.tr("Detach") + '</a>'
|
||||
}
|
||||
}
|
||||
@ -268,27 +294,16 @@ define(function(require) {
|
||||
});
|
||||
}
|
||||
|
||||
function ipTr(attr){
|
||||
var v = "--";
|
||||
|
||||
if (nic[attr] != undefined){
|
||||
v = nic[attr];
|
||||
|
||||
if (nic["VROUTER_"+attr] != undefined){
|
||||
v += ("<br/>" + nic["VROUTER_"+attr] + Locale.tr(" (VRouter)"));
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
var pci_address = is_pci ? nic.ADDRESS : '';
|
||||
|
||||
nic_dt_data.push({
|
||||
NIC_ID : nic.NIC_ID,
|
||||
NETWORK : nic.NETWORK,
|
||||
IP : ipTr("IP"),
|
||||
IP : _ipTr(nic, "IP"),
|
||||
MAC : nic.MAC,
|
||||
IP6_ULA : ipTr("IP6_ULA"),
|
||||
IP6_GLOBAL : ipTr("IP6_GLOBAL"),
|
||||
PCI_ADDRESS: pci_address,
|
||||
IP6_ULA : _ipTr(nic, "IP6_ULA"),
|
||||
IP6_GLOBAL : _ipTr(nic, "IP6_GLOBAL"),
|
||||
ACTIONS : actions,
|
||||
SECURITY_GROUP_RULES : secgroups
|
||||
});
|
||||
@ -309,6 +324,7 @@ define(function(require) {
|
||||
{"data": "NETWORK", "defaultContent": ""},
|
||||
{"data": "IP", "defaultContent": "", "class": "nowrap"},
|
||||
{"data": "MAC", "defaultContent": ""},
|
||||
{"data": "PCI_ADDRESS","defaultContent": ""},
|
||||
{"data": "IP6_ULA", "defaultContent": "", "class": "nowrap"},
|
||||
{"data": "IP6_GLOBAL", "defaultContent": "", "class": "nowrap"},
|
||||
{"data": "ACTIONS", "defaultContent": "", "orderable": false},
|
||||
|
@ -55,11 +55,28 @@ define(function(require) {
|
||||
try {
|
||||
if (OpenNebulaTemplate.isNetworkChangeEnabled(template_json)) {
|
||||
var template_nic = template_json.VMTEMPLATE.TEMPLATE.NIC
|
||||
var nics = []
|
||||
if ($.isArray(template_nic))
|
||||
nics = template_nic
|
||||
else if (!$.isEmptyObject(template_nic))
|
||||
nics = [template_nic]
|
||||
|
||||
var nics = [];
|
||||
|
||||
if ($.isArray(template_nic)){
|
||||
nics = template_nic;
|
||||
} else if (!$.isEmptyObject(template_nic)){
|
||||
nics = [template_nic];
|
||||
}
|
||||
|
||||
var pcis = [];
|
||||
|
||||
if ($.isArray(template_json.VMTEMPLATE.TEMPLATE.PCI)){
|
||||
pcis = template_json.VMTEMPLATE.TEMPLATE.PCI;
|
||||
} else if (!$.isEmptyObject(template_json.VMTEMPLATE.TEMPLATE.PCI)){
|
||||
pcis = [template_json.VMTEMPLATE.TEMPLATE.PCI];
|
||||
}
|
||||
|
||||
$.each(pcis, function(){
|
||||
if(this.TYPE == "NIC"){
|
||||
nics.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
_generate_provision_network_accordion(
|
||||
$(".provision_network_selector", context), options);
|
||||
@ -68,6 +85,8 @@ define(function(require) {
|
||||
var opt = $.extend({}, options);
|
||||
opt.nic = nic;
|
||||
|
||||
opt.pci = (nic.TYPE == "NIC");
|
||||
|
||||
_generate_provision_network_table(
|
||||
$(".provision_nic_accordion", context),
|
||||
opt);
|
||||
@ -160,6 +179,7 @@ define(function(require) {
|
||||
* - management {bool}: true to show the
|
||||
* management checkbox
|
||||
* - securityGroups {bool}: true to select SGs
|
||||
* - pci {bool}: true if this is a PCI interface
|
||||
*/
|
||||
function _generate_provision_network_table(context, options) {
|
||||
context.off();
|
||||
|
@ -2,7 +2,11 @@
|
||||
<a href="#provision_accordion_dd_{{provision_nic_accordion_dd_id}}" class="accordion-title">
|
||||
<i class="only-not-active fa fa-chevron-down"/>
|
||||
<i class="only-active fa fa-chevron-up"/>
|
||||
{{#if options.pci}}
|
||||
{{tr "PCI interface"}}
|
||||
{{else}}
|
||||
{{tr "Interface"}}
|
||||
{{/if}}
|
||||
<span class="selected_network">
|
||||
{{#if options.nic}}
|
||||
{{#if options.nic.NETWORK}}
|
||||
|
@ -145,9 +145,10 @@ const char * VirtualMachine::NETWORK_CONTEXT[][2] = {
|
||||
{"DNS", "DNS"},
|
||||
{"SEARCH_DOMAIN", "SEARCH_DOMAIN"},
|
||||
{"MTU", "GUEST_MTU"},
|
||||
{"VLAN_ID", "VLAN_ID"},
|
||||
{"VROUTER_IP", "VROUTER_IP"},
|
||||
{"VROUTER_MANAGEMENT", "VROUTER_MANAGEMENT"}};
|
||||
const int VirtualMachine::NUM_NETWORK_CONTEXT = 10;
|
||||
const int VirtualMachine::NUM_NETWORK_CONTEXT = 11;
|
||||
|
||||
const char* VirtualMachine::NETWORK6_CONTEXT[][2] = {
|
||||
{"IP6", "IP6_GLOBAL"},
|
||||
@ -552,6 +553,17 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
goto error_os;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// PCI Devices (Needs to be parsed before network)
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = parse_pci(error_str);
|
||||
|
||||
if ( rc != 0 )
|
||||
{
|
||||
goto error_pci;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Parse the defaults to merge
|
||||
// ------------------------------------------------------------------------
|
||||
@ -612,17 +624,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
state = VirtualMachine::CLONING;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// PCI Devices
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
rc = parse_pci(error_str);
|
||||
|
||||
if ( rc != 0 )
|
||||
{
|
||||
goto error_pci;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Set boot order
|
||||
// -------------------------------------------------------------------------
|
||||
@ -706,9 +707,6 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
|
||||
error_update:
|
||||
goto error_rollback;
|
||||
|
||||
error_pci:
|
||||
goto error_rollback;
|
||||
|
||||
error_boot_order:
|
||||
goto error_rollback;
|
||||
|
||||
@ -757,6 +755,7 @@ error_one_vms:
|
||||
goto error_common;
|
||||
|
||||
error_os:
|
||||
error_pci:
|
||||
error_defaults:
|
||||
error_vrouter:
|
||||
error_public:
|
||||
@ -1067,6 +1066,8 @@ int VirtualMachine::parse_context(string& error_str)
|
||||
return -1;
|
||||
}
|
||||
|
||||
generate_pci_context(context);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Parse FILE_DS variables
|
||||
// -------------------------------------------------------------------------
|
||||
@ -1204,60 +1205,71 @@ int VirtualMachine::parse_context_variables(VectorAttribute ** context,
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static int check_pci_attributes(VectorAttribute * pci, const string& default_bus,
|
||||
string& error_str)
|
||||
{
|
||||
static string attrs[] = {"VENDOR", "DEVICE", "CLASS"};
|
||||
static int num_attrs = 3;
|
||||
|
||||
string bus;
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < num_attrs; i++)
|
||||
{
|
||||
unsigned int val;
|
||||
int rc = HostSharePCI::get_pci_value(attrs[i].c_str(), pci, val);
|
||||
|
||||
if (rc == -1)
|
||||
{
|
||||
error_str = "Wrong Hex value for PCI attribute " + attrs[i];
|
||||
return -1;
|
||||
}
|
||||
else if ( rc != 0 )
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
error_str = "DEVICE, VENDOR or CLASS must be defined for PCI.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( HostSharePCI::set_pci_address(pci, default_bus) != 0 )
|
||||
{
|
||||
error_str = "Wrong BUS in PCI attribute";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VirtualMachine::parse_pci(string& error_str)
|
||||
{
|
||||
VectorAttribute * pci;
|
||||
vector<Attribute *> array_pci;
|
||||
vector<Attribute *>::iterator it;
|
||||
vector<VectorAttribute *> array_pci;
|
||||
vector<VectorAttribute *>::iterator it;
|
||||
|
||||
unsigned int val;
|
||||
int pci_id = 0;
|
||||
|
||||
user_obj_template->remove("PCI", array_pci);
|
||||
|
||||
static string attrs[] = {"VENDOR", "DEVICE", "CLASS"};
|
||||
|
||||
for (it = array_pci.begin(); it !=array_pci.end(); it++)
|
||||
for (it = array_pci.begin(); it !=array_pci.end(); ++it, ++pci_id)
|
||||
{
|
||||
(*it)->replace("PCI_ID", pci_id);
|
||||
|
||||
obj_template->set(*it);
|
||||
}
|
||||
|
||||
for (it = array_pci.begin(); it !=array_pci.end(); it++)
|
||||
Nebula& nd = Nebula::instance();
|
||||
string default_bus;
|
||||
|
||||
nd.get_configuration_attribute("PCI_PASSTHROUGH_BUS", default_bus);
|
||||
|
||||
for (it = array_pci.begin(); it !=array_pci.end(); ++it)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
pci = dynamic_cast<VectorAttribute * >(*it);
|
||||
|
||||
if ( pci == 0 )
|
||||
if ( check_pci_attributes(*it, default_bus, error_str) != 0 )
|
||||
{
|
||||
error_str = "PCI attribute must be a vector attribute";
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
int rc = HostSharePCI::get_pci_value(attrs[i].c_str(), pci, val);
|
||||
|
||||
if (rc == -1)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << "Wrong value for PCI/" << attrs[i] << ": "
|
||||
<< pci->vector_value(attrs[i].c_str())
|
||||
<<". It must be a hex value";
|
||||
|
||||
error_str = oss.str();
|
||||
return -1;
|
||||
}
|
||||
else if ( rc != 0 )
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
error_str = "Missing mandatory attributes inside PCI. "
|
||||
"Either DEVICE, VENDOR or CLASS must be defined";
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1529,6 +1541,27 @@ int VirtualMachine::automatic_requirements(string& error_str)
|
||||
}
|
||||
}
|
||||
|
||||
vatts.clear();
|
||||
|
||||
// Get cluster id from all PCI attibutes, TYPE = NIC
|
||||
num_vatts = obj_template->get("PCI", vatts);
|
||||
|
||||
for(int i=0; i<num_vatts; i++)
|
||||
{
|
||||
if ( vatts[i]->vector_value("TYPE") != "NIC" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = check_and_set_cluster_id("CLUSTER_ID", vatts[i], cluster_ids);
|
||||
|
||||
if ( rc != 0 )
|
||||
{
|
||||
incomp_id = i;
|
||||
goto error_pci;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !cluster_ids.empty() )
|
||||
{
|
||||
set<int>::iterator i = cluster_ids.begin();
|
||||
@ -1642,6 +1675,21 @@ error_nic:
|
||||
|
||||
goto error_common;
|
||||
|
||||
error_pci:
|
||||
if (rc == -1)
|
||||
{
|
||||
oss << "Incompatible clusters in PCI (TYPE=NIC). Network for PCI "<< incomp_id
|
||||
<< " is not the same as the one used by other VM elements (cluster "
|
||||
<< one_util::join(cluster_ids, ',') << ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "Missing clusters. Network for PCI "<< incomp_id
|
||||
<< " is not in any cluster";
|
||||
}
|
||||
|
||||
goto error_common;
|
||||
|
||||
error_common:
|
||||
error_str = oss.str();
|
||||
|
||||
@ -3159,6 +3207,23 @@ int VirtualMachine::get_network_leases(string& estr)
|
||||
}
|
||||
}
|
||||
|
||||
vector<VectorAttribute *> pcis;
|
||||
|
||||
int num_pcis = get_template_attribute("PCI", pcis);
|
||||
|
||||
for (int i = 0; i < num_pcis; ++i)
|
||||
{
|
||||
if ( pcis[i]->vector_value("TYPE") == "NIC" )
|
||||
{
|
||||
rc = vnpool->nic_attribute(PoolObjectSQL::VM, pcis[i], i, uid, oid, estr);
|
||||
|
||||
if ( rc == -1 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get_security_groups(vm_sgs);
|
||||
|
||||
sgpool->get_security_group_rules(get_oid(), vm_sgs, sg_rules);
|
||||
@ -3191,12 +3256,23 @@ void VirtualMachine::release_network_leases()
|
||||
string vnid;
|
||||
string ip;
|
||||
|
||||
vector<VectorAttribute const * > nics;
|
||||
int num_nics = get_template_attribute("NIC",nics);
|
||||
vector<VectorAttribute const *> vatts;
|
||||
|
||||
for(int i=0; i<num_nics; i++)
|
||||
int num = get_template_attribute("NIC", vatts);
|
||||
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
release_network_leases(nics[i], oid);
|
||||
release_network_leases(vatts[i], oid);
|
||||
}
|
||||
|
||||
num = get_template_attribute("PCI", vatts);
|
||||
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
if ( vatts[i]->vector_value("TYPE") == "NIC" )
|
||||
{
|
||||
release_network_leases(vatts[i], oid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3264,15 +3340,26 @@ int VirtualMachine::release_network_leases(const VectorAttribute * nic, int vmid
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachine::get_security_groups(set<int>& sgs) const
|
||||
void VirtualMachine::get_security_groups(VirtualMachineTemplate *tmpl, set<int>& sgs)
|
||||
{
|
||||
vector<VectorAttribute *> ns;
|
||||
|
||||
int num_nics = obj_template->get("NIC", ns);
|
||||
vector<VectorAttribute const *> vatts;
|
||||
|
||||
for(int i=0; i<num_nics; i++)
|
||||
int num = tmpl->get("NIC", vatts);
|
||||
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
get_security_groups(ns[i], sgs);
|
||||
get_security_groups(vatts[i], sgs);
|
||||
}
|
||||
|
||||
num = tmpl->get("PCI", vatts);
|
||||
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
if ( vatts[i]->vector_value("TYPE") == "NIC" )
|
||||
{
|
||||
get_security_groups(vatts[i], sgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3733,7 +3820,6 @@ void VirtualMachine::set_auth_request(int uid,
|
||||
AuthRequest& ar,
|
||||
VirtualMachineTemplate *tmpl)
|
||||
{
|
||||
int num;
|
||||
vector<VectorAttribute *> vectors;
|
||||
|
||||
Nebula& nd = Nebula::instance();
|
||||
@ -3742,10 +3828,7 @@ void VirtualMachine::set_auth_request(int uid,
|
||||
VirtualNetworkPool * vnpool = nd.get_vnpool();
|
||||
SecurityGroupPool * sgpool = nd.get_secgrouppool();
|
||||
|
||||
set<int> sgroups;
|
||||
SecurityGroup * sgroup;
|
||||
|
||||
num = tmpl->get("DISK", vectors);
|
||||
int num = tmpl->get("DISK", vectors);
|
||||
|
||||
for(int i=0; i<num; i++)
|
||||
{
|
||||
@ -3756,25 +3839,28 @@ void VirtualMachine::set_auth_request(int uid,
|
||||
|
||||
num = tmpl->get("NIC", vectors);
|
||||
|
||||
for(int i=0; i<num; i++, sgroups.clear())
|
||||
for(int i=0; i<num; i++)
|
||||
{
|
||||
vnpool->authorize_nic(PoolObjectSQL::VM, vectors[i], uid, &ar);
|
||||
}
|
||||
|
||||
get_security_groups(vectors[i], sgroups);
|
||||
set<int> sgroups;
|
||||
|
||||
for(set<int>::iterator it = sgroups.begin(); it != sgroups.end(); it++)
|
||||
get_security_groups(tmpl, sgroups);
|
||||
|
||||
for(set<int>::iterator it = sgroups.begin(); it != sgroups.end(); it++)
|
||||
{
|
||||
SecurityGroup * sgroup = sgpool->get(*it, true);
|
||||
|
||||
if(sgroup != 0)
|
||||
{
|
||||
sgroup = sgpool->get(*it, true);
|
||||
PoolObjectAuth perm;
|
||||
|
||||
if(sgroup != 0)
|
||||
{
|
||||
PoolObjectAuth perm;
|
||||
sgroup->get_permissions(perm);
|
||||
sgroup->get_permissions(perm);
|
||||
|
||||
sgroup->unlock();
|
||||
sgroup->unlock();
|
||||
|
||||
ar.add_auth(AuthRequest::USE, perm);
|
||||
}
|
||||
ar.add_auth(AuthRequest::USE, perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3796,7 +3882,6 @@ void VirtualMachine::disk_extended_info(int uid,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
@ -4761,7 +4846,6 @@ static void parse_context_network(const char* vars[][2], int num_vars,
|
||||
|
||||
cvar << "ETH" << nic_id << "_" << vars[i][0];
|
||||
|
||||
cval = context->vector_value(cvar.str().c_str());
|
||||
cval = nic->vector_value(vars[i][1]); //Check the NIC
|
||||
|
||||
if (cval.empty()) //Will check the AR and VNET
|
||||
@ -4778,6 +4862,29 @@ static void parse_context_network(const char* vars[][2], int num_vars,
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void parse_pci_context_network(const char* vars[][2], int num_vars,
|
||||
VectorAttribute * context, VectorAttribute * nic)
|
||||
{
|
||||
string pci_id = nic->vector_value("PCI_ID");
|
||||
|
||||
for (int i=0; i < num_vars; i++)
|
||||
{
|
||||
ostringstream cvar;
|
||||
|
||||
cvar << "PCI" << pci_id << "_" << vars[i][0];
|
||||
|
||||
string cval = nic->vector_value(vars[i][1]);
|
||||
|
||||
if (!cval.empty())
|
||||
{
|
||||
context->replace(cvar.str(), cval);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachine::parse_nic_context(VectorAttribute * c, VectorAttribute * n)
|
||||
{
|
||||
parse_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT, c, n);
|
||||
@ -4786,6 +4893,42 @@ void VirtualMachine::parse_nic_context(VectorAttribute * c, VectorAttribute * n)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool VirtualMachine::generate_pci_context(VectorAttribute * context)
|
||||
{
|
||||
bool net_context;
|
||||
vector<VectorAttribute *> vatts;
|
||||
|
||||
context->vector_value("NETWORK", net_context);
|
||||
|
||||
int num_vatts = obj_template->get("PCI", vatts);
|
||||
|
||||
for(int i=0; i<num_vatts; i++)
|
||||
{
|
||||
if ( net_context && vatts[i]->vector_value("TYPE") == "NIC" )
|
||||
{
|
||||
parse_pci_context_network(NETWORK_CONTEXT, NUM_NETWORK_CONTEXT,
|
||||
context, vatts[i]);
|
||||
parse_pci_context_network(NETWORK6_CONTEXT, NUM_NETWORK6_CONTEXT,
|
||||
context, vatts[i]);
|
||||
}
|
||||
|
||||
ostringstream cvar;
|
||||
|
||||
cvar << "PCI" << vatts[i]->vector_value("PCI_ID") << "_ADDRESS";
|
||||
|
||||
string cval = vatts[i]->vector_value("VM_ADDRESS");
|
||||
|
||||
if (!cval.empty())
|
||||
{
|
||||
context->replace(cvar.str(), cval);
|
||||
}
|
||||
}
|
||||
|
||||
return net_context;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
bool VirtualMachine::generate_network_context(VectorAttribute * context)
|
||||
{
|
||||
bool net_context;
|
||||
|
@ -184,10 +184,15 @@ int LibVirtDriver::deployment_description_kvm(
|
||||
|
||||
vector<const VectorAttribute *> pci;
|
||||
|
||||
string domain = "";
|
||||
string domain = "";
|
||||
/* bus is already defined for disks */
|
||||
string slot = "";
|
||||
string func = "";
|
||||
string slot = "";
|
||||
string func = "";
|
||||
|
||||
string vm_domain = "";
|
||||
string vm_bus = "";
|
||||
string vm_slot = "";
|
||||
string vm_func = "";
|
||||
|
||||
const VectorAttribute * features;
|
||||
|
||||
@ -1014,6 +1019,11 @@ int LibVirtDriver::deployment_description_kvm(
|
||||
slot = pci[i]->vector_value("SLOT");
|
||||
func = pci[i]->vector_value("FUNCTION");
|
||||
|
||||
vm_domain = pci[i]->vector_value("VM_DOMAIN");
|
||||
vm_bus = pci[i]->vector_value("VM_BUS");
|
||||
vm_slot = pci[i]->vector_value("VM_SLOT");
|
||||
vm_func = pci[i]->vector_value("VM_FUNCTION");
|
||||
|
||||
if ( domain.empty() || bus.empty() || slot.empty() || func.empty() )
|
||||
{
|
||||
vm->log("VMM", Log::WARNING,
|
||||
@ -1033,6 +1043,17 @@ int LibVirtDriver::deployment_description_kvm(
|
||||
<< "/>\n";
|
||||
file << "\t\t\t</source>\n";
|
||||
|
||||
if ( !vm_domain.empty() && !vm_bus.empty() && !vm_slot.empty() &&
|
||||
!vm_func.empty() )
|
||||
{
|
||||
file << "\t\t\t\t<address type='pci'"
|
||||
<< " domain=" << one_util::escape_xml_attr(vm_domain)
|
||||
<< " bus=" << one_util::escape_xml_attr(vm_bus)
|
||||
<< " slot=" << one_util::escape_xml_attr(vm_slot)
|
||||
<< " function=" << one_util::escape_xml_attr(vm_func)
|
||||
<< "/>\n";
|
||||
}
|
||||
|
||||
file << "\t\t</hostdev>" << endl;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user