vagrant-hostmanager 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -72,6 +72,41 @@ Use:
72
72
  config.vm.provision :hostmanager
73
73
  ```
74
74
 
75
+ Custom IP resolver
76
+ ------------------
77
+
78
+ You can customize way, how host manager resolves IP address
79
+ for each machine. This might be handy in case of aws provider,
80
+ where host name is stored in ssh_info hash of each machine.
81
+ This causes generation of invalid /etc/hosts file.
82
+
83
+ Custom IP resolver gives you oportunity to calculate IP address
84
+ for each machine by yourself. For example:
85
+
86
+ ```ruby
87
+ config.hostmanager.ip_resolver = proc do |vm|
88
+ if hostname = (vm.ssh_info && vm.ssh_info[:host])
89
+ `host #{hostname}`.split("\n").last[/(\d+\.\d+\.\d+\.\d+)/, 1]
90
+ end
91
+ end
92
+ ```
93
+
94
+ Windows support
95
+ ---------------
96
+
97
+ Hostmanager will detect Windows guests and hosts and use the appropriate
98
+ path for the ```hosts``` file: ```%WINDIR%\System32\drivers\etc\hosts```
99
+
100
+ By default on a Windows host, the ```hosts``` file is not writable without
101
+ elevated privileges. If hostmanager detects that it cannot overwrite the file,
102
+ it will attempt to do so with elevated privileges, causing the
103
+ [UAC](http://en.wikipedia.org/wiki/User_Account_Control) prompt to appear.
104
+
105
+ ### UAC limitations
106
+
107
+ Due to limitations caused by UAC, cancelling out of the UAC prompt will not cause any
108
+ visible errors, however the ```hosts``` file will not be updated.
109
+
75
110
  Contribute
76
111
  ----------
77
112
  Contributions are welcome.
@@ -13,7 +13,7 @@ module VagrantPlugins
13
13
 
14
14
  o.on('--provider provider', String,
15
15
  'Update machines with the specific provider.') do |provider|
16
- options[:provider] = provider
16
+ options[:provider] = provider.to_sym
17
17
  end
18
18
  end
19
19
 
@@ -6,6 +6,7 @@ module VagrantPlugins
6
6
  attr_accessor :ignore_private_ip
7
7
  attr_accessor :aliases
8
8
  attr_accessor :include_offline
9
+ attr_accessor :ip_resolver
9
10
 
10
11
  alias_method :enabled?, :enabled
11
12
  alias_method :include_offline?, :include_offline
@@ -17,6 +18,9 @@ module VagrantPlugins
17
18
  @ignore_private_ip = UNSET_VALUE
18
19
  @include_offline = UNSET_VALUE
19
20
  @aliases = []
21
+ @aliases = Array.new
22
+ @include_offline = false
23
+ @ip_resolver = nil
20
24
  end
21
25
 
22
26
  def finalize!
@@ -35,7 +39,8 @@ module VagrantPlugins
35
39
  errors << validate_bool('hostmanager.include_offline', @include_offline)
36
40
  errors.compact!
37
41
 
38
- if !machine.config.hostmanager.aliases.kind_of?(Array) and
42
+ # check if aliases option is an Array
43
+ if !machine.config.hostmanager.aliases.kind_of?(Array) &&
39
44
  !machine.config.hostmanager.aliases.kind_of?(String)
40
45
  errors << I18n.t('vagrant_hostmanager.config.not_an_array_or_string', {
41
46
  :config_key => 'hostmanager.aliases',
@@ -43,7 +48,16 @@ module VagrantPlugins
43
48
  })
44
49
  end
45
50
 
46
- { 'HostManager configuration' => errors }
51
+ if !machine.config.hostmanager.ip_resolver.nil? &&
52
+ !machine.config.hostmanager.ip_resolver.kind_of?(Proc)
53
+ errors << I18n.t('vagrant_hostmanager.config.not_a_proc', {
54
+ :config_key => 'hostmanager.ip_resolver',
55
+ :is_class => ip_resolver.class.to_s,
56
+ })
57
+ end
58
+
59
+ errors.compact!
60
+ { "HostManager configuration" => errors }
47
61
  end
48
62
 
49
63
  private
@@ -8,13 +8,13 @@ module VagrantPlugins
8
8
 
9
9
  if (machine.communicate.test("uname -s | grep SunOS"))
10
10
  realhostfile = '/etc/inet/hosts'
11
- move_cmd = 'mv'
11
+ move_cmd = 'mv'
12
12
  elsif (machine.communicate.test("test -d $Env:SystemRoot"))
13
- realhostfile = 'C:\Windows\System32\Drivers\etc\hosts'
14
- move_cmd = 'mv -force'
13
+ realhostfile = "#{ENV['WINDIR']}\\System32\\drivers\\etc\\hosts"
14
+ move_cmd = 'mv -force'
15
15
  else
16
16
  realhostfile = '/etc/hosts'
17
- move_cmd = 'mv'
17
+ move_cmd = 'mv'
18
18
  end
19
19
  # download and modify file with Vagrant-managed entries
20
20
  file = @global_env.tmp_path.join("hosts.#{machine.name}")
@@ -34,19 +34,23 @@ module VagrantPlugins
34
34
  def update_host
35
35
  # copy and modify hosts file on host with Vagrant-managed entries
36
36
  file = @global_env.tmp_path.join('hosts.local')
37
- # add a "if windows..."
38
- hosts_location = '/etc/hosts'
39
- copy_cmd = 'sudo cp'
40
- # handles the windows hosts file...
41
- if ENV['OS'] == 'Windows_NT'
37
+
38
+ if WindowsSupport.windows?
39
+ # lazily include windows Module
40
+ class << self
41
+ include WindowsSupport unless include? WindowsSupport
42
+ end
43
+
42
44
  hosts_location = "#{ENV['WINDIR']}\\System32\\drivers\\etc\\hosts"
43
- copy_cmd = 'cp'
45
+ copy_proc = Proc.new { windows_copy_file(file, hosts_location) }
46
+ else
47
+ hosts_location = '/etc/hosts'
48
+ copy_proc = Proc.new { `sudo cp #{file} #{hosts_location}` }
44
49
  end
50
+
45
51
  FileUtils.cp(hosts_location, file)
46
52
  update_file(file)
47
-
48
- # copy modified file using sudo for permission
49
- `#{copy_cmd} #{file} #{hosts_location}`
53
+ copy_proc.call
50
54
  end
51
55
 
52
56
  private
@@ -54,6 +58,7 @@ module VagrantPlugins
54
58
  def update_file(file)
55
59
  # build array of host file entries from Vagrant configuration
56
60
  entries = []
61
+ destroyed_entries = []
57
62
  ids = []
58
63
  get_machines.each do |name, p|
59
64
  if @provider == p
@@ -62,8 +67,12 @@ module VagrantPlugins
62
67
  id = machine.id
63
68
  ip = get_ip_address(machine)
64
69
  aliases = machine.config.hostmanager.aliases.join(' ').chomp
65
- entries << "#{ip}\t#{host} #{aliases}\t# VAGRANT ID: #{id}\n"
66
- ids << id unless ids.include?(id)
70
+ if id.nil?
71
+ destroyed_entries << "#{ip}\t#{host} #{aliases}"
72
+ else
73
+ entries << "#{ip}\t#{host} #{aliases}\t# VAGRANT ID: #{id}\n"
74
+ ids << id unless ids.include?(id)
75
+ end
67
76
  end
68
77
  end
69
78
 
@@ -71,6 +80,8 @@ module VagrantPlugins
71
80
  begin
72
81
  # copy each line not managed by Vagrant
73
82
  File.open(file).each_line do |line|
83
+ # Eliminate lines for machines that have been destroyed
84
+ next if destroyed_entries.any? { |entry| line =~ /^#{entry}\t# VAGRANT ID: .*/ }
74
85
  tmp_file << line unless ids.any? { |id| line =~ /# VAGRANT ID: #{id}/ }
75
86
  end
76
87
 
@@ -84,12 +95,17 @@ module VagrantPlugins
84
95
  end
85
96
 
86
97
  def get_ip_address(machine)
87
- ip = nil
88
- if machine.config.hostmanager.ignore_private_ip != true
89
- machine.config.vm.networks.each do |network|
90
- key, options = network[0], network[1]
91
- ip = options[:ip] if key == :private_network
92
- next if ip
98
+ custom_ip_resolver = machine.config.hostmanager.ip_resolver
99
+ if custom_ip_resolver
100
+ custom_ip_resolver.call(machine)
101
+ else
102
+ ip = nil
103
+ if machine.config.hostmanager.ignore_private_ip != true
104
+ machine.config.vm.networks.each do |network|
105
+ key, options = network[0], network[1]
106
+ ip = options[:ip] if key == :private_network
107
+ next if ip
108
+ end
93
109
  end
94
110
  end
95
111
  ip || (machine.ssh_info ? machine.ssh_info[:host] : nil)
@@ -110,6 +126,45 @@ module VagrantPlugins
110
126
  @global_env.active_machines
111
127
  end
112
128
  end
129
+
130
+ ## Windows support for copying files, requesting elevated privileges if necessary
131
+ module WindowsSupport
132
+ require 'rbconfig'
133
+
134
+ def self.windows?
135
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
136
+ end
137
+
138
+ require 'win32ole' if windows?
139
+
140
+ def windows_copy_file(source, dest)
141
+ begin
142
+ # First, try Ruby copy
143
+ FileUtils.cp(source, dest)
144
+ rescue Errno::EACCES
145
+ # Access denied, try with elevated privileges
146
+ windows_copy_file_elevated(source, dest)
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def windows_copy_file_elevated(source, dest)
153
+ # copy command only supports backslashes as separators
154
+ source, dest = [source, dest].map { |s| s.to_s.gsub(/\//, '\\') }
155
+
156
+ # run 'cmd /C copy ...' with elevated privilege, minimized
157
+ copy_cmd = "copy \"#{source}\" \"#{dest}\""
158
+ WIN32OLE.new('Shell.Application').ShellExecute('cmd', "/C #{copy_cmd}", nil, 'runas', 7)
159
+
160
+ # Unfortunately, ShellExecute does not give us a status code,
161
+ # and it is non-blocking so we can't reliably compare the file contents
162
+ # to see if they were copied.
163
+ #
164
+ # If the user rejects the UAC prompt, vagrant will silently continue
165
+ # without updating the hostsfile.
166
+ end
167
+ end
113
168
  end
114
169
  end
115
170
  end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module HostManager
3
- VERSION = '1.2.3'
3
+ VERSION = '1.3.0'
4
4
  end
5
5
  end
@@ -7,3 +7,4 @@ en:
7
7
  config:
8
8
  not_a_bool: "A value for %{config_key} can only be true or false, not type '%{value}'"
9
9
  not_an_array_or_string: "A value for %{config_key} must be an Array or String, not type '%{is_class}'"
10
+ not_a_proc: "A value for %{config_key} must be a Proc, not type '%{is_class}'"
@@ -11,6 +11,7 @@ Gem::Specification.new do |gem|
11
11
  gem.email = ['shawn@dahlen.me']
12
12
  gem.description = %q{A Vagrant plugin that manages the /etc/hosts file within a multi-machine environment}
13
13
  gem.summary = gem.description
14
+ gem.license = 'MIT'
14
15
 
15
16
  gem.files = `git ls-files`.split($/)
16
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-hostmanager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-04 00:00:00.000000000 Z
12
+ date: 2013-12-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -73,7 +73,8 @@ files:
73
73
  - test/test.sh
74
74
  - vagrant-hostmanager.gemspec
75
75
  homepage:
76
- licenses: []
76
+ licenses:
77
+ - MIT
77
78
  post_install_message:
78
79
  rdoc_options: []
79
80
  require_paths: