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

F #4913: Add distributed port group / switches management to Datacenter

This commit is contained in:
mcabrerizo 2017-03-30 13:05:09 +02:00
parent 14c3dff7df
commit 6ab1f325d1

View File

@ -349,6 +349,8 @@ end # class DatatacenterFolder
class Datacenter
attr_accessor :item
DPG_CREATE_TIMEOUT = 240
def initialize(item, vi_client=nil)
if !item.instance_of? RbVmomi::VIM::Datacenter
raise "Expecting type 'RbVmomi::VIM::Datacenter'. " <<
@ -357,6 +359,8 @@ class Datacenter
@vi_client = vi_client
@item = item
@net_rollback = []
@locking = true
end
def datastore_folder
@ -375,6 +379,319 @@ class Datacenter
NetworkFolder.new(@item.networkFolder)
end
# Locking function. Similar to flock
def lock
hostlockname = @item['name'].downcase.tr(" ", "_")
if @locking
@locking_file = File.open("/tmp/vcenter-dc-#{hostlockname}-lock","w")
@locking_file.flock(File::LOCK_EX)
end
end
# Unlock driver execution mutex
def unlock
if @locking
@locking_file.close
end
end
########################################################################
# Check if distributed virtual switch exists in host
########################################################################
def dvs_exists(switch_name, net_folder)
return net_folder.items.values.select{ |dvs|
dvs.instance_of?(VCenterDriver::DistributedVirtualSwitch) &&
dvs['name'] == switch_name
}.first rescue nil
end
########################################################################
# Is the distributed switch for the distributed pg different?
########################################################################
def pg_changes_sw?(dpg, switch_name)
return dpg['config.distributedVirtualSwitch.name'] != switch_name
end
########################################################################
# Create a distributed vcenter switch in a datacenter
########################################################################
def create_dvs(switch_name, pnics, mtu=1500)
# Prepare spec for DVS creation
spec = RbVmomi::VIM::DVSCreateSpec.new
spec.configSpec = RbVmomi::VIM::VMwareDVSConfigSpec.new
spec.configSpec.name = switch_name
# Specify number of uplinks port for dpg
if pnics
pnics = pnics.split(",")
if !pnics.empty?
spec.configSpec.uplinkPortPolicy = RbVmomi::VIM::DVSNameArrayUplinkPortPolicy.new
spec.configSpec.uplinkPortPolicy.uplinkPortName = []
(0..pnics.size-1).each { |index|
spec.configSpec.uplinkPortPolicy.uplinkPortName[index]="dvUplink#{index+1}"
}
end
end
#Set maximum MTU
spec.configSpec.maxMtu = mtu
# The DVS must be created in the networkFolder of the datacenter
begin
dvs_creation_task = @item.networkFolder.CreateDVS_Task(:spec => spec)
dvs_creation_task.wait_for_completion
# If task finished successfuly we rename the uplink portgroup
dvs = nil
if dvs_creation_task.info.state == 'success'
dvs = dvs_creation_task.info.result
dvs.config.uplinkPortgroup[0].Rename_Task(:newName => "#{switch_name}-uplink-pg").wait_for_completion
else
raise "The Distributed vSwitch #{switch_name} could not be created. "
end
rescue Exception => e
raise e
end
@net_rollback << {:action => :delete_dvs, :dvs => dvs, :name => switch_name}
return VCenterDriver::DistributedVirtualSwitch.new(dvs, @vi_client)
end
########################################################################
# Update a distributed vcenter switch
########################################################################
def update_dvs(dvs, pnics, mtu)
# Prepare spec for DVS creation
spec = RbVmomi::VIM::VMwareDVSConfigSpec.new
changed = false
orig_spec = RbVmomi::VIM::VMwareDVSConfigSpec.new
orig_spec.maxMtu = dvs['config.maxMtu']
orig_spec.uplinkPortPolicy = RbVmomi::VIM::DVSNameArrayUplinkPortPolicy.new
orig_spec.uplinkPortPolicy.uplinkPortName = []
(0..dvs['config.uplinkPortgroup'].length-1).each { |index|
orig_spec.uplinkPortPolicy.uplinkPortName[index]="dvUplink#{index+1}"
}
# Add more uplinks to default uplink port group according to number of pnics
if pnics
pnics = pnics.split(",")
if !pnics.empty? && dvs['config.uplinkPortgroup'].length != pnics.size
spec.uplinkPortPolicy = RbVmomi::VIM::DVSNameArrayUplinkPortPolicy.new
spec.uplinkPortPolicy.uplinkPortName = []
(dvs['config.uplinkPortgroup'].length..num_pnics-1).each { |index|
spec.uplinkPortPolicy.uplinkPortName[index]="dvUplink#{index+1}"
}
changed = true
end
end
#Set maximum MTU
if mtu != dvs['config.maxMtu']
spec.maxMtu = mtu
changed = true
end
# The DVS must be created in the networkFolder of the datacenter
if changed
spec.configVersion = dvs['config.configVersion']
begin
dvs.item.ReconfigureDvs_Task(:spec => spec).wait_for_completion
rescue Exception => e
raise "The Distributed switch #{dvs['name']} could not be updated. "\
"Reason: #{e.message}"
end
@net_rollback << {:action => :update_dvs, :dvs => dvs.item, :name => dvs['name'], :spec => orig_spec}
end
end
########################################################################
# Remove a distributed vcenter switch in a datacenter
########################################################################
def remove_dvs(dvs)
begin
dvs.item.Destroy_Task.wait_for_completion
rescue
#Ignore destroy task exception
end
end
########################################################################
# Check if distributed port group exists in datacenter
########################################################################
def dpg_exists(pg_name, net_folder)
return net_folder.items.values.select{ |dpg|
dpg.instance_of?(VCenterDriver::DistributedPortGroup) &&
dpg['name'] == pg_name
}.first rescue nil
end
########################################################################
# Create a distributed vcenter port group
########################################################################
def create_dpg(dvs, pg_name, vlan_id, num_ports)
spec = RbVmomi::VIM::DVPortgroupConfigSpec.new
# OpenNebula use DVS static port binding with autoexpand
if num_ports
spec.autoExpand = true
spec.numPorts = num_ports
end
# Distributed port group name
spec.name = pg_name
# Set VLAN information
spec.defaultPortConfig = RbVmomi::VIM::VMwareDVSPortSetting.new
spec.defaultPortConfig.vlan = RbVmomi::VIM::VmwareDistributedVirtualSwitchVlanIdSpec.new
spec.defaultPortConfig.vlan.vlanId = vlan_id
spec.defaultPortConfig.vlan.inherited = false
# earlyBinding. A free DistributedVirtualPort will be selected and
# assigned to a VirtualMachine when the virtual machine is reconfigured
# to connect to the portgroup.
spec.type = "earlyBinding"
begin
dvs.item.AddDVPortgroup_Task(spec: [spec]).wait_for_completion
rescue Exception => e
raise "The Distributed port group #{pg_name} could not be created. "\
"Reason: #{e.message}"
end
# wait until the network is ready and we have a reference
portgroups = dvs['portgroup'].select{ |dpg|
dpg.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup) &&
dpg['name'] == pg_name
}
(0..DPG_CREATE_TIMEOUT).each do
break if !portgroups.empty?
portgroups = dvs['portgroup'].select{ |dpg|
dpg.instance_of?(RbVmomi::VIM::DistributedVirtualPortgroup) &&
dpg['name'] == pg_name
}
sleep 1
end
raise "Cannot get VCENTER_NET_REF for new distributed port group" if portgroups.empty?
@net_rollback << {:action => :delete_dpg, :dpg => portgroups.first, :name => pg_name}
return portgroups.first._ref
end
########################################################################
# Update a distributed vcenter port group
########################################################################
def update_dpg(dpg, vlan_id, num_ports)
spec = RbVmomi::VIM::DVPortgroupConfigSpec.new
changed = false
orig_spec = RbVmomi::VIM::DVPortgroupConfigSpec.new
orig_spec.numPorts = dpg['config.numPorts']
orig_spec.defaultPortConfig = RbVmomi::VIM::VMwareDVSPortSetting.new
orig_spec.defaultPortConfig.vlan = RbVmomi::VIM::VmwareDistributedVirtualSwitchVlanIdSpec.new
orig_spec.defaultPortConfig.vlan.vlanId = dpg['config.defaultPortConfig.vlan.vlanId']
orig_spec.defaultPortConfig.vlan.inherited = false
if num_ports && num_ports != orig_spec.numPorts
spec.numPorts = num_ports
changed = true
end
# earlyBinding. A free DistributedVirtualPort will be selected and
# assigned to a VirtualMachine when the virtual machine is reconfigured
# to connect to the portgroup.
spec.type = "earlyBinding"
if vlan_id != orig_spec.defaultPortConfig.vlan.vlanId
spec.defaultPortConfig = RbVmomi::VIM::VMwareDVSPortSetting.new
spec.defaultPortConfig.vlan = RbVmomi::VIM::VmwareDistributedVirtualSwitchVlanIdSpec.new
spec.defaultPortConfig.vlan.vlanId = vlan_id
spec.defaultPortConfig.vlan.inherited = false
changed = true
end
if changed
spec.configVersion = dpg['config.configVersion']
begin
dpg.item.ReconfigureDVPortgroup_Task(:spec => spec).wait_for_completion
rescue Exception => e
raise "The Distributed port group #{dpg['name']} could not be created. "\
"Reason: #{e.message}"
end
@net_rollback << {:action => :update_dpg, :dpg => dpg.item, :name => dpg['name'], :spec => orig_spec}
end
end
########################################################################
# Remove distributed port group from datacenter
########################################################################
def remove_dpg(dpg)
begin
dpg.item.Destroy_Task.wait_for_completion
rescue RbVmomi::VIM::ResourceInUse => e
STDERR.puts "The distributed portgroup #{dpg["name"]} is in use so it cannot be deleted"
return nil
rescue Exception => e
raise "The Distributed portgroup #{dpg["name"]} could not be deleted. Reason: #{e.message} "
end
end
########################################################################
# Perform vcenter network rollback operations
########################################################################
def network_rollback
@net_rollback.reverse_each do |nr|
case nr[:action]
when :update_dpg
begin
nr[:dpg].ReconfigureDVPortgroupConfigSpec_Task(:spec => nr[:spec])
rescue Exception => e
raise "A rollback operation for distributed port group #{nr[:name]} could not be performed. Reason: #{e.message}"
end
when :update_dvs
begin
nr[:dvs].ReconfigureDvs_Task(:spec => nr[:spec])
rescue Exception => e
raise "A rollback operation for distributed standard switch #{nr[:name]} could not be performed. Reason: #{e.message}"
end
when :delete_dvs
begin
nr[:dvs].Destroy_Task.wait_for_completion
rescue RbVmomi::VIM::ResourceInUse
return #Ignore if switch in use
rescue RbVmomi::VIM::NotFound
return #Ignore if switch not found
rescue Exception => e
raise "A rollback operation for standard switch #{nr[:name]} could not be performed. Reason: #{e.message}"
end
when :delete_dpg
begin
nr[:dpg].Destroy_Task.wait_for_completion
rescue RbVmomi::VIM::ResourceInUse
return #Ignore if pg in use
rescue RbVmomi::VIM::NotFound
return #Ignore if pg not found
rescue Exception => e
raise "A rollback operation for standard port group #{nr[:name]} could not be performed. Reason: #{e.message}"
end
end
end
end
def self.new_from_ref(ref, vi_client)
self.new(RbVmomi::VIM::Datacenter.new(vi_client.vim, ref), vi_client)
end