diff --git a/lib/vagrant-hostmanager/action/delete_guests.rb b/lib/vagrant-hostmanager/action/delete_guests.rb new file mode 100644 index 0000000..505350d --- /dev/null +++ b/lib/vagrant-hostmanager/action/delete_guests.rb @@ -0,0 +1,32 @@ +require 'vagrant-hostmanager/hosts_file' + +module VagrantPlugins + module HostManager + module Action + class DeleteGuests + include HostsFile + + def initialize(app, env) + @app = app + @machine = env[:machine] + @logger = Log4r::Logger.new('vagrant::hostmanager::delete_hosts_file') + end + + def call(env) + # check if machine is already active + #return @app.call(env) if @machine.id + + # check config to see if the hosts file should be update automatically + return @app.call(env) unless @machine.config.hostmanager.enabled? + @logger.info 'Updating /etc/hosts file automatically' + + # continue the action stack so the machine will be created + @app.call(env) + + # update /etc/hosts file on each active machine + delete_guests(@machine,@machine.provider_name) + end + end + end + end +end diff --git a/lib/vagrant-hostmanager/action/update_hosts_file.rb b/lib/vagrant-hostmanager/action/update_guests.rb similarity index 78% rename from lib/vagrant-hostmanager/action/update_hosts_file.rb rename to lib/vagrant-hostmanager/action/update_guests.rb index 292b7f6..c495bf0 100644 --- a/lib/vagrant-hostmanager/action/update_hosts_file.rb +++ b/lib/vagrant-hostmanager/action/update_guests.rb @@ -3,18 +3,18 @@ require 'vagrant-hostmanager/hosts_file' module VagrantPlugins module HostManager module Action - class UpdateHostsFile + class UpdateGuests include HostsFile def initialize(app, env) @app = app @machine = env[:machine] - @logger = Log4r::Logger.new('vagrant::hostmanager::update_hosts_file') + @logger = Log4r::Logger.new('vagrant::hostmanager::update_guests') end def call(env) # check if machine is already active - return @app.call(env) if @machine.id + #return @app.call(env) if @machine.id # check config to see if the hosts file should be update automatically return @app.call(env) unless @machine.config.hostmanager.enabled? @@ -24,8 +24,7 @@ module VagrantPlugins @app.call(env) # update /etc/hosts file on each active machine - machines = generate(@machine.env, @machine.provider_name) - machines.each { |machine| update(machine) } + update_guests(@machine,@machine.provider_name) end end end diff --git a/lib/vagrant-hostmanager/command.rb b/lib/vagrant-hostmanager/command.rb index 5a75621..7b886fb 100644 --- a/lib/vagrant-hostmanager/command.rb +++ b/lib/vagrant-hostmanager/command.rb @@ -18,10 +18,8 @@ module VagrantPlugins argv = parse_options(opts) options[:provider] ||= @env.default_provider - generate(@env, options[:provider].to_sym) - with_target_vms(argv, options) do |machine| - update(machine) + update_guests(machine, machine.provider_name) update_local(machine) end end diff --git a/lib/vagrant-hostmanager/hosts_file.rb b/lib/vagrant-hostmanager/hosts_file.rb index 6f92f58..6330de8 100644 --- a/lib/vagrant-hostmanager/hosts_file.rb +++ b/lib/vagrant-hostmanager/hosts_file.rb @@ -1,36 +1,64 @@ module VagrantPlugins module HostManager module HostsFile - # Generate a hosts file containing the the active machines - # in the Vagrant environment backed by the specified provider. - # The file is written to the Vagrant temporary path. - def generate(env, provider) + def update_guests(machine, provider) machines = [] - + env = machine.env # create the temporary hosts file - path = env.tmp_path.join('hosts') - File.open(path, 'w') do |file| - file << "127.0.0.1\tlocalhost\slocalhost.localdomain\n" + path = env.tmp_path - # add a hosts entry for each active machine matching the provider - env.active_machines.each do |name, p| - if provider == p - machines << machine = env.machine(name, provider) - host = machine.config.vm.hostname || name - id = machine.id - ip = get_ip_address(machine) - host_aliases = machine.config.hostmanager.aliases.join("\s").chomp - host_entry = "#{ip}\t#{host}\s#{host_aliases}\n" - @logger.info "Adding /etc/hosts entry: #{ip} #{host} #{host_aliases} #{id}" - file << "#{host_entry}" - end + #fetch hosts file from each machine + #for each machine, ensure all machine entries are updated + # add a hosts entry for each active machine matching the provider + env.active_machines.each do |name, p| + if provider == p + machines << machine = env.machine(name, provider) + machine.communicate.download('/etc/hosts',path.join("hosts.#{name}")) end end + env.active_machines.each do |name, p| + if provider == p + machines.each do |m| + @logger.info "Adding entry for #{m.name} to hosts.#{name}" + update_entry(m,path.join("hosts.#{name}")) + m.communicate.upload(path.join("hosts.#{name}"), '/tmp/hosts') + m.communicate.sudo("mv /tmp/hosts /etc/hosts") + end + end + end machines end + # delete victim machine from all guests + def delete_guests(victim, provider) + machines = [] + + env = victim.env + # create the temporary hosts file + path = env.tmp_path + + #fetch hosts file from each machine + #for each machine, ensure all machine entries are updated + # add a hosts entry for each active machine matching the provider + env.active_machines.each do |name, p| + if provider == p + machines << machine = env.machine(name, provider) + machine.communicate.download('/etc/hosts',path.join("hosts.#{name}")) + delete_entry(victim,path.join("hosts.#{name}")) + if machine.communicate.ready? + machine.env.ui.info I18n.t('vagrant_hostmanager.action.update_guest', { + :name => machine.name + }) + machine.communicate.upload(path.join("hosts.#{name}"), '/tmp/hosts') + machine.communicate.sudo("mv /tmp/hosts /etc/hosts") + end + end + end + end + + # define a lambda for looking up a machine's ip address def get_ip_address(machine) ip = nil @@ -44,42 +72,65 @@ module VagrantPlugins ip || machine.ssh_info[:host] end - def update_local(machine) - return if machine.id.nil? - tmplocal=machine.env.tmp_path.join('hosts.local') - delete_local(machine) + def update_entry(machine,file_name,sudo=false) + delete_entry(machine,file_name,sudo) host = machine.config.vm.hostname || name id = machine.id ip = get_ip_address(machine) host_aliases = machine.config.hostmanager.aliases.join("\s").chomp host_entry = "#{ip}\t#{host}\s#{host_aliases}\s# VAGRANT: #{id}\n" - @logger.info "Adding /etc/hosts entry: #{ip} #{host} #{host_aliases} # #{id} - #{tmplocal}" - File.open(tmplocal,'a') do |tmpfile| - tmpfile << host_entry + @logger.info "Adding /etc/hosts entry: #{host_entry}" + temp_file_name = Dir::Tmpname.make_tmpname(File.join(machine.env.tmp_path,'hostmanager'), nil) + FileUtils.cp(file_name, temp_file_name) + File.open(temp_file_name,'a') do |tempfile| + @logger.info "writing #{host_entry} to #{tempfile.path}" + tempfile << host_entry end - publish_local(machine.env) + if sudo == false + @logger.info "copy #{temp_file_name} #{file_name}" + FileUtils.cp(temp_file_name,file_name) + else + machine.env.ui.info I18n.t('vagrant_hostmanager.action.run_sudo') + @logger.warn "Running sudo to replace local hosts file, enter your local password if prompted..." + @logger.info `sudo cp -v #{temp_file_name} #{file_name}` + end + end + def delete_entry(machine,file_name,sudo=false) + host = machine.config.vm.hostname || name + temp_file_name = Dir::Tmpname.make_tmpname(File.join(machine.env.tmp_path,'hostmanager'), nil) + tempfile = File.open(temp_file_name,'w') do |f| + File.open(file_name,'r').each_line do |line| + if line.match(/#{machine.id}$/).nil? + f << line + else + @logger.info "Matched #{machine.id}" + end + end + end + if sudo == false + @logger.info "copy #{temp_file_name} #{file_name}" + FileUtils.cp(temp_file_name,file_name) + else + machine.env.ui.info I18n.t('vagrant_hostmanager.action.run_sudo') + @logger.info `sudo cp -v #{temp_file_name} #{file_name}` + end + end + + def update_local(machine) + return if machine.id.nil? + update_entry(machine,'/etc/hosts',true) end def delete_local(machine) return if machine.id.nil? - tmplocal=machine.env.tmp_path.join('hosts.local') - File.open(tmplocal, 'w') do |tmpfile| - File.open('/etc/hosts','r').each_line do |line| - if line.match(/#{machine.id}$/).nil? - @logger.info "Found #{machine.id} in hosts file" - tmpfile << line - end - end - end - publish_local(machine.env) + delete_entry(machine,'/etc/hosts',true) end - def publish_local(env) - @logger.info `sudo cp -v /etc/hosts /etc/hosts.bak` - @logger.info `sudo cp -v #{env.tmp_path.join('hosts.local')} /etc/hosts` + def publish_local(tempfile) + @logger.info `sudo cp -v #{tempfile} /etc/hosts` end @@ -88,11 +139,12 @@ module VagrantPlugins def update(machine) path = machine.env.tmp_path.join('hosts') if machine.communicate.ready? - machine.env.ui.info I18n.t('vagrant_hostmanager.action.update', { + machine.env.ui.info I18n.t('vagrant_hostmanager.action.update_guest', { :name => machine.name }) + machine.communicate.download(path, '/etc/hosts') machine.communicate.upload(path, '/tmp/hosts') - machine.communicate.sudo("mv /tmp/hosts /etc/hosts.hostmanager") + machine.communicate.sudo("mv /tmp/hosts /etc/hosts") end end end diff --git a/lib/vagrant-hostmanager/plugin.rb b/lib/vagrant-hostmanager/plugin.rb index 197dce8..f0af8d7 100644 --- a/lib/vagrant-hostmanager/plugin.rb +++ b/lib/vagrant-hostmanager/plugin.rb @@ -1,4 +1,5 @@ -require 'vagrant-hostmanager/action/update_hosts_file' +require 'vagrant-hostmanager/action/delete_guests' +require 'vagrant-hostmanager/action/update_guests' require 'vagrant-hostmanager/action/update_local_entry' require 'vagrant-hostmanager/action/delete_local_entry' @@ -16,14 +17,18 @@ module VagrantPlugins Config end + action_hook(self::ALL_ACTIONS) do |hook| + hook.after(VagrantPlugins::ProviderVirtualBox::Action::Boot, Action::UpdateGuests) + end + action_hook(:hostmanager, :machine_action_up) do |hook| - hook.prepend(Action::UpdateHostsFile) + hook.prepend(Action::UpdateGuests) hook.prepend(Action::UpdateLocalEntry) end action_hook(:hostmanager, :machine_action_destroy) do |hook| hook.prepend(Action::DeleteLocalEntry) - hook.append(Action::UpdateHostsFile) + hook.append(Action::DeleteGuests) end command(:hostmanager) do diff --git a/locales/en.yml b/locales/en.yml index f8d2ea2..7bcb324 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -1,4 +1,6 @@ en: vagrant_hostmanager: action: - update: "[%{name}] Updating /etc/hosts file" + update_guest: "[%{name}] Updating /etc/hosts file" + update_host: "Updating local /etc/hosts file" + run_sudo: "Running sudo to modify host machine's /etc/hosts file"