diff --git a/README.md b/README.md index 7093713..e3b26d1 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,31 @@ The current implementation is a proof-of-concept supporting the larger objective of using Vagrant as a cloud management interface for development and production environments. -The plugin has been tested with Vagrant 1.1.4. +The plugin has been tested with Vagrant 1.1.5. Installation ------------ Install the plugin following the typical Vagrant 1.1 procedure: - vagrant plugin install vagrant-hostmanager + $ vagrant plugin install vagrant-hostmanager Usage ----- -The plugin hooks into the `vagrant up` and `vagrant destroy` commands -automatically updating the `/etc/hosts` file on each active machine that -is using the same provider. +To update the `/etc/hosts` file on each active machine, run the following +command: + + $ vagrant hostmanager + +The plugin may hook into the `vagrant up` and `vagrant destroy` commands +automatically to update the `/etc/hosts` file on each active machine that +is using the same provider. To enable this, add the following configuration +to your Vagrant file: + +```ruby +Vagrant.configure('2') do |config| + config.hostmanager.auto_update = true +end +``` A machine's IP address is defined by either the static IP for a private network configuration or by the SSH host configuration. diff --git a/lib/vagrant-hostmanager/action/update_hosts_file.rb b/lib/vagrant-hostmanager/action/update_hosts_file.rb index 761451e..ab08967 100644 --- a/lib/vagrant-hostmanager/action/update_hosts_file.rb +++ b/lib/vagrant-hostmanager/action/update_hosts_file.rb @@ -1,66 +1,31 @@ +require 'vagrant-hostmanager/hosts_file' + module VagrantPlugins module HostManager module Action class UpdateHostsFile + include HostsFile + def initialize(app, env) - @app, @env = app, env + @app = app + @machine = env[:machine] @translator = Helpers::Translator.new('action.update_hosts_file') - @logger = + @logger = Log4r::Logger.new('vagrant_hostmanager::action::update') end def call(env) - global_env = env[:machine].env - current_provider = env[:machine].provider_name + # check config to see if the hosts file should updated automatically + if @machine.config.hostmanager.auto_update + # generate temporary hosts file + machines = generate(@machine.env, @machine.provider_name) - # build a list of host entries based on active machines that - # are using the same provider as the current one - matching_machines = [] - entries = {} - entries['127.0.0.1'] = 'localhost' - global_env.active_machines.each do |name, provider| - if provider == current_provider - machine = global_env.machine(name, provider) - host = machine.config.vm.hostname || name - entries[get_ip_address(machine)] = host - matching_machines << machine - end - end - - # generate hosts file - path = env[:tmp_path].join('hosts') - File.open(path, 'w') do |file| - entries.each_pair do |ip, host| - @logger.info "Adding /etc/hosts entry: #{ip} #{host}" - file << "#{ip}\t#{host}\n" - end - end - - # copy the hosts file to each matching machine - # TODO append hostname to loopback address - matching_machines.each do |machine| - if machine.communicate.ready? - env[:ui].info @translator.t('update', { :name => machine.name }) - machine.communicate.upload(path, '/tmp/hosts') - machine.communicate.sudo("mv /tmp/hosts /etc/hosts") - end + # update /etc/hosts file on each active machine + machines.each { |machine| update(machine) } end @app.call(env) end - - protected - - def get_ip_address(machine) - ip = nil - machine.config.vm.networks.each do |network| - key, options = network[0], network[1] - ip = options[:ip] if key == :private_network - next if ip - end - - ip || machine.ssh_info[:host] - end end end end diff --git a/lib/vagrant-hostmanager/command.rb b/lib/vagrant-hostmanager/command.rb new file mode 100644 index 0000000..10130f6 --- /dev/null +++ b/lib/vagrant-hostmanager/command.rb @@ -0,0 +1,29 @@ +module VagrantPlugins + module HostManager + class Command < Vagrant.plugin('2', :command) + include HostsFile + + def execute + options = {} + opts = OptionParser.new do |o| + o.banner = 'Usage: vagrant hostmanager [vm-name]' + o.separator '' + + o.on('--provider provider', String, + 'Update machines with the specific provider.') do |provider| + options[:provider] = provider + end + end + + argv = parse_options(opts) + options[:provider] ||= @env.default_provider + + generate(@env, options[:provider]) + + with_target_vms(argv[1..-1], :provider => options[:provider]) do |machine| + update(machine) + end + end + end + end +end diff --git a/lib/vagrant-hostmanager/config.rb b/lib/vagrant-hostmanager/config.rb new file mode 100644 index 0000000..21edffe --- /dev/null +++ b/lib/vagrant-hostmanager/config.rb @@ -0,0 +1,20 @@ +module VagrantPlugins + module HostManager + class Config < Vagrant.plugin('2', :config) + attr_accessor :auto_update + + def initialize + @auto_update = false + end + + def validate(machine) + errors = [] + if !(!!@auto_update == @auto_update) + errors << 'auto_update must be a boolean' + end + + { 'hostmanager' => errors } + end + end + end +end diff --git a/lib/vagrant-hostmanager/hosts_file.rb b/lib/vagrant-hostmanager/hosts_file.rb new file mode 100644 index 0000000..075c439 --- /dev/null +++ b/lib/vagrant-hostmanager/hosts_file.rb @@ -0,0 +1,57 @@ +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) + machines = [] + + # define a lambda for looking up a machine's ip address + get_ip_address = lambda do |machine| + ip = nil + machine.config.vm.networks.each do |network| + key, options = network[0], network[1] + ip = options[:ip] if key == :private_network + next if ip + end + ip || machine.ssh_info[:host] + end + + # create the temporary hosts file + path = env.tmp_path.join('hosts') + File.open(path, 'w') do |file| + file << "127.0.0.1\tlocalhost\n" + + # 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 + ip = get_ip_address.call(machine) + @logger.info "Adding /etc/hosts entry: #{ip} #{host}" + file << "#{ip}\t#{host}\n" + end + end + end + + machines + end + + # Copy the temporary hosts file to the specified machine overwritting + # the existing /etc/hosts file. + def update(machine) + path = machine.env.tmp_path.join('hosts') + if machine.communicate.ready? + machine.env.ui.info translator.t('update', { :name => machine.name }) + machine.communicate.upload(path, '/tmp/hosts') + machine.communicate.sudo("mv /tmp/hosts /etc/hosts") + end + end + + def translator + Helpers::Translator.new('hosts_file') + end + end + end +end diff --git a/lib/vagrant-hostmanager/plugin.rb b/lib/vagrant-hostmanager/plugin.rb index 7a97da2..318e27a 100644 --- a/lib/vagrant-hostmanager/plugin.rb +++ b/lib/vagrant-hostmanager/plugin.rb @@ -10,16 +10,26 @@ module VagrantPlugins created for each active machine using the hostname attribute. DESC - action_hook(:hostmanager_up, :machine_action_up) do |hook| + def self.update(hook) setup_i18n setup_logging hook.append(Action::UpdateHostsFile) end - action_hook(:hostmanger_destroy, :machine_action_destroy) do |hook| + config(:hostmanager) do + require_relative 'config' + Config + end + + action_hook(:hostmanager_up, :machine_action_up, &method(:update)) + action_hook(:hostmanger_destroy, :machine_action_destroy, &method(:update)) + + # TODO remove duplication of i18n and logging setup + command(:hostmanager) do setup_i18n setup_logging - hook.append(Action::UpdateHostsFile) + require_relative 'command' + Command end def self.setup_i18n diff --git a/lib/vagrant-hostmanager/version.rb b/lib/vagrant-hostmanager/version.rb index 0317228..5e148a2 100644 --- a/lib/vagrant-hostmanager/version.rb +++ b/lib/vagrant-hostmanager/version.rb @@ -1,5 +1,5 @@ module VagrantPlugins module HostManager - VERSION = '0.0.3' + VERSION = '0.0.4' end end diff --git a/locales/en.yml b/locales/en.yml index 99c6e6c..ad3a2e6 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -1,5 +1,4 @@ en: vagrant_hostmanager: - action: - update_hosts_file: - update: "Updating /etc/hosts file on %{name}" + hosts_file: + update: "[%{name}] Updating /etc/hosts file" diff --git a/test/test.sh b/test/test.sh index 8e31350..178630b 100755 --- a/test/test.sh +++ b/test/test.sh @@ -6,12 +6,13 @@ vagrant ssh server1 -c 'cat /etc/hosts' echo "[server2] /etc/hosts file:" vagrant ssh server2 -c 'cat /etc/hosts' -vagrant halt -vagrant up +vagrant hostmanager -vagrant destroy server1 -f +echo "[server1] /etc/hosts file:" +vagrant ssh server1 -c 'cat /etc/hosts' echo "[server2] /etc/hosts file:" vagrant ssh server2 -c 'cat /etc/hosts' -vagrant destroy server2 -f + +vagrant destroy -f cd ..