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