diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..18b2379 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog + +## 1.4.0 +### Features +* supports vagrant 1.5 [[#80](https://github.com/smdahlen/vagrant-hostmanager/issues/80), [#81](https://github.com/smdahlen/vagrant-hostmanager/pull/81)] +* only updates hosts file if contents have changed [[#78](https://github.com/smdahlen/vagrant-hostmanager/pull/78)] +* custom ip resolver now has access to the machine whose hosts file is being updated [[#62](https://github.com/smdahlen/vagrant-hostmanager/pull/62)] + +### Bug fixes +* custom IP resolver result no longer ignored [[#57](https://github.com/smdahlen/vagrant-hostmanager/pull/57)] +* when multiple private_networks are configured, the first one is used [[#64](https://github.com/smdahlen/vagrant-hostmanager/pull/64)] +* destroyed machines are now removed from hosts file [[#52](https://github.com/smdahlen/vagrant-hostmanager/pull/52)] + +[Full diff](https://github.com/smdahlen/vagrant-hostmanager/compare/v1.3.0...v1.4.0) + + +## 1.3.0 +### Features +* allow defining a custom IP resolver block [[#15](https://github.com/smdahlen/vagrant-hostmanager/pull/15)] +* handle removing destroyed machines from hosts file (currently only works with `include_offline = true`) [[#45](https://github.com/smdahlen/vagrant-hostmanager/pull/45)] +* attempt to elevate privileges when needed in Windows hosts [[#48](https://github.com/smdahlen/vagrant-hostmanager/pull/48)] + +### Bug fixes +* `--provider` command-line option now finds machines as expected [[#46](https://github.com/smdahlen/vagrant-hostmanager/pull/46)] +* uses proper `hosts` file location in Windows under cygwin [[#49](https://github.com/smdahlen/vagrant-hostmanager/pull/49)] + +### Miscelaneous +* MIT license added to gemspec + +[Full diff](https://github.com/smdahlen/vagrant-hostmanager/compare/v1.2.3...v1.3.0) diff --git a/Gemfile b/Gemfile index 137bac0..fecf40e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,9 @@ source 'https://rubygems.org' group :development do - gem 'vagrant', :git => 'git://github.com/mitchellh/vagrant.git', :tag => 'v1.2.7' + gem 'vagrant', :git => 'git://github.com/mitchellh/vagrant.git', :tag => 'v1.5.1' end -gemspec +group :plugins do + gemspec +end diff --git a/lib/vagrant-hostmanager/action/update_all.rb b/lib/vagrant-hostmanager/action/update_all.rb index 7dcdcbe..d2671d9 100644 --- a/lib/vagrant-hostmanager/action/update_all.rb +++ b/lib/vagrant-hostmanager/action/update_all.rb @@ -11,6 +11,14 @@ module VagrantPlugins @machine = env[:machine] @global_env = @machine.env @provider = @machine.provider_name + + # config_global is deprecated from v1.5 + if Gem::Version.new(::Vagrant::VERSION) >= Gem::Version.new('1.5') + @config = @global_env.vagrantfile.config + else + @config = @global_env.config_global + end + @logger = Log4r::Logger.new('vagrant::hostmanager::update_all') end @@ -21,7 +29,7 @@ module VagrantPlugins return @app.call(env) if !@machine.id && env[:machine_action] == :destroy # check config to see if the hosts file should be update automatically - return @app.call(env) unless @global_env.config_global.hostmanager.enabled? + return @app.call(env) unless @config.hostmanager.enabled? @logger.info 'Updating /etc/hosts file automatically' @app.call(env) diff --git a/lib/vagrant-hostmanager/action/update_guest.rb b/lib/vagrant-hostmanager/action/update_guest.rb index 73a7cb1..7ab7352 100644 --- a/lib/vagrant-hostmanager/action/update_guest.rb +++ b/lib/vagrant-hostmanager/action/update_guest.rb @@ -11,6 +11,14 @@ module VagrantPlugins @machine = env[:machine] @global_env = @machine.env @provider = env[:provider] + + # config_global is deprecated from v1.5 + if Gem::Version.new(::Vagrant::VERSION) >= Gem::Version.new('1.5') + @config = @global_env.vagrantfile.config + else + @config = @global_env.config_global + end + @logger = Log4r::Logger.new('vagrant::hostmanager::update_guest') end diff --git a/lib/vagrant-hostmanager/action/update_host.rb b/lib/vagrant-hostmanager/action/update_host.rb index 5418953..8d48255 100644 --- a/lib/vagrant-hostmanager/action/update_host.rb +++ b/lib/vagrant-hostmanager/action/update_host.rb @@ -10,11 +10,19 @@ module VagrantPlugins @app = app @global_env = env[:global_env] @provider = env[:provider] + + # config_global is deprecated from v1.5 + if Gem::Version.new(::Vagrant::VERSION) >= Gem::Version.new('1.5') + @config = @global_env.vagrantfile.config + else + @config = @global_env.config_global + end + @logger = Log4r::Logger.new('vagrant::hostmanager::update_host') end def call(env) - if @global_env.config_global.hostmanager.manage_host? + if @config.hostmanager.manage_host? env[:ui].info I18n.t('vagrant_hostmanager.action.update_host') update_host end diff --git a/lib/vagrant-hostmanager/hosts_file.rb b/lib/vagrant-hostmanager/hosts_file.rb index c1dcf6e..a08be74 100644 --- a/lib/vagrant-hostmanager/hosts_file.rb +++ b/lib/vagrant-hostmanager/hosts_file.rb @@ -25,11 +25,13 @@ module VagrantPlugins # download and modify file with Vagrant-managed entries file = @global_env.tmp_path.join("hosts.#{machine.name}") machine.communicate.download(realhostfile, file) - update_file(file, machine) + if update_file(file, machine, false) + + # upload modified file and remove temporary file + machine.communicate.upload(file, '/tmp/hosts') + machine.communicate.sudo("#{move_cmd} /tmp/hosts #{realhostfile}") + end - # upload modified file and remove temporary file - machine.communicate.upload(file, '/tmp/hosts') - machine.communicate.sudo("#{move_cmd} /tmp/hosts #{realhostfile}") # i have no idea if this is a windows competibility issue or not, but sometimes it dosen't work on my machine begin FileUtils.rm(file) @@ -55,49 +57,36 @@ module VagrantPlugins end FileUtils.cp(hosts_location, file) - update_file(file) - copy_proc.call + if update_file(file) + copy_proc.call + end end private - def update_file(file, resolving_machine=nil) - # build array of host file entries from Vagrant configuration - entries = [] - destroyed_entries = [] - ids = [] - get_machines.each do |name, p| - if @provider == p - machine = @global_env.machine(name, p) - host = machine.config.vm.hostname || name - id = machine.id - ip = get_ip_address(machine, resolving_machine) - aliases = machine.config.hostmanager.aliases.join(' ').chomp - if id.nil? - destroyed_entries << "#{ip}\t#{host} #{aliases}" - else - entries << "#{ip}\t#{host} #{aliases}\t# VAGRANT ID: #{id}\n" - ids << id unless ids.include?(id) - end - end - end + def update_file(file, resolving_machine = nil, include_id = true) + file = Pathname.new(file) + old_file_content = file.read + new_file_content = update_content(old_file_content, resolving_machine, include_id) + file.open('w') { |io| io.write(new_file_content) } + old_file_content != new_file_content + end - tmp_file = Tempfile.open('hostmanager', @global_env.tmp_path, 'a') - begin - # copy each line not managed by Vagrant - File.open(file).each_line do |line| - # Eliminate lines for machines that have been destroyed - next if destroyed_entries.any? { |entry| line =~ /^#{entry}\t# VAGRANT ID: .*/ } - tmp_file << line unless ids.any? { |id| line =~ /# VAGRANT ID: #{id}/ } - end + def update_content(file_content, resolving_machine, include_id) + id = include_id ? " id: #{read_or_create_id}" : "" + header = "## vagrant-hostmanager-start#{id}\n" + footer = "## vagrant-hostmanager-end\n" + body = get_machines + .map { |machine| get_hosts_file_entry(machine, resolving_machine) } + .join + get_new_content(header, footer, body, file_content) + end - # write a line for each Vagrant-managed entry - entries.each { |entry| tmp_file << entry } - ensure - tmp_file.close - FileUtils.cp(tmp_file, file) - tmp_file.unlink - end + def get_hosts_file_entry(machine, resolving_machine) + ip = get_ip_address(machine, resolving_machine) + host = machine.config.vm.hostname || machine.name + aliases = machine.config.hostmanager.aliases.join(' ').chomp + "#{ip}\t#{host} #{aliases}\n" end def get_ip_address(machine, resolving_machine) @@ -110,27 +99,57 @@ module VagrantPlugins machine.config.vm.networks.each do |network| key, options = network[0], network[1] ip = options[:ip] if key == :private_network - next if ip + break if ip end end ip || (machine.ssh_info ? machine.ssh_info[:host] : nil) - end + end end def get_machines - if @global_env.config_global.hostmanager.include_offline? - machines = [] - @global_env.machine_names.each do |name| - begin - @global_env.machine(name, @provider) - machines << [name, @provider] - rescue Vagrant::Errors::MachineNotFound - end - end - machines + if @config.hostmanager.include_offline? + machines = @global_env.machine_names else - @global_env.active_machines + machines = @global_env.active_machines + .select { |name, provider| provider == @provider } + .collect { |name, provider| name } end + # Collect only machines that exist for the current provider + machines.collect do |name| + begin + machine = @global_env.machine(name, @provider) + rescue Vagrant::Errors::MachineNotFound + # ignore + end + machine + end + .reject(&:nil?) + end + + def get_new_content(header, footer, body, old_content) + if body.empty? + block = "\n" + else + block = "\n\n" + header + body + footer + "\n" + end + # Pattern for finding existing block + header_pattern = Regexp.quote(header) + footer_pattern = Regexp.quote(footer) + pattern = Regexp.new("\n*#{header_pattern}.*?#{footer_pattern}\n*", Regexp::MULTILINE) + # Replace existing block or append + old_content.match(pattern) ? old_content.sub(pattern, block) : old_content.rstrip + block + end + + def read_or_create_id + file = Pathname.new("#{@global_env.local_data_path}/hostmanager/id") + if (file.file?) + id = file.read.strip + else + id = SecureRandom.uuid + file.dirname.mkpath + file.open('w') { |io| io.write(id) } + end + id end ## Windows support for copying files, requesting elevated privileges if necessary diff --git a/lib/vagrant-hostmanager/plugin.rb b/lib/vagrant-hostmanager/plugin.rb index 8369d19..86dab08 100644 --- a/lib/vagrant-hostmanager/plugin.rb +++ b/lib/vagrant-hostmanager/plugin.rb @@ -29,6 +29,12 @@ module VagrantPlugins Provisioner end + # Work-around for vagrant >= 1.5 + # It breaks without a provisioner config, so we provide a dummy one + config(:hostmanager, :provisioner) do + ::Vagrant::Config::V2::DummyConfig.new + end + command(:hostmanager) do require_relative 'command' Command diff --git a/lib/vagrant-hostmanager/provisioner.rb b/lib/vagrant-hostmanager/provisioner.rb index 4c5397e..afe027a 100644 --- a/lib/vagrant-hostmanager/provisioner.rb +++ b/lib/vagrant-hostmanager/provisioner.rb @@ -7,11 +7,19 @@ module VagrantPlugins super(machine, config) @global_env = machine.env @provider = machine.provider_name + + # config_global is deprecated from v1.5 + if Gem::Version.new(::Vagrant::VERSION) >= Gem::Version.new('1.5') + @config = @global_env.vagrantfile.config + else + @config = @global_env.config_global + end + end def provision update_guest(@machine) - if @global_env.config_global.hostmanager.manage_host? + if @config.hostmanager.manage_host? update_host end end diff --git a/lib/vagrant-hostmanager/version.rb b/lib/vagrant-hostmanager/version.rb index 6f78a08..6410bd0 100644 --- a/lib/vagrant-hostmanager/version.rb +++ b/lib/vagrant-hostmanager/version.rb @@ -1,5 +1,5 @@ module VagrantPlugins module HostManager - VERSION = '1.3.0' + VERSION = '1.4.0' end end diff --git a/test/Vagrantfile b/test/Vagrantfile index b3a4f31..24683e6 100644 --- a/test/Vagrantfile +++ b/test/Vagrantfile @@ -1,11 +1,18 @@ # -*- mode: ruby -*- # vi: set ft=ruby : -Vagrant.require_plugin('vagrant-hostmanager') +if Gem::Version.new(::Vagrant::VERSION) < Gem::Version.new('1.5') + Vagrant.require_plugin('vagrant-hostmanager') +end Vagrant.configure('2') do |config| - config.vm.box = 'precise64' - config.vm.box_url = 'http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-amd64-disk1.box' + + if ENV.key? 'VAGRANT_BOX' + config.vm.box = ENV['VAGRANT_BOX'] + else + config.vm.box = 'precise64' + config.vm.box_url = 'http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-amd64-disk1.box' + end config.hostmanager.enabled = true config.hostmanager.manage_host = true @@ -20,4 +27,10 @@ Vagrant.configure('2') do |config| server.vm.hostname = 'bender' server.vm.network :private_network, :ip => '10.0.5.3' end -end + + config.vm.define :server3 do |server| + server.vm.hostname = 'leena' + server.vm.network :private_network, :ip => '10.0.5.4' + server.vm.provision :hostmanager + end +end \ No newline at end of file