vagrant-servant-hosts-provisioner 2.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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +35 -0
- data/Rakefile +22 -0
- data/lib/vagrant-servant-hosts-provisioner.rb +16 -0
- data/lib/vagrant-servant-hosts-provisioner/action.rb +25 -0
- data/lib/vagrant-servant-hosts-provisioner/action/add.rb +24 -0
- data/lib/vagrant-servant-hosts-provisioner/action/remove.rb +24 -0
- data/lib/vagrant-servant-hosts-provisioner/config.rb +108 -0
- data/lib/vagrant-servant-hosts-provisioner/hosts.rb +266 -0
- data/lib/vagrant-servant-hosts-provisioner/plugin.rb +49 -0
- data/lib/vagrant-servant-hosts-provisioner/provisioner.rb +18 -0
- data/lib/vagrant-servant-hosts-provisioner/version.rb +5 -0
- data/locales/en.yml +11 -0
- data/test/multi/Vagrantfile +43 -0
- data/test/multi/config/hosts.json +1 -0
- data/test/multi/test.sh +16 -0
- data/test/single/Vagrantfile +18 -0
- data/test/single/config/hosts.json +1 -0
- data/test/single/test.sh +10 -0
- data/vagrant-servant-hosts-provisioner.gemspec +24 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2e1dd527fc6f1f6c44e17da6dc424fc8dc0eb080
|
4
|
+
data.tar.gz: 7b118293f37531fde0afa35d1b2b763a1bc7ec63
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a16f3a45afc38fea12c583ca2fd7cf5df0a7adcb968fd1f9b9846767c5a4dcd983b5e9af8c9eafb81007ef05055629730aa5cb4fc801c387509e831e50d95997
|
7
|
+
data.tar.gz: 18411ff6df79098d6101e951e93538e71e70e7fe95f5b7c9da9d8c985939415c6e421e2e6c9c672c27c7a3115f55b53b6b339ee4052341e0a33541c409a38a60
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Mohamed Elkholy
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# VagrantPlugins::ServantHostsProvisioner
|
2
|
+
|
3
|
+
A Vagrant provisioner for managing the /etc/hosts file of the host and guest machines.
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Install into vagrant's isolated RubyGems instance using:
|
7
|
+
|
8
|
+
$ vagrant plugin install vagrant-servant-hosts-provisioner
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
Example configuration:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
config.vm.provision :hostsupdate, run: 'always' do |host|
|
16
|
+
host.hostname = 'demo-hostname'
|
17
|
+
host.manage_guest = true
|
18
|
+
host.manage_host = true
|
19
|
+
host.aliases = [
|
20
|
+
'hostname-aliase1',
|
21
|
+
'hostname-aliase2'
|
22
|
+
]
|
23
|
+
host.files = [
|
24
|
+
'config/hosts.json'
|
25
|
+
]
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'bundler/gem_helper'
|
3
|
+
|
4
|
+
# Immediately sync all stdout so that tools like buildbot can
|
5
|
+
# immediately load in the output.
|
6
|
+
$stdout.sync = true
|
7
|
+
$stderr.sync = true
|
8
|
+
|
9
|
+
# Change to the directory of this file.
|
10
|
+
Dir.chdir(File.expand_path("../", __FILE__))
|
11
|
+
|
12
|
+
# This installs the tasks that help with gem creation and
|
13
|
+
# publishing.
|
14
|
+
Bundler::GemHelper.install_tasks
|
15
|
+
|
16
|
+
task :test_single do
|
17
|
+
sh 'bash test/single/test.sh'
|
18
|
+
end
|
19
|
+
|
20
|
+
task :test_multi do
|
21
|
+
sh 'bash test/multi/test.sh'
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "vagrant-servant-hosts-provisioner/plugin"
|
3
|
+
require "vagrant-servant-hosts-provisioner/version"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module HostsProvisioner
|
7
|
+
# This returns the path to the source of this plugin.
|
8
|
+
def self.source_root
|
9
|
+
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
10
|
+
end
|
11
|
+
|
12
|
+
# This initializes the internationalization strings.
|
13
|
+
I18n.load_path << File.expand_path("locales/en.yml", self.source_root)
|
14
|
+
I18n.reload!
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'action/add'
|
2
|
+
require_relative 'action/remove'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module HostsProvisioner
|
6
|
+
module Action
|
7
|
+
include Vagrant::Action::Builtin
|
8
|
+
|
9
|
+
def self.add
|
10
|
+
Vagrant::Action::Builder.new.tap do |builder|
|
11
|
+
builder.use ConfigValidate
|
12
|
+
builder.use Add
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.remove
|
17
|
+
Vagrant::Action::Builder.new.tap do |builder|
|
18
|
+
builder.use ConfigValidate
|
19
|
+
builder.use Remove
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HostsProvisioner
|
3
|
+
module Action
|
4
|
+
class Add
|
5
|
+
|
6
|
+
def initialize(app, env)
|
7
|
+
@app = app
|
8
|
+
@machine = env[:machine]
|
9
|
+
@config = @machine.env.vagrantfile.config
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@config.vm.provisioners.each do |provisioner|
|
14
|
+
if provisioner.name == :hostsupdate
|
15
|
+
Hosts.new(@machine, provisioner.config).add
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HostsProvisioner
|
3
|
+
module Action
|
4
|
+
class Remove
|
5
|
+
|
6
|
+
def initialize(app, env)
|
7
|
+
@app = app
|
8
|
+
@machine = env[:machine]
|
9
|
+
@config = @machine.env.vagrantfile.config
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@config.vm.provisioners.each do |provisioner|
|
14
|
+
if provisioner.name == :hostsupdate
|
15
|
+
Hosts.new(@machine, provisioner.config).remove
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module HostsProvisioner
|
3
|
+
class Config < Vagrant.plugin("2", :config)
|
4
|
+
attr_accessor :id
|
5
|
+
attr_accessor :hostname
|
6
|
+
attr_accessor :manage_guest
|
7
|
+
attr_accessor :manage_host
|
8
|
+
attr_accessor :aliases
|
9
|
+
attr_accessor :files
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@id = UNSET_VALUE
|
13
|
+
@hostname = UNSET_VALUE
|
14
|
+
@manage_guest = UNSET_VALUE
|
15
|
+
@manage_host = UNSET_VALUE
|
16
|
+
@aliases = UNSET_VALUE
|
17
|
+
@files = UNSET_VALUE
|
18
|
+
end
|
19
|
+
|
20
|
+
def finalize!
|
21
|
+
@id = 0 if @id == UNSET_VALUE
|
22
|
+
@hostname = nil if @hostname == UNSET_VALUE
|
23
|
+
@manage_guest = false if @manage_guest == UNSET_VALUE
|
24
|
+
@manage_host = false if @manage_host == UNSET_VALUE
|
25
|
+
@aliases = [] if @aliases == UNSET_VALUE
|
26
|
+
@files = [] if @files == UNSET_VALUE
|
27
|
+
|
28
|
+
@aliases = [ @aliases ].flatten
|
29
|
+
@files = [ @files ].flatten
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate(machine)
|
33
|
+
errors = []
|
34
|
+
|
35
|
+
errors << validate_number('id', id)
|
36
|
+
errors << validate_bool_or_string('hostname', hostname)
|
37
|
+
errors << validate_bool('manage_guest', manage_guest)
|
38
|
+
errors << validate_bool('manage_host', manage_host)
|
39
|
+
errors << validate_array_or_string('files', files)
|
40
|
+
errors << validate_array_or_string('aliases', aliases)
|
41
|
+
errors.compact!
|
42
|
+
|
43
|
+
{ "HostsProvisioner configuration" => errors }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Checks if a option is Boolean
|
47
|
+
def validate_bool(key, value)
|
48
|
+
if ![TrueClass, FalseClass].include?(value.class) && value != UNSET_VALUE
|
49
|
+
I18n.t('vagrant_hostsprovisioner.error.invalid_bool', {
|
50
|
+
:config_key => key,
|
51
|
+
:invalid_class => value.class.to_s
|
52
|
+
})
|
53
|
+
else
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks if a option is a Number
|
59
|
+
def validate_number(key, value)
|
60
|
+
if !value.kind_of?(Fixnum) && !value.kind_of?(NilClass)
|
61
|
+
I18n.t('vagrant_hostsprovisioner.error.not_a_number', {
|
62
|
+
:config_key => key,
|
63
|
+
:invalid_class => value.class.to_s
|
64
|
+
})
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Checks if a option is an Array or String
|
71
|
+
def validate_array_or_string(key, value)
|
72
|
+
if !value.kind_of?(Array) && !value.kind_of?(String) && !value.kind_of?(NilClass)
|
73
|
+
I18n.t('vagrant_hostsprovisioner.error.not_an_array_or_string', {
|
74
|
+
:config_key => key,
|
75
|
+
:invalid_class => value.class.to_s
|
76
|
+
})
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Checks if a option is a String or Boolean
|
83
|
+
def validate_bool_or_string(key, value)
|
84
|
+
if ![TrueClass, FalseClass].include?(value.class) && !value.kind_of?(String) && !value.kind_of?(NilClass)
|
85
|
+
I18n.t('vagrant_hostsprovisioner.error.not_a_bool_or_string', {
|
86
|
+
:config_key => key,
|
87
|
+
:invalid_class => value.class.to_s
|
88
|
+
})
|
89
|
+
else
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Checks if a option is a String
|
95
|
+
def validate_string(key, value)
|
96
|
+
if !value.kind_of?(String) && !value.kind_of?(NilClass)
|
97
|
+
I18n.t('vagrant_hostsprovisioner.error.not_a_string', {
|
98
|
+
:config_key => key,
|
99
|
+
:invalid_class => value.class.to_s
|
100
|
+
})
|
101
|
+
else
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HostsProvisioner
|
5
|
+
class Hosts
|
6
|
+
|
7
|
+
def initialize(machine, config)
|
8
|
+
@machine = machine
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def add
|
13
|
+
# Update the guest machine if manage_guest is enabled
|
14
|
+
if @config.manage_guest
|
15
|
+
update_guest
|
16
|
+
end
|
17
|
+
|
18
|
+
# Update the host machine if manage_host is enabled
|
19
|
+
if @config.manage_host
|
20
|
+
update_host(false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove
|
25
|
+
if @config.manage_host
|
26
|
+
update_host(true)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_guest
|
31
|
+
return unless @machine.communicate.ready?
|
32
|
+
|
33
|
+
handle_comm(:stdout, I18n.t("vagrant_hostsprovisioner.provisioner.update_guest"))
|
34
|
+
|
35
|
+
if (@machine.communicate.test("uname -s | grep SunOS"))
|
36
|
+
realhostfile = '/etc/inet/hosts'
|
37
|
+
move_cmd = 'mv'
|
38
|
+
elsif (@machine.communicate.test("test -d $Env:SystemRoot"))
|
39
|
+
windir = ""
|
40
|
+
@machine.communicate.execute("echo %SYSTEMROOT%", {:shell => :cmd}) do |type, contents|
|
41
|
+
windir << contents.gsub("\r\n", '') if type == :stdout
|
42
|
+
end
|
43
|
+
realhostfile = "#{windir}\\System32\\drivers\\etc\\hosts"
|
44
|
+
move_cmd = 'mv -force'
|
45
|
+
else
|
46
|
+
realhostfile = '/etc/hosts'
|
47
|
+
move_cmd = 'mv -f'
|
48
|
+
end
|
49
|
+
|
50
|
+
# download and modify file with Vagrant-managed entries
|
51
|
+
file = @machine.env.tmp_path.join("hosts.#{@machine.name}")
|
52
|
+
@machine.communicate.download(realhostfile, file)
|
53
|
+
if update_file(file, false, false)
|
54
|
+
# upload modified file and remove temporary file
|
55
|
+
@machine.communicate.upload(file, '/tmp/hosts')
|
56
|
+
@machine.communicate.sudo("#{move_cmd} /tmp/hosts #{realhostfile}")
|
57
|
+
handle_comm(:stdout, I18n.t("vagrant_hostsprovisioner.provisioner.hosts_file_updated", {:file => realhostfile}))
|
58
|
+
end
|
59
|
+
|
60
|
+
begin
|
61
|
+
FileUtils.rm(file)
|
62
|
+
rescue Exception => e
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_host(clean)
|
67
|
+
# copy and modify hosts file on host with Vagrant-managed entries
|
68
|
+
file = @machine.env.tmp_path.join('hosts.local')
|
69
|
+
|
70
|
+
if clean == true
|
71
|
+
handle_comm(:stdout, I18n.t("vagrant_hostsprovisioner.provisioner.clean_host"))
|
72
|
+
else
|
73
|
+
handle_comm(:stdout, I18n.t("vagrant_hostsprovisioner.provisioner.update_host"))
|
74
|
+
end
|
75
|
+
|
76
|
+
if WindowsSupport.windows?
|
77
|
+
# lazily include windows Module
|
78
|
+
class << self
|
79
|
+
include WindowsSupport unless include? WindowsSupport
|
80
|
+
end
|
81
|
+
|
82
|
+
hosts_location = "#{ENV['WINDIR']}\\System32\\drivers\\etc\\hosts"
|
83
|
+
copy_proc = Proc.new { windows_copy_file(file, hosts_location) }
|
84
|
+
else
|
85
|
+
hosts_location = '/etc/hosts'
|
86
|
+
copy_proc = Proc.new { `sudo cp #{file} #{hosts_location}` }
|
87
|
+
end
|
88
|
+
|
89
|
+
FileUtils.cp(hosts_location, file)
|
90
|
+
if update_file(file, true, clean)
|
91
|
+
copy_proc.call
|
92
|
+
handle_comm(:stdout, I18n.t("vagrant_hostsprovisioner.provisioner.hosts_file_updated", {:file => hosts_location}))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def update_file(file, include_id, clean)
|
97
|
+
file = Pathname.new(file)
|
98
|
+
old_file_content = file.read
|
99
|
+
new_file_content = update_content(old_file_content, include_id, clean)
|
100
|
+
file.open('w') { |io| io.write(new_file_content) }
|
101
|
+
old_file_content != new_file_content
|
102
|
+
end
|
103
|
+
|
104
|
+
def update_content(file_content, include_id, clean)
|
105
|
+
id = include_id ? " id: #{read_or_create_id}" : ""
|
106
|
+
header = "## vagrant-servant-hosts-provisioner-start#{id}\n"
|
107
|
+
footer = "## vagrant-servant-hosts-provisioner-end\n"
|
108
|
+
body = clean ? "" : get_hosts_file_entry
|
109
|
+
get_new_content(header, footer, body, file_content)
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_hosts_file_entry
|
113
|
+
# Get the vm ip address
|
114
|
+
ip = get_ip_address
|
115
|
+
|
116
|
+
# Return empy string if we don't have an ip address
|
117
|
+
if ip === nil
|
118
|
+
handle_comm(:stderr, I18n.t("vagrant_hostsprovisioner.error.no_vm_ip"))
|
119
|
+
return ''
|
120
|
+
end
|
121
|
+
|
122
|
+
hosts = []
|
123
|
+
|
124
|
+
# Add the machine hostname
|
125
|
+
unless @config.hostname === false
|
126
|
+
hosts.push(@config.hostname || @machine.config.vm.hostname || @machine.name)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Add the defined aliases
|
130
|
+
hosts.concat(@config.aliases)
|
131
|
+
|
132
|
+
# Add the contents of the defined hosts files
|
133
|
+
if @config.files.count > 0
|
134
|
+
hosts.concat(get_files_data)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Remove duplicates
|
138
|
+
hosts = hosts.uniq
|
139
|
+
|
140
|
+
# Limit the number of hosts per line to 8
|
141
|
+
lines = []
|
142
|
+
hosts.each_slice(8) do |chnk|
|
143
|
+
lines.push("#{ip}\t" + chnk.join(' ').strip)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Join lines
|
147
|
+
hosts = lines.join("\n").strip
|
148
|
+
|
149
|
+
"#{hosts}\n"
|
150
|
+
end
|
151
|
+
|
152
|
+
def get_files_data
|
153
|
+
require 'json'
|
154
|
+
data = []
|
155
|
+
@config.files.each do |file|
|
156
|
+
if file.kind_of?(String) && file != ""
|
157
|
+
file_path = File.join(@machine.env.root_path, file)
|
158
|
+
if File.exist?(file_path)
|
159
|
+
file_data = JSON.parse(File.read(file_path))
|
160
|
+
data.concat([ file_data ].flatten)
|
161
|
+
else
|
162
|
+
handle_comm(:stderr, I18n.t("vagrant_hostsprovisioner.error.file_not_found", {:file => file.to_s}))
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
data.collect(&:strip)
|
167
|
+
end
|
168
|
+
|
169
|
+
def get_ip_address
|
170
|
+
ip = nil
|
171
|
+
@machine.config.vm.networks.each do |network|
|
172
|
+
key, options = network[0], network[1]
|
173
|
+
ip = options[:ip] if key == :private_network
|
174
|
+
break if ip
|
175
|
+
end
|
176
|
+
# If no ip is defined in private_network then use the ssh host ip instead
|
177
|
+
ip || (@machine.ssh_info ? @machine.ssh_info[:host] : nil)
|
178
|
+
end
|
179
|
+
|
180
|
+
def get_new_content(header, footer, body, old_content)
|
181
|
+
if body.empty?
|
182
|
+
block = "\n"
|
183
|
+
else
|
184
|
+
block = "\n\n" + header + body + footer + "\n"
|
185
|
+
end
|
186
|
+
# Pattern for finding existing block
|
187
|
+
header_pattern = Regexp.quote(header)
|
188
|
+
footer_pattern = Regexp.quote(footer)
|
189
|
+
pattern = Regexp.new("\n*#{header_pattern}.*?#{footer_pattern}\n*", Regexp::MULTILINE)
|
190
|
+
# Replace existing block or append
|
191
|
+
old_content.match(pattern) ? old_content.sub(pattern, block) : old_content.rstrip + block
|
192
|
+
end
|
193
|
+
|
194
|
+
def read_or_create_id
|
195
|
+
file = Pathname.new("#{@machine.env.local_data_path}/hostsprovisioner/#{@machine.name}")
|
196
|
+
if (file.file?)
|
197
|
+
id = file.read.strip
|
198
|
+
else
|
199
|
+
id = SecureRandom.uuid
|
200
|
+
file.dirname.mkpath
|
201
|
+
file.open('w') { |f| f.write(id) }
|
202
|
+
end
|
203
|
+
id + "-" + @config.id.to_s
|
204
|
+
end
|
205
|
+
|
206
|
+
## Windows support for copying files, requesting elevated privileges if necessary
|
207
|
+
module WindowsSupport
|
208
|
+
require 'rbconfig'
|
209
|
+
|
210
|
+
def self.windows?
|
211
|
+
RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
212
|
+
end
|
213
|
+
|
214
|
+
require 'win32ole' if windows?
|
215
|
+
|
216
|
+
def windows_copy_file(source, dest)
|
217
|
+
begin
|
218
|
+
# First, try Ruby copy
|
219
|
+
FileUtils.cp(source, dest)
|
220
|
+
rescue Errno::EACCES
|
221
|
+
# Access denied, try with elevated privileges
|
222
|
+
windows_copy_file_elevated(source, dest)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
def windows_copy_file_elevated(source, dest)
|
229
|
+
# copy command only supports backslashes as separators
|
230
|
+
source, dest = [source, dest].map { |s| s.to_s.gsub(/\//, '\\') }
|
231
|
+
|
232
|
+
# run 'cmd /C copy ...' with elevated privilege, minimized
|
233
|
+
copy_cmd = "copy \"#{source}\" \"#{dest}\""
|
234
|
+
WIN32OLE.new('Shell.Application').ShellExecute('cmd', "/C #{copy_cmd}", nil, 'runas', 7)
|
235
|
+
|
236
|
+
# Unfortunately, ShellExecute does not give us a status code,
|
237
|
+
# and it is non-blocking so we can't reliably compare the file contents
|
238
|
+
# to see if they were copied.
|
239
|
+
#
|
240
|
+
# If the user rejects the UAC prompt, vagrant will silently continue
|
241
|
+
# without updating the hostsfile.
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# This handles outputting the communication data back to the UI
|
246
|
+
def handle_comm(type, data)
|
247
|
+
if [:stderr, :stdout].include?(type)
|
248
|
+
# Output the data with the proper color based on the stream.
|
249
|
+
color = type == :stdout ? :green : :red
|
250
|
+
|
251
|
+
# Clear out the newline since we add one
|
252
|
+
data = data.chomp
|
253
|
+
return if data.empty?
|
254
|
+
|
255
|
+
options = {}
|
256
|
+
options[:color] = color
|
257
|
+
|
258
|
+
prefix = "[hosts-updater]"
|
259
|
+
|
260
|
+
@machine.ui.info(prefix + " " + data.chomp, options)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
# This is a sanity check to make sure no one is attempting to install
|
4
|
+
# this into an early Vagrant version.
|
5
|
+
if Vagrant::VERSION < "1.5.0"
|
6
|
+
raise "Vagrant HostsProvisioner plugin is only compatible with Vagrant 1.5+"
|
7
|
+
end
|
8
|
+
|
9
|
+
module VagrantPlugins
|
10
|
+
module HostsProvisioner
|
11
|
+
class Plugin < Vagrant.plugin('2')
|
12
|
+
name 'HostsProvisioner'
|
13
|
+
description <<-DESC
|
14
|
+
A Vagrant provisioner for managing the /etc/hosts file of the host and guest machines.
|
15
|
+
DESC
|
16
|
+
|
17
|
+
config(:hostsupdate, :provisioner) do
|
18
|
+
require_relative 'config'
|
19
|
+
Config
|
20
|
+
end
|
21
|
+
|
22
|
+
provisioner(:hostsupdate) do
|
23
|
+
require_relative 'provisioner'
|
24
|
+
Provisioner
|
25
|
+
end
|
26
|
+
|
27
|
+
action_hook(:hostsupdate, :machine_action_resume) do |hook|
|
28
|
+
require_relative 'action'
|
29
|
+
hook.append(Action.add)
|
30
|
+
end
|
31
|
+
|
32
|
+
action_hook(:hostsupdate, :machine_action_suspend) do |hook|
|
33
|
+
require_relative 'action'
|
34
|
+
hook.prepend(Action.remove)
|
35
|
+
end
|
36
|
+
|
37
|
+
action_hook(:hostsupdate, :machine_action_halt) do |hook|
|
38
|
+
require_relative 'action'
|
39
|
+
hook.prepend(Action.remove)
|
40
|
+
end
|
41
|
+
|
42
|
+
action_hook(:hostsupdate, :machine_action_destroy) do |hook|
|
43
|
+
require_relative 'action'
|
44
|
+
hook.prepend(Action.remove)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path("../hosts", __FILE__)
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module HostsProvisioner
|
5
|
+
class Provisioner < Vagrant.plugin('2', :provisioner)
|
6
|
+
|
7
|
+
def initialize(machine, config)
|
8
|
+
@hosts = Hosts.new(machine, config)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def provision
|
13
|
+
@hosts.add
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
en:
|
2
|
+
vagrant_hostsprovisioner:
|
3
|
+
provisioner:
|
4
|
+
update_guest: "Updating hosts file on the guest machine..."
|
5
|
+
update_host: "Updating hosts file on the host machine (password may be required)..."
|
6
|
+
hosts_file_updated: "'%{file}' file updated successfully"
|
7
|
+
error:
|
8
|
+
invalid_bool: "Invalid data type '%{invalid_class}' provided for %{config_key}, expected 'boolean' value"
|
9
|
+
not_an_array_or_string: "Invalid data type '%{invalid_class}' provided for %{config_key}, expected an Array or String"
|
10
|
+
no_vm_ip: "Unable to find the ip address of the guest machine"
|
11
|
+
file_not_found: "Unable to find the file '%{file}'"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure('2') do |config|
|
5
|
+
|
6
|
+
config.vm.box = 'ubuntu/trusty64'
|
7
|
+
|
8
|
+
config.vm.hostname = "multi-testbox"
|
9
|
+
|
10
|
+
config.vm.define :mark do |node|
|
11
|
+
node.vm.hostname = 'mark'
|
12
|
+
node.vm.network :private_network, :ip => '10.0.5.2'
|
13
|
+
node.vm.provision :hostsupdate do |provision|
|
14
|
+
provision.hostname = 'mark-hostname.dev'
|
15
|
+
provision.manage_guest = true
|
16
|
+
provision.manage_host = true
|
17
|
+
provision.aliases = ['mark-aliase1', 'mark-aliase2']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
config.vm.define :john do |node|
|
22
|
+
node.vm.hostname = 'john'
|
23
|
+
node.vm.network :private_network, :ip => '10.0.5.3'
|
24
|
+
node.vm.provision :hostsupdate do |provision|
|
25
|
+
provision.hostname = 'john-hostname.dev'
|
26
|
+
provision.manage_guest = true
|
27
|
+
provision.manage_host = true
|
28
|
+
provision.aliases = ['john-aliase1', 'john-aliase2']
|
29
|
+
provision.files = ['config/hosts.json']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
config.vm.define :brad do |node|
|
34
|
+
node.vm.hostname = 'brad'
|
35
|
+
node.vm.network :private_network, :ip => '10.0.5.4'
|
36
|
+
node.vm.provision :hostsupdate do |provision|
|
37
|
+
provision.manage_guest = true
|
38
|
+
provision.manage_host = true
|
39
|
+
provision.files = ['config/notfile.json']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
["local.dev","www.local.dev","localhost.dev","www.localhost.dev"]
|
data/test/multi/test.sh
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
cd test
|
2
|
+
|
3
|
+
vagrant up
|
4
|
+
|
5
|
+
echo "[mark] /etc/hosts file:"
|
6
|
+
vagrant ssh mark -c 'cat /etc/hosts'
|
7
|
+
|
8
|
+
echo "[john] /etc/hosts file:"
|
9
|
+
vagrant ssh john -c 'cat /etc/hosts'
|
10
|
+
|
11
|
+
echo "[brad] /etc/hosts file:"
|
12
|
+
vagrant ssh brad -c 'cat /etc/hosts'
|
13
|
+
|
14
|
+
vagrant destroy -f
|
15
|
+
|
16
|
+
cd ..
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure('2') do |config|
|
5
|
+
|
6
|
+
config.vm.box = 'ubuntu/trusty64'
|
7
|
+
|
8
|
+
config.vm.hostname = "single-testbox"
|
9
|
+
|
10
|
+
config.vm.provision :hostsupdate do |host|
|
11
|
+
host.hostname = 'single-testbox-hostname'
|
12
|
+
host.manage_guest = true
|
13
|
+
host.manage_host = true
|
14
|
+
host.aliases = ['testbox-aliase1', 'testbox-aliase2']
|
15
|
+
host.files = ['config/hosts.json']
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
["local.dev","www.local.dev","localhost.dev","www.localhost.dev"]
|
data/test/single/test.sh
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'vagrant-servant-hosts-provisioner/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "vagrant-servant-hosts-provisioner"
|
9
|
+
spec.version = VagrantPlugins::HostsProvisioner::VERSION
|
10
|
+
spec.authors = ["Jonas Friedmann"]
|
11
|
+
spec.email = ["j@frd.mn"]
|
12
|
+
spec.description = %q{A Vagrant provisioner for managing the /etc/hosts file of the host and guest machines.}
|
13
|
+
spec.summary = spec.description
|
14
|
+
spec.homepage = "https://github.com/frdmn/vagrant-servant-hosts-provisioner"
|
15
|
+
spec.license = "MIT"
|
16
|
+
spec.rubyforge_project = "vagrant-servant-hosts-provisioner"
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-servant-hosts-provisioner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '2.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonas Friedmann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: A Vagrant provisioner for managing the /etc/hosts file of the host and
|
42
|
+
guest machines.
|
43
|
+
email:
|
44
|
+
- j@frd.mn
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- lib/vagrant-servant-hosts-provisioner.rb
|
55
|
+
- lib/vagrant-servant-hosts-provisioner/action.rb
|
56
|
+
- lib/vagrant-servant-hosts-provisioner/action/add.rb
|
57
|
+
- lib/vagrant-servant-hosts-provisioner/action/remove.rb
|
58
|
+
- lib/vagrant-servant-hosts-provisioner/config.rb
|
59
|
+
- lib/vagrant-servant-hosts-provisioner/hosts.rb
|
60
|
+
- lib/vagrant-servant-hosts-provisioner/plugin.rb
|
61
|
+
- lib/vagrant-servant-hosts-provisioner/provisioner.rb
|
62
|
+
- lib/vagrant-servant-hosts-provisioner/version.rb
|
63
|
+
- locales/en.yml
|
64
|
+
- test/multi/Vagrantfile
|
65
|
+
- test/multi/config/hosts.json
|
66
|
+
- test/multi/test.sh
|
67
|
+
- test/single/Vagrantfile
|
68
|
+
- test/single/config/hosts.json
|
69
|
+
- test/single/test.sh
|
70
|
+
- vagrant-servant-hosts-provisioner.gemspec
|
71
|
+
homepage: https://github.com/frdmn/vagrant-servant-hosts-provisioner
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project: vagrant-servant-hosts-provisioner
|
91
|
+
rubygems_version: 2.6.6
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: A Vagrant provisioner for managing the /etc/hosts file of the host and guest
|
95
|
+
machines.
|
96
|
+
test_files:
|
97
|
+
- test/multi/Vagrantfile
|
98
|
+
- test/multi/config/hosts.json
|
99
|
+
- test/multi/test.sh
|
100
|
+
- test/single/Vagrantfile
|
101
|
+
- test/single/config/hosts.json
|
102
|
+
- test/single/test.sh
|