lib/vagrant-vcenter/action/build_vm.rb in vagrant-vcenter-0.3.2 vs lib/vagrant-vcenter/action/build_vm.rb in vagrant-vcenter-0.3.3

- old
+ new

@@ -1,8 +1,5 @@ -require 'securerandom' -require 'etc' - module VagrantPlugins module VCenter module Action # This class builds the VM to be used by Vagrant. class BuildVM @@ -13,71 +10,64 @@ def call(env) # FIXME: we need to find a way to clean things up when a SIGINT get # called... see env[:interrupted] in the vagrant code - config = env[:machine].provider_config + cfg = env[:machine].provider_config vm_name = env[:machine].name - # FIXME: Raise a correct exception - dc = config.vcenter_cnx.serviceInstance.find_datacenter( - config.datacenter_name) or abort 'datacenter not found' - - if env[:machine].box.name.to_s.include? '/' - box_file = env[:machine].box.name.rpartition('/').last.to_s - box_name = env[:machine].box.name.to_s.gsub(/\//, '-') + if env[:machine].box.name.include? '/' + # box_file = env[:machine].box.name.rpartition('/').last + box_name = env[:machine].box.name.gsub(/\//, '-') else - box_file = env[:machine].box.name.to_s + box_file = env[:machine].box.name box_name = box_file end - if config.template_folder_name.nil? + if cfg.template_folder_name.nil? box_to_search = box_name else - box_to_search = config.template_folder_name + '/' + - box_name + box_to_search = cfg.template_folder_name + '/' + box_name end - # FIXME: Raise a correct exception - computer = dc.find_compute_resource( - config.computer_name) or fail 'Host not found' - - if config.resourcepool_name - rp = computer.resourcePool.resourcePool.find { - |f| f.name == config.resourcepool_name + if cfg.resourcepool_name + cfg.compute_rp = compute.resourcePool.resourcePool.find { + |f| f.name == cfg.resourcepool_name } else - rp = computer.resourcePool + cfg.compute_rp = cfg.compute.resourcePool end - # FIXME: Raise a correct exception - template = dc.find_vm( - box_to_search) or abort 'VM not found' + template = cfg.datacenter.find_vm(box_to_search) or + fail Errors::VMNotFound, + :vm_name => box_to_search - if config.linked_clones + if cfg.linked_clones @logger.debug('DOING LINKED CLONE!') # The API for linked clones is quite strange. We can't create a # linked straight from any VM. The disks of the VM for which we can # create a linked clone need to be read-only and thus VC demands # that the VM we are cloning from uses delta-disks. Only then it # will allow us to share the base disk. # # Thus, this code first create a delta disk on top of the base disk # for the to-be-cloned VM, if delta disks aren't used already. disks = template.config.hardware.device.grep( - RbVmomi::VIM::VirtualDisk) + RbVmomi::VIM::VirtualDisk + ) + disks.select { |x| x.backing.parent.nil? }.each do |disk| spec = { :deviceChange => [ { - :operation => :remove, - :device => disk + :operation => :remove, + :device => disk }, { - :operation => :add, - :fileOperation => :create, - :device => disk.dup.tap do |x| + :operation => :add, + :fileOperation => :create, + :device => disk.dup.tap do |x| x.backing = x.backing.dup x.backing.fileName = "[#{disk.backing.datastore.name}]" x.backing.parent = disk.backing end } @@ -85,154 +75,172 @@ } template.ReconfigVM_Task(:spec => spec).wait_for_completion end relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - :diskMoveType => :moveChildMostDiskBacking, - :pool => rp) + :diskMoveType => :moveChildMostDiskBacking, + :pool => cfg.compute_rp + ) else relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - :pool => rp) + :pool => cfg.compute_rp + ) end @logger.debug("Relocate Spec: #{relocate_spec.pretty_inspect}") spec = RbVmomi::VIM.VirtualMachineCloneSpec( - :location => relocate_spec, - :powerOn => false, - :template => false) - - if config.vm_network_name or config.num_cpu or config.memory + :location => relocate_spec, + :powerOn => false, + :template => false + ) + + if cfg.vm_network_name || cfg.num_cpu || cfg.memory config_spec = RbVmomi::VIM.VirtualMachineConfigSpec - config_spec.numCPUs = config.num_cpu if config.num_cpu - config_spec.memoryMB = config.memory if config.memory - - if config.vm_network_name - # First we must find the specified network - network = dc.network.find { |f| f.name == config.vm_network_name } or - abort "Could not find network with name #{config.vm_network_name} to join vm to" + config_spec.numCPUs = cfg.num_cpu if cfg.num_cpu + config_spec.memoryMB = cfg.memory if cfg.memory + + if cfg.vm_network_name card = template.config.hardware.device.grep( - RbVmomi::VIM::VirtualEthernetCard).first or - abort "could not find network card to customize" - if config.vm_network_type == "DistributedVirtualSwitchPort" - switch_port = RbVmomi::VIM.DistributedVirtualSwitchPortConnection( - :switchUuid => network.config.distributedVirtualSwitch.uuid, - :portgroupKey => network.key) + RbVmomi::VIM::VirtualEthernetCard + ).first or abort 'could not find network card to customize' + + if cfg.vm_network_type == 'DistributedVirtualSwitchPort' + switch_port = + RbVmomi::VIM.DistributedVirtualSwitchPortConnection( + :switchUuid => cfg.network.config.distributedVirtualSwitch.uuid, + :portgroupKey => cfg.network.key + ) card.backing = RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( - :port => switch_port) - end - dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec(:device => card, :operation => "edit") + :port => switch_port + ) + end + + dev_spec = RbVmomi::VIM.VirtualDeviceConfigSpec( + :device => card, + :operation => 'edit' + ) config_spec.deviceChange = [dev_spec] end spec.config = config_spec end - if config.enable_vm_customization + if cfg.enable_vm_customization public_networks = env[:machine].config.vm.networks.select { - |n| n[0].eql? :public_network + |n| n[0].eql? :public_network } network_spec = public_networks.first[1] unless public_networks.empty? @logger.debug("This is our network #{public_networks.inspect}") if network_spec - # Check for sanity and validation of network parameters. - - # Specify ip but no netmask - if network_spec[:ip] && !network_spec[:netmask] + if (network_spec[:ip] && !network_spec[:netmask]) || + (!network_spec[:ip] && network_spec[:netmask]) fail Errors::WrongNetworkSpec end - # specify netmask but no ip - if !network_spec[:ip] && network_spec[:netmask] - fail Errors::WrongNetworkSpec - end - global_ip_settings = RbVmomi::VIM.CustomizationGlobalIPSettings( - :dnsServerList => network_spec[:dns_server_list], - :dnsSuffixList => network_spec[:dns_suffix_list]) + :dnsServerList => network_spec[:dns_server_list], + :dnsSuffixList => network_spec[:dns_suffix_list] + ) # if no ip and no netmask, let's default to dhcp if !network_spec[:ip] && !network_spec[:netmask] adapter = RbVmomi::VIM.CustomizationIPSettings( - :ip => RbVmomi::VIM.CustomizationDhcpIpGenerator()) + :ip => RbVmomi::VIM.CustomizationDhcpIpGenerator() + ) else adapter = RbVmomi::VIM.CustomizationIPSettings( - :gateway => [network_spec[:gateway]], - :ip => RbVmomi::VIM.CustomizationFixedIp( - :ipAddress => network_spec[:ip]), - :subnetMask => network_spec[:netmask]) + :gateway => [network_spec[:gateway]], + :ip => RbVmomi::VIM.CustomizationFixedIp( + :ipAddress => network_spec[:ip] + ), + :subnetMask => network_spec[:netmask] + ) end - nic_map = [RbVmomi::VIM.CustomizationAdapterMapping( - :adapter => adapter)] + nic_map = [ + RbVmomi::VIM.CustomizationAdapterMapping(:adapter => adapter) + ] end - if config.prep_type.downcase == 'linux' + if cfg.prep_type.downcase == 'linux' prep = RbVmomi::VIM.CustomizationLinuxPrep( - :domain => env[:machine].name.to_s.sub(/^[^.]+\./, ''), - :hostName => RbVmomi::VIM.CustomizationFixedName( - :name => env[:machine].name.to_s.split('.')[0])) - elsif config.prep_type.downcase == 'windows' + :domain => env[:machine].name.to_s.sub(/^[^.]+\./, ''), + :hostName => RbVmomi::VIM.CustomizationFixedName( + :name => env[:machine].name.to_s.split('.')[0] + ) + ) + elsif cfg.prep_type.downcase == 'windows' prep = RbVmomi::VIM.CustomizationSysprep( - :guiUnattended => RbVmomi::VIM.CustomizationGuiUnattended( - :autoLogon => false, - :autoLogonCount => 0, - :timeZone => 004 - ), - :identification => RbVmomi::VIM.CustomizationIdentification(), - :userData => RbVmomi::VIM.CustomizationUserData( - :computerName => RbVmomi::VIM.CustomizationFixedName( - :name => env[:machine].name.to_s.split('.')[0]), - :fullName => 'Vagrant', - :orgName => 'Vagrant', - :productId => 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX' - ) + :guiUnattended => RbVmomi::VIM.CustomizationGuiUnattended( + :autoLogon => false, + :autoLogonCount => 0, + :timeZone => 004 + ), + :identification => RbVmomi::VIM.CustomizationIdentification(), + :userData => RbVmomi::VIM.CustomizationUserData( + :computerName => RbVmomi::VIM.CustomizationFixedName( + :name => env[:machine].name.to_s.split('.')[0] + ), + :fullName => 'Vagrant', + :orgName => 'Vagrant', + :productId => 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX' + ) ) - else - fail "specification type #{config.prep_type} not supported" + else + fail Errors::GuestCustomNotSupported, + :type => cfg.prep_type end if prep && network_spec - # If prep and network specification are present, let's do a full config + # If prep and network specification are present, + # -> Do a full config cust_spec = RbVmomi::VIM.CustomizationSpec( - :globalIPSettings => global_ip_settings, - :identity => prep, - :nicSettingMap => nic_map) + :globalIPSettings => global_ip_settings, + :identity => prep, + :nicSettingMap => nic_map + ) spec.customization = cust_spec elsif prep && !network_spec # If no network specifications, default to dhcp global_ip_settings = RbVmomi::VIM.CustomizationGlobalIPSettings( :dnsServerList => [], - :dnsSuffixList => []) + :dnsSuffixList => [] + ) adapter = RbVmomi::VIM.CustomizationIPSettings( - :ip => RbVmomi::VIM.CustomizationDhcpIpGenerator()) + :ip => RbVmomi::VIM.CustomizationDhcpIpGenerator() + ) - nic_map = [RbVmomi::VIM.CustomizationAdapterMapping( - :adapter => adapter)] + nic_map = [ + RbVmomi::VIM.CustomizationAdapterMapping(:adapter => adapter) + ] cust_spec = RbVmomi::VIM.CustomizationSpec( - :globalIPSettings => global_ip_settings, - :identity => prep, - :nicSettingMap => nic_map) + :globalIPSettings => global_ip_settings, + :identity => prep, + :nicSettingMap => nic_map + ) spec.customization = cust_spec end @logger.debug("Spec: #{spec.pretty_inspect}") end - @logger.debug("disable_auto_vm_name: #{config.disable_auto_vm_name}") + @logger.debug("disable_auto_vm_name: #{cfg.disable_auto_vm_name}") - if config.disable_auto_vm_name || config.disable_auto_vm_name == 'true' - vm_target = vm_name.to_s + # Not recommended in a vSphere environment where VM names might + # conflict a lot if used in the same vm folder namespace + if cfg.disable_auto_vm_name == true + vm_target = vm_name else vm_target = "Vagrant-#{Etc.getlogin}-" + "#{vm_name}-#{Socket.gethostname.downcase}-" + "#{SecureRandom.hex(4)}" end @@ -240,46 +248,51 @@ @logger.debug("VM name: #{vm_target}") # FIXME: vm.parent brings us to the template folder, fix this with # folder_path. - root_vm_folder = dc.vmFolder - vm_folder = root_vm_folder - unless config.folder_name.nil? + vm_folder = cfg.vmfolder + unless cfg.folder_name.nil? begin # Better ask for forgiveness than permission ;-) - @logger.debug("Creating folder #{config.folder_name}.") - vm_folder = root_vm_folder.traverse(config.folder_name, - RbVmomi::VIM::Folder, - create = true) + @logger.debug("Creating folder #{cfg.folder_name}.") + vm_folder = cfg.vmfolder.traverse( + cfg.folder_name, + RbVmomi::VIM::Folder, + create = true + ) # FIXME: we should trap the correct exception rescue RbVmomi::Fault # if somebody else created the folder already... - @logger.debug("Folder #{config.folder_name} already exists.") - vm_folder = root_vm_folder.traverse(config.folder_name, - RbVmomi::VIM::Folder) + @logger.debug("Folder #{cfg.folder_name} already exists.") + vm_folder = cfg.vmfolder.traverse( + cfg.folder_name, + RbVmomi::VIM::Folder + ) end end @logger.debug("folder for VM: #{vm_folder}") env[:ui].info('Creating VM...') template.CloneVM_Task( - :folder => vm_folder, - :name => vm_target, - :spec => spec).wait_for_completion + :folder => vm_folder, + :name => vm_target, + :spec => spec + ).wait_for_completion - if config.folder_name.nil? - vm_to_search = vm_target + if cfg.folder_name.nil? + vm_to_search = vm_target.to_s else - vm_to_search = config.folder_name + '/' + vm_target + vm_to_search = cfg.folder_name + '/' + vm_target.to_s end @logger.debug("VM to search: #{vm_to_search}") - # FIXME: Raise a correct exception - env[:machine].id = dc.find_vm( - vm_to_search).config.uuid or abort 'VM not found' + env[:machine].id = cfg.datacenter.find_vm( + vm_to_search + ).config.uuid or fail Errors::VMNotFound, + :vm_name => vm_to_search @app.call env end end end