1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-02-28 17:57:22 +03:00

F #4913: Add support for unmanaged nics. Remove opennebula.hotplugged_nics

This commit is contained in:
mcabrerizo 2017-03-23 10:27:32 +01:00
parent 9f6abc21b9
commit d73adc1c24
4 changed files with 180 additions and 127 deletions

View File

@ -84,6 +84,7 @@ def self.import_templates(con_ops, options)
# Create OpenNebula pools
dpool = VCenterDriver::VIHelper.one_pool(OpenNebula::DatastorePool)
ipool = VCenterDriver::VIHelper.one_pool(OpenNebula::ImagePool)
npool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool)
# Get vcenter intance uuid as moref is unique for each vcenter
vc_uuid = vi_client.vim.serviceContent.about.instanceUuid
@ -118,17 +119,28 @@ def self.import_templates(con_ops, options)
template = t[:template]
error, template_disks = template.import_vcenter_disks(vc_uuid,
error, template_disks_and_nics = template.import_vcenter_disks(vc_uuid,
dpool,
ipool)
if error.empty?
t[:one] << template_disks
t[:one] << template_disks_and_nics
else
STDOUT.puts error
next
end
error, template_nics = template.import_vcenter_nics(vc_uuid,
npool)
if error.empty?
t[:one] << template_nics
else
STDOUT.puts error
next
end
# Datastore placement
ds_input = ""

View File

@ -86,6 +86,25 @@ class Network
return template
end
def self.get_network_type(device)
if device.backing.network.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup)
return "Distributed Port Group"
else
return "Port Group"
end
end
def self.get_one_vnet_ds_by_ref_and_ccr(ref, ccr_ref, vcenter_uuid, pool = nil)
pool = VCenterDriver::VIHelper.one_pool(OpenNebula::VirtualNetworkPool, false) if pool.nil?
element = pool.select do |e|
e["TEMPLATE/VCENTER_NET_REF"] == ref &&
e["TEMPLATE/VCENTER_CCR_REF"] == ccr_ref &&
e["TEMPLATE/VCENTER_INSTANCE_ID"] == vcenter_uuid
end.first rescue nil
return element
end
# This is never cached
def self.new_from_ref(ref, vi_client)
self.new(RbVmomi::VIM::Network.new(vi_client.vim, ref), vi_client)

View File

@ -430,9 +430,36 @@ class VirtualMachine
one_item.info
end
def reference_imported_nics
mac_change_hash = {}
nics = []
# Add info for existing disks in template in vm xml
xpath = "TEMPLATE/NIC[OPENNEBULA_MANAGED=\"NO\"]"
unmanaged_nics = one_item.retrieve_xmlelements(xpath)
return if unmanaged_nics.empty?
# Update vcenter VM's mac addresses with the one in OpenNebula's XML
index = 0
@item["config.hardware.device"].each_with_index do |device|
if is_nic?(device)
# Edit capacity setting new size in KB
device.macAddress = unmanaged_nics[index]["MAC"]
nics << { :device => device, :operation => :edit }
index += 1
end
end
if !nics.empty?
mac_change_hash[:deviceChange] = nics
@item.ReconfigVM_Task(:spec => mac_change_hash).wait_for_completion
end
end
def resize_imported_disks
resize_hash = {}
device_change_disks = []
disks = []
# Look for unmanaged disks with original size changed
xpath = "TEMPLATE/DISK[OPENNEBULA_MANAGED=\"NO\" and boolean(ORIGINAL_SIZE)]"
@ -457,8 +484,7 @@ class VirtualMachine
# Edit capacity setting new size in KB
d.capacityInKB = disk["SIZE"].to_i * 1024
device_change_disks << { :device => d,
:operation => :edit }
disks << { :device => d, :operation => :edit }
break
end
end
@ -466,8 +492,8 @@ class VirtualMachine
end
end
if !device_change_disks.empty?
resize_hash[:deviceChange] = device_change_disks
if !disks.empty?
resize_hash[:deviceChange] = disks
@item.ReconfigVM_Task(:spec => resize_hash).wait_for_completion
end
end
@ -486,10 +512,8 @@ class VirtualMachine
# vnc configuration (for config_array hash)
extraconfig += extraconfig_vnc
# device_change hash (nics and extraconfig)
nics, extraconfig_nics = device_change_nics
device_change += nics
extraconfig += extraconfig_nics
# device_change hash (nics)
device_change += device_change_nics
# device_change hash (disks)
device_change += device_change_disks
@ -557,94 +581,37 @@ class VirtualMachine
def device_change_nics
# Final list of changes to be applied in vCenter
device_change = []
config_array = []
hotplugged_nics = []
# Hash of interfaces from the OpenNebula xml
nics_in_template = {}
xpath = "TEMPLATE/NIC"
one_item.each(xpath) { |nic|
nics_in_template[nic["MAC"]] = nic
}
# List of interfaces from the OpenNebula template
nics = []
one_item.each("TEMPLATE/NIC") { |nic| nics << nic }
# Remove detached nics in poweroff
if !is_new?
# To be included in device_change
detach_nic_array = []
# B4897 - Get mac of NICs that were hot-plugged from vCenter
# extraConfig
# Get opennebula.hotplugged_nics attribute from the vCenter object
extraconfig_nics = @item["config.extraConfig"].select do |val|
val[:key] == "opennebula.hotplugged_nics"
end
if extraconfig_nics && !extraconfig_nics.empty?
hotplugged_nics = extraconfig_nics[0][:value].to_s.split(";")
end
# Get MACs from NICs inside VM template
one_mac_addresses = []
nics.each do |nic|
one_mac_addresses << nic["MAC"]
# B4897 - Add NICs that were attached in POWEROFF
if !hotplugged_nics.include?(nic["MAC"])
hotplugged_nics << nic["MAC"]
# Check nics in VM
@item["config.hardware.device"].each do |dv|
if is_nic?(dv)
if nics_in_template.key?(dv.macAddress)
# Remove nic that is already in the XML to avoid duplicate
nics_in_template.delete(dv.macAddress)
else
# B4897 - It was detached in poweroff, remove it from VM
device_change << {
:operation => :remove,
:device => dv
}
end
end
@item["config.hardware.device"].each do |dv|
if is_nic?(dv)
# nics array will contain the list of nics to be attached
nics.each do |nic|
if nic["MAC"] == dv.macAddress
nics.delete(nic)
end
end
# if the nic is in the list opennebula.hotplugged_nics and
# not in the list of the OpenNebula NICs we can remove it.
# B4897 - Remove detached NICs from vCenter that were unplugged
# in POWEROFF
if !one_mac_addresses.include?(dv.macAddress) &&
hotplugged_nics.include?(dv.macAddress)
detach_nic_array << {
:operation => :remove,
:device => dv
}
hotplugged_nics.delete(dv.macAddress)
end
end
end
config_array << { :key => 'opennebula.hotplugged_nics',
:value => hotplugged_nics.join(";")}
device_change += detach_nic_array
else
# B4897 - Add NICs that have been added to the VM template
# to the hotplugged_nics extraconfig so we can track what must be removed
# Get MACs from NICs inside VM template to track NICs added by OpenNebula
nics.each{|nic|
hotplugged_nics << nic["MAC"]
}
if !hotplugged_nics.empty?
config_array << {
:key => 'opennebula.hotplugged_nics',
:value => hotplugged_nics.join(";")
}
end
end
# Attach new nics (nics now contains only the interfaces not present
# in the VM in vCenter)
nics.each do |nic|
# Attach new nics (nics_in_template now contains only the interfaces
# not present in the VM in vCenter)
nics_in_template.each do |key, nic|
device_change << calculate_add_nic_spec(nic)
end
return device_change, config_array
return device_change
end
# Regenerate context when devices are hot plugged (reconfigure)
@ -777,25 +744,6 @@ class VirtualMachine
attach_nic_array << calculate_add_nic_spec(nic)
spec_hash[:deviceChange] = attach_nic_array if !attach_nic_array.empty?
# Get mac addresses plugged to the VM B#4897
hotplugged_nics = @item["config.extraConfig"].select do |val|
val[:key] == "opennebula.hotplugged_nics"
end.first[:value].to_s.split(";") rescue nil
# Include MAC in opennebula.hotplugged_nics variable
if hotplugged_nics && !hotplugged_nics.empty?
if !hotplugged_nics.include?(nic["MAC"])
hotplugged_nics << nic["MAC"]
end
else
hotplugged_nics = []
hotplugged_nics << nic["MAC"]
end
spec_hash[:extraConfig] = [{
:key=>"opennebula.hotplugged_nics",
:value=>hotplugged_nics.join(";")}]
# Reconfigure VM
spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash)
@ -814,32 +762,15 @@ class VirtualMachine
# Extract nic from driver action
nic = one_item.retrieve_xmlelements("TEMPLATE/NIC[ATTACH='YES']").first
mac = nic["MAC"]
# Get VM nic element if it has a device with that mac
nic_device = @item["config.hardware.device"].find do |device|
is_nic?(device) && (device.macAddress == mac)
is_nic?(device) && (device.macAddress == mac)
end rescue nil
raise "Could not find NIC with mac address #{mac}" if nic_device.nil?
# Get mac addresses plugged to the VM B#4897
hotplugged_nics = @item["config.extraConfig"].select do |val|
val[:key] == "opennebula.hotplugged_nics"
end.first[:value].to_s.split(";") rescue nil
# Remove MAC from opennebula.hotplugged_nics variable if included
if hotplugged_nics &&
!hotplugged_nics.empty? && hotplugged_nics.include?(mac)
hotplugged_nics.delete(mac)
spec_hash[:extraConfig] = [{
:key=>"opennebula.hotplugged_nics",
:value=>hotplugged_nics.join(";")}]
end
# Remove NIC from VM in the ReconfigVM_Task
spec_hash[:deviceChange] = [
:operation => :remove,
@ -1128,6 +1059,20 @@ class VirtualMachine
return disks
end
def get_vcenter_nics
nics = []
@item["config.hardware.device"].each do |device|
nic = {}
if is_nic?(device)
nic[:net_name] = device.backing.network.name
nic[:net_ref] = device.backing.network._ref
nic[:pg_type] = VCenterDriver::Network.get_network_type(device)
nics << nic
end
end
return nics
end
def import_vcenter_disks(vc_uuid, dpool, ipool)
disk_info = ""
error = ""
@ -1205,6 +1150,80 @@ class VirtualMachine
return error, disk_info
end
def import_vcenter_nics(vc_uuid, npool)
nic_info = ""
error = ""
ccr_ref = self["runtime.host.parent._ref"]
ccr_name = self["runtime.host.parent.name"]
#Get disks and info required
vc_nics = get_vcenter_nics
# Track allocated networks
allocated_networks = []
vc_nics.each do |nic|
network_found = VCenterDriver::Network.get_one_vnet_ds_by_ref_and_ccr(nic[:net_ref],
ccr_ref,
vc_uuid,
npool)
#Network is already in the datastore
if network_found
# This is the existing nic info
nic_info << "NIC=[\n"
nic_info << "NETWORK=\"#{network_found["NAME"]}\",\n"
nic_info << "OPENNEBULA_MANAGED=\"NO\"\n"
nic_info << "]\n"
else
# Then the network has to be created as it's not in OpenNebula
one_vn = VCenterDriver::VIHelper.new_one_item(OpenNebula::VirtualNetwork)
allocated_networks << one_vn
vlan_id = "" # TODO VLAN ID management
one_vnet = VCenterDriver::Network.to_one_template(nic[:net_name],
nic[:net_ref],
nic[:pg_type],
vlan_id,
ccr_ref,
ccr_name,
vc_uuid)
# By default add an ethernet range to network size 255
ar_str = ""
ar_str << "AR=[\n"
ar_str << "TYPE=\"ETHER\",\n"
ar_str << "SIZE=\"255\"\n"
ar_str << "]\n"
one_vnet[:one] << ar_str
rc = one_vn.allocate(one_vnet[:one])
if ::OpenNebula.is_error?(rc)
error = " Error creating virtual network from template: #{rc.message}. Cannot import the template\n"
#Rollback, delete virtual networks
allocated_networks.each do |n|
n.delete
end
break
end
#Add info for One template
one_vn.info
nic_info << "NIC=[\n"
nic_info << "NETWORK=\"#{one_vn["NAME"]}\",\n"
nic_info << "OPENNEBULA_MANAGED=\"NO\"\n"
nic_info << "]\n"
end
end
return error, nic_info
end
# Checks if a RbVmomi::VIM::VirtualDevice is a disk or a cdrom
def is_disk_or_cdrom?(device)
is_disk = !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil?

View File

@ -60,6 +60,9 @@ begin
# Set reference to template disks in VM template for detach ops
vm.reference_imported_disks
# Set reference to template nics in VM template for detach ops
vm.reference_imported_nics
end
# Resize cloned disks from template if needed