diff --git a/Gemfile b/Gemfile index e9c9b79..2fbd2ae 100644 --- a/Gemfile +++ b/Gemfile @@ -5,3 +5,7 @@ gemspec group :development do gem 'vagrant', :git => 'git://github.com/mitchellh/vagrant.git' end + +group :plugins do + gem "vagrant-vcenter", path: "." +end diff --git a/README.md b/README.md index 03fa370..c4567a1 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,30 @@ [Vagrant](http://www.vagrantup.com) provider for VMware vCenter® ============= -[Version 0.1.1](../../releases/tag/v0.1.1) has been released! +[Version 0.2.0](../../releases/tag/v0.2.0) has been released! ------------- Please note that this software is still Alpha/Beta quality and is not recommended for production usage. Right now a [Precise32](http://vagrant.gosddc.com/boxes/precise32-vcenter.box) is available for use, or you can roll your own as you please, make sure to install VMware tools in it. +Changes in [version 0.2.0](../../releases/tag/v0.2.0) include: + +New Features + +- Add option to set the actual vm name +- Set some options in the vm via linux prep +- Static networking +- Hostname +- Add option to set vmnetwork name and backing +- Vagrant now uses builtin ```SyncedFolders``` helper to synchronize folders + +Fixes + +- Fix the read_ssh_info if the vm doesn't have a network yet at first try the later ssh's wont forever fail + +Many thanks to @BarnacleBob for submitting PR #4 with all these new features! + Changes in [version 0.1.1](../../releases/tag/v0.1.1) include: - Support for ```vagrant share``` [Fixes [#2](../../issues/2)] diff --git a/lib/vagrant-vcenter/action.rb b/lib/vagrant-vcenter/action.rb index 7950a5d..8209441 100644 --- a/lib/vagrant-vcenter/action.rb +++ b/lib/vagrant-vcenter/action.rb @@ -14,7 +14,7 @@ def self.action_boot Vagrant::Action::Builder.new.tap do |b| b.use PowerOn b.use Provision - b.use SyncFolders + b.use SyncedFolders end end @@ -114,7 +114,7 @@ def self.action_provision next end b2.use Provision - b2.use SyncFolders + b2.use SyncedFolders end end end @@ -224,8 +224,6 @@ def self.action_up action_root.join('resume') autoload :Suspend, action_root.join('suspend') - autoload :SyncFolders, - action_root.join('sync_folders') end end end diff --git a/lib/vagrant-vcenter/action/build_vm.rb b/lib/vagrant-vcenter/action/build_vm.rb index 5cf5d01..f5ea14d 100644 --- a/lib/vagrant-vcenter/action/build_vm.rb +++ b/lib/vagrant-vcenter/action/build_vm.rb @@ -93,12 +93,73 @@ def call(env) :location => relocate_spec, :powerOn => false, :template => false) + + if config.vm_network_name or config.num_cpu or config.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" + 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) + card.backing = RbVmomi::VIM.VirtualEthernetCardDistributedVirtualPortBackingInfo( + :port => switch_port) + else + abort "vm network type of #{config.vm_network_type} is unknown" + 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 or config.enable_vm_customization == 'true' + gIPSettings = RbVmomi::VIM.CustomizationGlobalIPSettings( + :dnsServerList => config.dns_server_list, + :dnsSuffixList => config.dns_suffix_list) + + prep = RbVmomi::VIM.CustomizationLinuxPrep( + :domain => env[:machine].name, + :hostName => RbVmomi::VIM.CustomizationFixedName( + :name => env[:machine].name)) + + adapter = RbVmomi::VIM.CustomizationIPSettings( + :gateway => [config.gateway], + :ip => RbVmomi::VIM.CustomizationFixedIp( + :ipAddress => config.ipaddress), + :subnetMask => config.netmask) + + nic_map = [RbVmomi::VIM.CustomizationAdapterMapping( + :adapter => adapter)] + + cust_spec = RbVmomi::VIM.CustomizationSpec( + :globalIPSettings => gIPSettings, + :identity => prep, + :nicSettingMap => nic_map) + + spec.customization = cust_spec + end @logger.debug("Spec: #{spec.pretty_inspect}") - vm_target = "Vagrant-#{Etc.getlogin}-" + - "#{vm_name}-#{Socket.gethostname.downcase}-" + - "#{SecureRandom.hex(4)}" + @logger.debug("disable_auto_vm_name: #{config.disable_auto_vm_name}") + + if config.disable_auto_vm_name or config.disable_auto_vm_name == 'true' + vm_target = vm_name.to_s + else + vm_target = "Vagrant-#{Etc.getlogin}-" + + "#{vm_name}-#{Socket.gethostname.downcase}-" + + "#{SecureRandom.hex(4)}" + end @logger.debug("VM name: #{vm_target}") diff --git a/lib/vagrant-vcenter/action/power_on.rb b/lib/vagrant-vcenter/action/power_on.rb index 7c810e0..13d91bd 100644 --- a/lib/vagrant-vcenter/action/power_on.rb +++ b/lib/vagrant-vcenter/action/power_on.rb @@ -21,7 +21,7 @@ def call(env) # Poweron VM env[:ui].info('Powering on VM...') vm.PowerOnVM_Task.wait_for_completion - sleep(3) until env[:machine].communicate.ready? + sleep(20) until env[:machine].communicate.ready? @app.call env end end diff --git a/lib/vagrant-vcenter/action/read_ssh_info.rb b/lib/vagrant-vcenter/action/read_ssh_info.rb index 8a8aec6..3373b52 100644 --- a/lib/vagrant-vcenter/action/read_ssh_info.rb +++ b/lib/vagrant-vcenter/action/read_ssh_info.rb @@ -27,9 +27,19 @@ def read_ssh_info(env) root_vm_folder = dc.vmFolder vm = root_vm_folder.findByUuid(env[:machine].id) - @logger.debug("IP Address: #{vm.guest.ipAddress}") + address = vm.guest.ipAddress + if not address or address == '' + address = vm.guest_ip + end - { :host => vm.guest.ipAddress, :port => 22 } + if not address or address == '' + # if we can't find it right away just return nil. it will retry + # till the vmware tools supplies the ip address back to vcenter + @logger.debug('could not find booted guest ipaddress') + return nil + end + + { :host => address, :port => 22 } end end end diff --git a/lib/vagrant-vcenter/action/sync_folders.rb b/lib/vagrant-vcenter/action/sync_folders.rb deleted file mode 100644 index 190230e..0000000 --- a/lib/vagrant-vcenter/action/sync_folders.rb +++ /dev/null @@ -1,135 +0,0 @@ -# The MIT License (MIT) -# Copyright (c) 2013 Mitchell Hashimoto - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. - -require 'log4r' -require 'vagrant/util/subprocess' -require 'vagrant/util/scoped_hash_override' -require 'vagrant/util/which' - -module VagrantPlugins - module VCenter - module Action - # This class syncs Vagrant folders using RSYNC, this code has been ported - # from vagrant-aws (https://github.com/mitchellh/vagrant-aws) - class SyncFolders - include Vagrant::Util::ScopedHashOverride - - def initialize(app, env) - @app = app - @logger = Log4r::Logger.new('vagrant_vcenter::action::sync_folders') - end - - def call(env) - @app.call(env) - - ssh_info = env[:machine].ssh_info - - unless Vagrant::Util::Which.which('rsync') - env[:ui].warn(I18n.t('vagrant_vcenter.sync.rsync_not_found_warning', - :side => 'host')) - return - end - - if env[:machine].communicate.execute('which rsync', - :error_check => false) != 0 - env[:ui].warn(I18n.t('vagrant_vcenter.sync.rsync_not_found_warning', - :side => 'guest')) - return - end - - env[:machine].config.vm.synced_folders.each do |id, data| - data = scoped_hash_override(data, :vCenter) - - # Ignore disabled shared folders - next if data[:disabled] - - hostpath = File.expand_path(data[:hostpath], env[:root_path]) - guestpath = data[:guestpath] - - # Make sure there is a trailing slash on the host path to - # avoid creating an additional directory with rsync - hostpath = "#{hostpath}/" if hostpath !~ /\/$/ - - # on windows rsync.exe requires cygdrive-style paths - if Vagrant::Util::Platform.windows? - hostpath = hostpath.gsub(/^(\w):/) { "/cygdrive/\1" } - end - - env[:ui].info(I18n.t('vagrant_vcenter.sync.rsync_folder', - :hostpath => hostpath, - :guestpath => guestpath)) - - # Create the host path if it doesn't exist and option flag is set - if data[:create] - begin - FileUtils.mkdir_p(hostpath) - rescue => err - raise Errors::MkdirError, - :hostpath => hostpath, - :err => err - end - end - - # Create the guest path - env[:machine].communicate.sudo("mkdir -p '#{guestpath}'") - env[:machine].communicate.sudo( - "chown -R #{ssh_info[:username]} '#{guestpath}'") - - # collect rsync excludes specified :rsync_excludes=>['path1',...] - # in synced_folder options - excludes = ['.vagrant/', 'Vagrantfile', - *Array(data[:rsync_excludes])].uniq - - # Rsync over to the guest path using the SSH info - command = [ - 'rsync', '--verbose', '--archive', '-z', - *excludes.map { |e|['--exclude', e] }.flatten, - '-e', "ssh -p #{ssh_info[:port]} -o StrictHostKeyChecking=no " + - "#{ssh_key_options(ssh_info)}", hostpath, - "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"] - - # we need to fix permissions when using rsync.exe on windows, see - # http://stackoverflow.com/questions/5798807/rsync-permission- - # denied-created-directories-have-no-permissions - if Vagrant::Util::Platform.windows? - command.insert(1, '--chmod', 'ugo=rwX') - end - - r = Vagrant::Util::Subprocess.execute(*command) - if r.exit_code != 0 - fail Errors::RsyncError, - :guestpath => guestpath, - :hostpath => hostpath, - :stderr => r.stderr - end - end - end - - private - - def ssh_key_options(ssh_info) - # Ensure that `private_key_path` is an Array (for Vagrant < 1.4) - Array(ssh_info[:private_key_path]).map { |path| "-i '#{path}' " }.join - end - end - end - end -end diff --git a/lib/vagrant-vcenter/config.rb b/lib/vagrant-vcenter/config.rb index f5e5aea..8daa5b2 100644 --- a/lib/vagrant-vcenter/config.rb +++ b/lib/vagrant-vcenter/config.rb @@ -58,6 +58,74 @@ class Config < Vagrant.plugin('2', :config) # @return [Bool] attr_accessor :linked_clones + # Disable automatic safe vm name generation + # + # @return [Bool] + attr_accessor :disable_auto_vm_name + + # Use prep and customization api in the building + # of the vm in vcenter + # + # Mostly this allows the static ip configuration + # of a vm + # + # @return [Bool] + attr_accessor :enable_vm_customization + + # Type of the machine prep to use + # + # @return [String] + attr_accessor :prep_type + + # Dns server list + # + # @return [Array] + attr_accessor :dns_server_list + + # Dns suffix list + # + # @return [Array] + attr_accessor :dns_suffix_list + + # network gateway + # + # @return [String] + attr_accessor :gateway + + # subnet mask + # + # @return [String] + attr_accessor :netmask + + # ip address + # + # @return [String] + attr_accessor :ipaddress + + # vm network name + # + # @return [String] + attr_accessor :vm_network_name + + # vm network type + # only supported network type + # DistributedVirtualSwitchPort + # + # @return [String] + attr_accessor :vm_network_type + + # num cpu + # + # @return [Fixnum] + attr_accessor :num_cpu + + # memory in MB + # + # @return [Fixnum] + attr_accessor :memory + + + ## ## vCenter config runtime values ## @@ -66,6 +134,14 @@ class Config < Vagrant.plugin('2', :config) attr_accessor :vcenter_cnx attr_accessor :template_id + def initialize() + @enable_vm_customization = false + @prep_type = 'linux' + @enable_vm_customization = false + @dns_server_list = [] + @dns_suffix_list = [] + end + def validate(machine) errors = _detected_errors @@ -85,6 +161,17 @@ def validate(machine) errors << I18n.t('vagrant_vcenter.config.network_name') if network_name.nil? + if enable_vm_customization + errors << + I18n.t('vagrant_vcenter.config.no_prep_type') if prep_type != 'linux' + errors << + I18n.t('vagrant_vcenter.config.gateway') if gateway.empty? + errors << + I18n.t('vagrant_vcenter.config.ipaddress') if ipaddress.empty? + errors << + I18n.t('vagrant_vcenter.config.netmask') if netmask.empty? + end + { 'vCenter Provider' => errors } end end diff --git a/lib/vagrant-vcenter/version.rb b/lib/vagrant-vcenter/version.rb index 1a93ea8..b612640 100644 --- a/lib/vagrant-vcenter/version.rb +++ b/lib/vagrant-vcenter/version.rb @@ -1,6 +1,6 @@ module VagrantPlugins # Set version for vagrant-vcenter gem. module VCenter - VERSION = '0.1.1' + VERSION = '0.2.0' end end diff --git a/locales/en.yml b/locales/en.yml index d05efdb..ea42783 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -9,12 +9,6 @@ en: VM is already running vm_halted_cannot_suspend: |- VM is not running or already suspended, cannot suspend it. - sync: - rsync_not_found_warning: |- - Warning! Folder sync disabled because the rsync binary is missing. - Make sure rsync is installed and the binary can be found in the PATH. - rsync_folder: |- - Rsyncing folder: %{hostpath} => %{guestpath} config: hostname: |- Configuration must specify a vCenter hostname @@ -32,6 +26,14 @@ en: Configuration must specify a resource pool name resourcepool_name: |- Configuration must specify a resource pool name + no_prep_type: |- + The only supported prep type is linux. hack away. + ipaddress: |- + Configuration must specify a ipaddress + gateway: |- + Configuration must specify a gateway + netmask: |- + Configuration must specify a netmask states: not_created: |- The environment has not yet been created. Run `vagrant up` to