diff --git a/src/cli/onevcenter b/src/cli/onevcenter index c42313e867..9529c10f89 100755 --- a/src/cli/onevcenter +++ b/src/cli/onevcenter @@ -214,4 +214,95 @@ cmd=CommandParser::CmdParser.new(ARGV) do exit 0 end + + network_desc = <<-EOT.unindent + Import vCenter networks into OpenNebula + EOT + + command :networks, network_desc, :options=>[ VCENTER, USER, PASS ] do + if options[:vuser].nil? || + options[:vpass].nil? || + options[:vcenter].nil? + STDERR.puts "vCenter connection parameters are mandatory to import"\ + " vCenter networks:\n"\ + "\t --vcenter vCenter hostname\n"\ + "\t --vuser username to login in vcenter\n"\ + "\t --vpass password for the user" + exit -1 + end + + begin + STDOUT.print "\nConnecting to vCenter: #{options[:vcenter]}..." + + vc = VCenterDriver::VIClient.new_connection( + :user => options[:vuser], + :password => options[:vpass], + :host => options[:vcenter]) + + STDOUT.print "done!\n\n" + + STDOUT.print "Looking for vCenter networks..." + + rs = vc.vcenter_networks + + STDOUT.print "done!\n" + + rs.each {|dc, tmps| + STDOUT.print "\nDo you want to process datacenter #{dc} [y/n]? " + + next if STDIN.gets.strip.downcase != 'y' + + if tmps.empty? + STDOUT.print " No Networks found in #{dc}...\n\n" + next + end + + tmps.each{ |n| + print_str = "\n * Network found:\n"\ + " - Name : #{n[:name]}\n"\ + " - Type : #{n[:type]}\n" + print_str += " - VLAN ID : #{n[:vlan]}\n" if n[:vlan] + print_str += " Import this Network [y/n]? " + + STDOUT.print print_str + + next if STDIN.gets.strip.downcase != 'y' + + STDOUT.print " How many VMs are you planning"\ + " to fit into this network [255]? " + + size = STDIN.gets.strip + + size = "255" if size.to_i.to_s != size + + one_vn = ::OpenNebula::VirtualNetwork.new( + ::OpenNebula::Template.build_xml, vc.one) + + vnet_template = "NAME=\"#{n[:name]}\"\n" + + "BRIDGE=\"#{n[:name]}\"\n" + + "VCENTER_TYPE=\"#{n[:type]}\"" + + "AR=[\n" + + " TYPE = \"ETHER\"\n," + + " SIZE = \"#{size.to_i}\"\n]" + + vnet_template += "VLAN=\"YES\"\nVLAN_ID=#{n[:vlan]}" if n[:vlan] + + rc = one_vn.allocate(vnet_template) + + if ::OpenNebula.is_error?(rc) + STDOUT.puts " Error creating virtual network: " + + " #{rc.message}\n" + else + STDOUT.puts " OpenNebula virtual network " + + "#{one_vn.id} created with size #{size}!\n" + end + } + } + rescue Exception => e + STDOUT.puts "error: #{e.message}" + exit -1 + end + + exit 0 + end end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 8abde72f21..5d2fca7d4c 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -129,7 +129,7 @@ class VIClient ######################################################################## # Initialize a VIConnection based just on the VIM parameters. The - # OpenNebula client is also initilialize + # OpenNebula client is also initilialized ######################################################################## def self.new_connection(user_opts) @@ -166,6 +166,23 @@ class VIClient end end + ######################################################################## + # Searches the associated vmFolder of the DataCenter for the current + # connection. Returns a RbVmomi::VIM::VirtualMachine or nil if not found + # @param vm_name [String] the UUID of the VM or VM Template + ######################################################################## + def find_vm(vm_name) + vms = get_entities(@dc.vmFolder, 'VirtualMachine') + + return vms.find do |v| + begin + v.name == vm_name + rescue ManagedObjectNotFound + false + end + end + end + ######################################################################## # Builds a hash with the DataCenter / ClusterComputeResource hierarchy # for this VCenter. @@ -219,6 +236,63 @@ class VIClient return vm_templates end + ######################################################################## + # Builds a hash with the Datacenter / CCR (Distributed)Networks + # for this VCenter + # @return [Hash] in the form + # { dc_name [String] => Networks [Array] } + ######################################################################## + def vcenter_networks + vcenter_networks = {} + + datacenters = get_entities(@root, 'Datacenter') + + datacenters.each { |dc| + networks = get_entities(dc.networkFolder, 'Network' ) + one_nets = [] + + networks.each { |n| + one_nets << {:name => n.name, + :bridge => n.name, + :type => "Port Group"} + } + + vcenter_networks[dc.name] = one_nets + + networks = get_entities(dc.networkFolder, + 'DistributedVirtualPortgroup' ) + one_nets = [] + + networks.each { |n| + one_net = {:name => n.name, + :bridge => n.name, + :type=> "Distributed Port Group"} + + vlan = n.config.defaultPortConfig.vlan.vlanId + + if vlan != 0 + if vlan.is_a? Array + vlan_str = "" + vlan.each{|v| + vlan_str += v.start + ".." + v.end + "," + } + vlan_str.chop! + else + vlan_str = vlan.to_s + end + + one_net[:vlan] = vlan_str + end + + one_nets << one_net + } + + vcenter_networks[dc.name] += one_nets + } + + return vcenter_networks + end + def self.translate_hostname(hostname) host_pool = OpenNebula::HostPool.new(::OpenNebula::Client.new()) rc = host_pool.info @@ -820,7 +894,9 @@ private # Returns the spec to reconfig a VM and add a NIC ######################################################################## def self.calculate_addnic_spec(vm, mac, bridge, model) + model = model.nil? ? nil : model.downcase network = vm.runtime.host.network.select{|n| n.name==bridge} + backing = nil if network.empty? raise "Network #{bridge} not found in host #{vm.runtime.host.name}" @@ -836,8 +912,6 @@ private end } - model = model.nil? ? nil : model.downcase - nic_card = case model when "virtuale1000" RbVmomi::VIM::VirtualE1000 @@ -857,9 +931,19 @@ private RbVmomi::VIM::VirtualE1000 end - backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( - :deviceName => bridge, - :network => network) + if network.class == RbVmomi::VIM::Network + backing = RbVmomi::VIM.VirtualEthernetCardNetworkBackingInfo( + :deviceName => bridge, + :network => network) + else + port = RbVmomi::VIM::DistributedVirtualSwitchPortConnection( + :switchUuid => + network.config.distributedVirtualSwitch.uuid, + :portgroupKey => network.key) + backing = + RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( + :port => port) + end return {:operation => :add, :device => nic_card.new( @@ -920,10 +1004,22 @@ private :powerOn => false, :template => false) - vm = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => "one-#{vmid}", - :spec => clone_spec).wait_for_completion + begin + vm = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion + rescue Exception => e + if e.message.start_with?('DuplicateName') + vm = connection.find_vm("one-#{vmid}") + vm.Destroy_Task.wait_for_completion + vm = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion + end + end + vm_uuid = vm.config.uuid