Finish support for managing host /etc/hosts file.
This commit moves logic into action middleware and ensures that config validation is executed when the hostmanager command is called.
This commit is contained in:
parent
064d9b8658
commit
4ce7cd498e
31
README.md
31
README.md
|
@ -1,17 +1,9 @@
|
|||
Vagrant Host Manager
|
||||
====================
|
||||
`vagrant-hostmanager` is a Vagrant 1.1+ plugin that manages the `/etc/hosts`
|
||||
file on guest machines. Its goal is to enable resolution of multi-machine
|
||||
environments deployed with a cloud provider where IP addresses are not known
|
||||
in advance.
|
||||
|
||||
Status
|
||||
------
|
||||
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.5.
|
||||
file on guest machines (and optionally the host). Its goal is to enable
|
||||
resolution of multi-machine environments deployed with a cloud provider
|
||||
where IP addresses are not known in advance.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
@ -32,6 +24,9 @@ machines with the same provider will have their `/etc/hosts` file updated
|
|||
accordingly. Set the `hostmanager.enabled` attribute to `true` in the
|
||||
Vagrantfile to activate this behavior.
|
||||
|
||||
To update the host's `/etc/hosts` file, set the `hostmanager.manage_host`
|
||||
attribute to `true`.
|
||||
|
||||
A machine's IP address is defined by either the static IP for a private
|
||||
network configuration or by the SSH host configuration. To disable
|
||||
using the private network IP address, set `config.hostmanger.ignore_private_ip`
|
||||
|
@ -40,9 +35,8 @@ to true.
|
|||
A machine's host name is defined by `config.vm.hostname`. If this is not
|
||||
set, it falls back to the symbol defining the machine in the Vagrantfile.
|
||||
|
||||
When using include_offline set to true, only boxes that are up or have a
|
||||
private ip configured will be added to the hosts file. You will receive a
|
||||
warning on skipped boxes.
|
||||
If the `hostmanager.include_offline` attribute is set to `true`, boxes that are
|
||||
up or have a private ip configured will be added to the hosts file.
|
||||
|
||||
In addition, the `hostmanager.aliases` configuration attribute can be used
|
||||
to provide aliases for your host names.
|
||||
|
@ -52,17 +46,18 @@ Example configuration:
|
|||
```ruby
|
||||
Vagrant.configure("2") do |config|
|
||||
config.hostmanager.enabled = true
|
||||
config.hostmanager.manage_host = true
|
||||
config.hostmanager.ignore_private_ip = false
|
||||
config.hostmanager.include_offline = true
|
||||
config.vm.define "example-box" do |node|
|
||||
node.vm.hostname = "example-box-hostname"
|
||||
node.vm.network :private_network, ip: "192.168.42.42"
|
||||
config.vm.define 'example-box' do |node|
|
||||
node.vm.hostname = 'example-box-hostname'
|
||||
node.vm.network :private_network, ip: '192.168.42.42'
|
||||
node.hostmanager.aliases = %w(example-box.localdomain example-box-alias)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
As a last option, you can also choose hostmanager as a provisioner.
|
||||
As a last option, you can use hostmanager as a provisioner.
|
||||
This allows you to use the provisioning order to ensure that hostmanager
|
||||
runs before or after provisioning. The provisioner will collect hosts from
|
||||
boxes with the same provider as the running box.
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
require 'vagrant-hostmanager/action/update_all'
|
||||
require 'vagrant-hostmanager/action/update_guest'
|
||||
require 'vagrant-hostmanager/action/update_host'
|
||||
|
||||
module VagrantPlugins
|
||||
module HostManager
|
||||
module Action
|
||||
include Vagrant::Action::Builtin
|
||||
|
||||
def self.update_all
|
||||
Vagrant::Action::Builder.new.tap do |builder|
|
||||
builder.use ConfigValidate
|
||||
builder.use UpdateAll
|
||||
end
|
||||
end
|
||||
|
||||
def self.update_guest
|
||||
Vagrant::Action::Builder.new.tap do |builder|
|
||||
builder.use ConfigValidate
|
||||
builder.use UpdateGuest
|
||||
end
|
||||
end
|
||||
|
||||
def self.update_host
|
||||
Vagrant::Action::Builder.new.tap do |builder|
|
||||
builder.use UpdateHost
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,19 +3,22 @@ require 'vagrant-hostmanager/hosts_file'
|
|||
module VagrantPlugins
|
||||
module HostManager
|
||||
module Action
|
||||
class UpdateHostsFile
|
||||
class UpdateAll
|
||||
include HostsFile
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@machine = env[:machine]
|
||||
@logger = Log4r::Logger.new('vagrant::hostmanager::update_hosts_file')
|
||||
@global_env = @machine.env
|
||||
@provider = @machine.provider_name
|
||||
@logger = Log4r::Logger.new('vagrant::hostmanager::update_all')
|
||||
end
|
||||
|
||||
def call(env)
|
||||
# check if machine is already active
|
||||
return @app.call(env) if @machine.id
|
||||
@logger.info 'Continuing update of hosts file for new machine'
|
||||
# skip if machine is already active on up action
|
||||
return @app.call(env) if @machine.id && env[:machine_action] == :up
|
||||
# skip if machine is not active on destroy action
|
||||
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 @machine.config.hostmanager.enabled?
|
||||
|
@ -25,12 +28,17 @@ module VagrantPlugins
|
|||
|
||||
# update /etc/hosts file on active machines
|
||||
env[:ui].info I18n.t('vagrant_hostmanager.action.update_guests')
|
||||
update_guests(@machine.env, @machine.provider_name)
|
||||
@global_env.active_machines.each do |name, p|
|
||||
if p == @provider
|
||||
machine = @global_env.machine(name, p)
|
||||
update_guest(machine)
|
||||
end
|
||||
end
|
||||
|
||||
# update /etc/hosts files on host if enabled
|
||||
if @machine.config.hostmanager.manage_host?
|
||||
env[:ui].info I18n.t('vagrant_hostmanager.action.update_host')
|
||||
update_host(@machine.env, @machine.provider_name)
|
||||
update_host
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require 'vagrant-hostmanager/hosts_file'
|
||||
|
||||
module VagrantPlugins
|
||||
module HostManager
|
||||
module Action
|
||||
class UpdateGuest
|
||||
include HostsFile
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@machine = env[:machine]
|
||||
@global_env = @machine.env
|
||||
@provider = env[:provider]
|
||||
@logger = Log4r::Logger.new('vagrant::hostmanager::update_guest')
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[:ui].info I18n.t('vagrant_hostmanager.action.update_guest', {
|
||||
:name => @machine.name
|
||||
})
|
||||
update_guest(@machine)
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require 'vagrant-hostmanager/hosts_file'
|
||||
|
||||
module VagrantPlugins
|
||||
module HostManager
|
||||
module Action
|
||||
class UpdateHost
|
||||
include HostsFile
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@global_env = env[:global_env]
|
||||
@provider = env[:provider]
|
||||
@logger = Log4r::Logger.new('vagrant::hostmanager::update_host')
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if @global_env.config_global.hostmanager.manage_host?
|
||||
env[:ui].info I18n.t('vagrant_hostmanager.action.update_host')
|
||||
update_host
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,7 +6,7 @@ module VagrantPlugins
|
|||
def execute
|
||||
options = {}
|
||||
opts = OptionParser.new do |o|
|
||||
o.banner = 'Usage: vagrant hostmanager'
|
||||
o.banner = 'Usage: vagrant hostmanager [vm-name]'
|
||||
o.separator ''
|
||||
o.version = VagrantPlugins::HostManager::VERSION
|
||||
o.program_name = 'vagrant hostmanager'
|
||||
|
@ -17,14 +17,22 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
parse_options(opts)
|
||||
|
||||
argv = parse_options(opts)
|
||||
options[:provider] ||= @env.default_provider
|
||||
|
||||
update_guests(@env, options[:provider])
|
||||
if (@env.config_global.hostmanager.manage_host?)
|
||||
update_host(@env, options[:provider])
|
||||
# update /etc/hosts file for specified guest machines
|
||||
with_target_vms(argv, options) do |machine|
|
||||
@env.action_runner.run(Action.update_guest, {
|
||||
:machine => machine,
|
||||
:provider => options[:provider]
|
||||
})
|
||||
end
|
||||
|
||||
# update /etc/hosts file for host
|
||||
@env.action_runner.run(Action.update_host, {
|
||||
:global_env => @env,
|
||||
:provider => options[:provider]
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,35 +3,25 @@ require 'tempfile'
|
|||
module VagrantPlugins
|
||||
module HostManager
|
||||
module HostsFile
|
||||
def update_guests(env, provider)
|
||||
entries = get_entries(env, provider)
|
||||
|
||||
# update hosts file on each active machine with matching provider
|
||||
env.active_machines.each do |name, p|
|
||||
if provider == p
|
||||
target = env.machine(name, p)
|
||||
next unless target.communicate.ready?
|
||||
def update_guest(machine)
|
||||
return unless machine.communicate.ready?
|
||||
|
||||
# download and modify file with Vagrant-managed entries
|
||||
file = env.tmp_path.join("hosts.#{name}")
|
||||
target.communicate.download('/etc/hosts', file)
|
||||
update_file(file, entries, env.tmp_path)
|
||||
file = @global_env.tmp_path.join("hosts.#{machine.name}")
|
||||
machine.communicate.download('/etc/hosts', file)
|
||||
update_file(file)
|
||||
|
||||
# upload modified file and remove temporary file
|
||||
target.communicate.upload(file, '/tmp/hosts')
|
||||
target.communicate.sudo('mv /tmp/hosts /etc/hosts')
|
||||
machine.communicate.upload(file, '/tmp/hosts')
|
||||
machine.communicate.sudo('mv /tmp/hosts /etc/hosts')
|
||||
FileUtils.rm(file)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_host(env, provider)
|
||||
entries = get_entries(env, provider)
|
||||
|
||||
def update_host
|
||||
# copy and modify hosts file on host with Vagrant-managed entries
|
||||
file = env.tmp_path.join('hosts.local')
|
||||
file = @global_env.tmp_path.join('hosts.local')
|
||||
FileUtils.cp('/etc/hosts', file)
|
||||
update_file(file, entries, env.tmp_path)
|
||||
update_file(file)
|
||||
|
||||
# copy modified file using sudo for permission
|
||||
`sudo cp #{file} /etc/hosts`
|
||||
|
@ -39,8 +29,21 @@ module VagrantPlugins
|
|||
|
||||
private
|
||||
|
||||
def update_file(file, entries, tmp_path)
|
||||
tmp_file = Tempfile.open('hostmanager', tmp_path, 'a')
|
||||
def update_file(file)
|
||||
# build array of host file entries from Vagrant configuration
|
||||
entries = []
|
||||
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)
|
||||
aliases = machine.config.hostmanager.aliases.join(' ').chomp
|
||||
entries << "#{ip}\t#{host} #{aliases}\t# VAGRANT ID: #{id}\n"
|
||||
end
|
||||
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|
|
||||
|
@ -56,22 +59,6 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
def get_entries(env, provider)
|
||||
entries = []
|
||||
get_machines(env, provider).each do |name, p|
|
||||
if provider == p
|
||||
machine = env.machine(name, p)
|
||||
host = machine.config.vm.hostname || name
|
||||
id = machine.id
|
||||
ip = get_ip_address(machine)
|
||||
aliases = machine.config.hostmanager.aliases.join(' ').chomp
|
||||
entries << "#{ip}\t#{host} #{aliases}\t# VAGRANT ID: #{id}\n"
|
||||
end
|
||||
end
|
||||
|
||||
entries
|
||||
end
|
||||
|
||||
def get_ip_address(machine)
|
||||
ip = nil
|
||||
if machine.config.hostmanager.ignore_private_ip != true
|
||||
|
@ -84,20 +71,20 @@ module VagrantPlugins
|
|||
ip || (machine.ssh_info ? machine.ssh_info[:host] : nil)
|
||||
end
|
||||
|
||||
def get_machines(env, provider)
|
||||
def get_machines
|
||||
# check if offline machines should be included in host entries
|
||||
if env.config_global.hostmanager.include_offline?
|
||||
if @global_env.config_global.hostmanager.include_offline?
|
||||
machines = []
|
||||
env.machine_names.each do |name|
|
||||
@global_env.machine_names.each do |name|
|
||||
begin
|
||||
env.machine(name, provider)
|
||||
machines << [name, provider]
|
||||
@global_env.machine(name, @provider)
|
||||
machines << [name, @provider]
|
||||
rescue Vagrant::Errors::MachineNotFound
|
||||
end
|
||||
end
|
||||
machines
|
||||
else
|
||||
env.active_machines
|
||||
@global_env.active_machines
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'vagrant-hostmanager/action/update_hosts_file'
|
||||
require 'vagrant-hostmanager/action'
|
||||
|
||||
module VagrantPlugins
|
||||
module HostManager
|
||||
|
@ -17,11 +17,11 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
action_hook(:hostmanager, :machine_action_up) do |hook|
|
||||
hook.prepend(Action::UpdateHostsFile)
|
||||
hook.prepend(Action.update_all)
|
||||
end
|
||||
|
||||
action_hook(:hostmanager, :machine_action_destroy) do |hook|
|
||||
hook.append(Action::UpdateHostsFile)
|
||||
hook.prepend(Action.update_all)
|
||||
end
|
||||
|
||||
provisioner(:hostmanager) do
|
||||
|
|
|
@ -3,10 +3,16 @@ module VagrantPlugins
|
|||
class Provisioner < Vagrant.plugin('2', :provisioner)
|
||||
include HostsFile
|
||||
|
||||
def initialize(machine, config)
|
||||
super(machine, config)
|
||||
@global_env = machine.env
|
||||
@provider = machine.provider_name
|
||||
end
|
||||
|
||||
def provision
|
||||
update_guests(@machine.env, @machine.provider_name)
|
||||
if @machine.env.config_global.hostmanager.manage_host?
|
||||
update_host(@machine.env, @machine.provider_name)
|
||||
update_guest(@machine)
|
||||
if @global_env.config_global.hostmanager.manage_host?
|
||||
update_host
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ en:
|
|||
vagrant_hostmanager:
|
||||
action:
|
||||
update_guests: "Updating /etc/hosts file on active guest machines..."
|
||||
update_guest: "[%{name}] Updating /etc/hosts file..."
|
||||
update_host: "Updating /etc/hosts file on host machine (password may be required)..."
|
||||
config:
|
||||
not_a_bool: "A value for %{config_key} can only be true or false, not type '%{value}'"
|
||||
|
|
Loading…
Reference in New Issue