pleschev-vagrant-hostmaster 0.8.1

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.
@@ -0,0 +1,21 @@
1
+ .DS_Store
2
+ *.gem
3
+ *.rbc
4
+ *.swo
5
+ *.swp
6
+ .bundle
7
+ .config
8
+ .yardoc
9
+ Gemfile.lock
10
+ InstalledFiles
11
+ _yardoc
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
21
+ vendor/bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in vagrant-hostmaster.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 S. Brent Faulkner
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.
@@ -0,0 +1,108 @@
1
+ # vagrant-hostmaster
2
+
3
+ `vagrant-hostmaster` is a Vagrant plugin to manage /etc/hosts entries on both the host OS and guest VMs.
4
+
5
+ ## Installation
6
+
7
+ Install into vagrant's isolated RubyGems instance using:
8
+
9
+ $ vagrant gem install vagrant-hostmaster
10
+
11
+ ## Usage
12
+
13
+ vagrant-hostmaster will automatically add/update /etc/hosts entries when you run `vagrant up`
14
+ (or `vagrant provision`).
15
+
16
+ The host entries will automatically be removed when you run `vagrant destroy`.
17
+
18
+ ### Configuration
19
+
20
+ By default, the name specified in the `vm.host_name` configuration option will be associated
21
+ with the address of the first network interface.
22
+
23
+ For example:
24
+
25
+ Vagrant::Config.run do |config|
26
+ ...
27
+
28
+ config.vm.host_name = "www.example.com"
29
+
30
+ config.vm.network :hostonly, "33.33.33.60"
31
+ end
32
+
33
+ This would result in the following hosts entry:
34
+
35
+ 33.33.33.60 www.example.com # VAGRANT: ...
36
+
37
+ ### Using a different host name
38
+
39
+ To use a different host name, specify it in your Vagrantfile using the `hosts.name` configuration
40
+ option.
41
+
42
+ For example:
43
+
44
+ Vagrant::Config.run do |config|
45
+ ...
46
+
47
+ config.vm.host_name = "www.example.com"
48
+ config.hosts.name = "example.com"
49
+
50
+ config.vm.network :hostonly, "33.33.33.60"
51
+ end
52
+
53
+ This would result in the following hosts entry:
54
+
55
+ 33.33.33.60 example.com # VAGRANT: ...
56
+
57
+ ### Host aliases
58
+
59
+ In addition, the `hosts.aliases` configuration option can be used to provide aliases for your host names.
60
+
61
+ For example:
62
+
63
+ Vagrant::Config.run do |config|
64
+ ...
65
+
66
+ config.vm.host_name = "www.example.com"
67
+ config.hosts.aliases = %w(example.com)
68
+
69
+ config.vm.network :hostonly, "33.33.33.60"
70
+ end
71
+
72
+ This would result in the following hosts entry:
73
+
74
+ 33.33.33.60 www.example.com example.com # VAGRANT: ...
75
+
76
+ ## Command Line
77
+
78
+ In addition to automatically updating the hosts file, the `hosts` command supports manual
79
+ modification (or verification) of the hosts entries.
80
+
81
+ Usage: vagrant hosts <command> [<args>]
82
+
83
+ Available subcommands:
84
+ list
85
+ remove
86
+ update
87
+
88
+ For help on any individual command run `vagrant hosts COMMAND -h`
89
+
90
+ ### List Host Entries
91
+
92
+ vagrant hosts list [vm-name]
93
+
94
+ ### Remove Host Entries
95
+
96
+ vagrant hosts remove [vm-name]
97
+
98
+ ### Update Host Entries
99
+
100
+ vagrant hosts update [vm-name]
101
+
102
+ ## Contributing
103
+
104
+ 1. Fork it
105
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
106
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
107
+ 4. Push to the branch (`git push origin my-new-feature`)
108
+ 5. Create new Pull Request
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.pattern = 'test/**/*_test.rb'
8
+ end
9
+
10
+ desc "Run tests"
11
+ task :default => :test
@@ -0,0 +1,15 @@
1
+ require 'vagrant'
2
+ require 'vagrant/hostmaster/command/base'
3
+ require 'vagrant/hostmaster/command/root'
4
+ require 'vagrant/hostmaster/config'
5
+ require 'vagrant/hostmaster/vm'
6
+ require 'vagrant/hostmaster/middleware/remove'
7
+ require 'vagrant/hostmaster/middleware/update'
8
+
9
+ Vagrant.commands.register(:hosts) { Vagrant::Hostmaster::Command::Root }
10
+ Vagrant.config_keys.register(:hosts) { Vagrant::Hostmaster::Config }
11
+
12
+ Vagrant.actions[:destroy].insert_after(Vagrant::Action::VM::ProvisionerCleanup, Vagrant::Hostmaster::Middleware::Remove)
13
+
14
+ Vagrant.actions[:provision].insert_after(Vagrant::Action::VM::Provision, Vagrant::Hostmaster::Middleware::Update)
15
+ Vagrant.actions[:start].insert_after(Vagrant::Action::VM::Provision, Vagrant::Hostmaster::Middleware::Update)
@@ -0,0 +1,32 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ module Command
4
+ class Base < Vagrant::Command::Base
5
+ def execute
6
+ sub_command = self.class.name.split('::').last.downcase
7
+
8
+ parser = OptionParser.new do |opts|
9
+ opts.banner = "Usage: vagrant hosts #{sub_command} [vm-name]"
10
+ end
11
+
12
+ # Parse the options
13
+ argv = parse_options(parser)
14
+ return if !argv
15
+
16
+ with_target_vms(argv) do |vm|
17
+ if vm.state == :running
18
+ Hostmaster::VM.new(vm).send sub_command.to_sym
19
+ elsif vm.created?
20
+ vm.ui.info I18n.t("vagrant.commands.common.vm_not_running")
21
+ else
22
+ vm.ui.info I18n.t("vagrant.commands.common.vm_not_created")
23
+ end
24
+ end
25
+
26
+ # Success, exit status 0
27
+ 0
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,8 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ module Command
4
+ class List < Vagrant::Hostmaster::Command::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ module Command
4
+ class Remove < Vagrant::Hostmaster::Command::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,68 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ module Command
4
+ class Root < Vagrant::Command::Base
5
+ def initialize(argv, env)
6
+ super
7
+
8
+ @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
9
+
10
+ @subcommands = Vagrant::Registry.new
11
+ @subcommands.register(:list) do
12
+ require File.expand_path("../list", __FILE__)
13
+ List
14
+ end
15
+
16
+ @subcommands.register(:remove) do
17
+ require File.expand_path("../remove", __FILE__)
18
+ Remove
19
+ end
20
+
21
+ @subcommands.register(:update) do
22
+ require File.expand_path("../update", __FILE__)
23
+ Update
24
+ end
25
+ end
26
+
27
+ def execute
28
+ if @main_args.include?("-h") || @main_args.include?("--help")
29
+ # Print the help for all the hosts commands.
30
+ return help
31
+ end
32
+
33
+ # If we reached this far then we must have a subcommand. If not,
34
+ # then we also just print the help and exit.
35
+ command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
36
+ return help if !command_class || !@sub_command
37
+ @logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
38
+
39
+ # Initialize and execute the command class
40
+ command_class.new(@sub_args, @env).execute
41
+ end
42
+
43
+ # Prints the help out for this command
44
+ def help
45
+ opts = OptionParser.new do |opts|
46
+ opts.banner = "Usage: vagrant hosts <command> [<args>]"
47
+ opts.separator ""
48
+ opts.separator "Available subcommands:"
49
+
50
+ # Add the available subcommands as separators in order to print them
51
+ # out as well.
52
+ keys = []
53
+ @subcommands.each { |key, value| keys << key.to_s }
54
+
55
+ keys.sort.each do |key|
56
+ opts.separator " #{key}"
57
+ end
58
+
59
+ opts.separator ""
60
+ opts.separator "For help on any individual command run `vagrant hosts COMMAND -h`"
61
+ end
62
+
63
+ @env.ui.info(opts.help, :prefix => false)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,8 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ module Command
4
+ class Update < Vagrant::Hostmaster::Command::Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ class Config < Vagrant::Config::Base
4
+ attr_accessor :name
5
+ attr_accessor :aliases
6
+ attr_accessor :local
7
+ attr_accessor :quiet
8
+ attr_accessor :guests
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ module Middleware
4
+ class Remove
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ remove env[:vm] if env["vm"].created?
11
+ @app.call(env)
12
+ end
13
+
14
+ protected
15
+ def remove(vm)
16
+ Hostmaster::VM.new(vm).remove(:guests => false)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ module Middleware
4
+ class Update
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ @app.call(env)
11
+ update env[:vm] if env["vm"].state == :running
12
+ end
13
+
14
+ protected
15
+ def update(vm)
16
+ Hostmaster::VM.new(vm).update
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Vagrant
2
+ module Hostmaster
3
+ VERSION = "0.8.1"
4
+ end
5
+ end
@@ -0,0 +1,165 @@
1
+ require 'forwardable'
2
+
3
+ module Vagrant
4
+ module Hostmaster
5
+ class VM
6
+ extend Forwardable
7
+
8
+ def_delegators :@vm, :channel, :config, :env, :name, :uuid
9
+
10
+ class << self
11
+ def expand_path(relative_path, relative_to)
12
+ File.expand_path(relative_path, relative_to)
13
+ end
14
+
15
+ def hosts_path
16
+ Util::Platform.windows? ? expand_path('system32/drivers/etc/hosts', ENV['SYSTEMROOT']) : '/etc/hosts'
17
+ end
18
+ end
19
+
20
+ def initialize(vm)
21
+ @vm = vm
22
+ end
23
+
24
+ def add(options = {})
25
+ options.merge! config_to_h
26
+ if process_local?(options)
27
+ env.ui.info("Adding host entry for #{name} VM. Administrator privileges will be required...") unless options[:quiet]
28
+ sudo add_command
29
+ end
30
+
31
+ with_other_vms { |vm| channel.sudo vm.add_command(:uuid => uuid, :hosts_path => hosts_path) } if process_guests?(options)
32
+ end
33
+
34
+ def hosts_path
35
+ # TODO: if windows guests are supported, this will need to be smarter
36
+ "/etc/hosts"
37
+ end
38
+
39
+ def list(options = {})
40
+ options.merge! config_to_h
41
+ if process_local?(options)
42
+ output = `#{list_command}`.chomp
43
+ env.ui.info("[local] #{output}\n\n", :prefix => false) unless output.empty?
44
+ end
45
+
46
+ if process_guests?(options)
47
+ entries = ""
48
+ with_other_vms do |vm|
49
+ channel.execute(vm.list_command(:uuid => uuid, :hosts_path => hosts_path), :error_check => false) do |type, data|
50
+ entries << data if type == :stdout
51
+ end
52
+ end
53
+ entries = entries.split($/).collect { |entry| "[#{name}] #{entry}" }.join("\n")
54
+ env.ui.info("#{entries}\n\n", :prefix => false) unless entries.empty?
55
+ end
56
+ end
57
+
58
+ def remove(options = {})
59
+ options.merge! config_to_h
60
+ if process_local?(options)
61
+ env.ui.info("Removing host entry for #{name} VM. Administrator privileges will be required...") unless options[:quiet]
62
+ sudo remove_command
63
+ end
64
+ with_other_vms { |vm| channel.sudo vm.remove_command(:uuid => uuid, :hosts_path => hosts_path) } if process_guests?(options)
65
+ end
66
+
67
+ def update(options = {})
68
+ options.merge! config_to_h
69
+ if process_local?(options)
70
+ env.ui.info("Updating host entry for #{name} VM. Administrator privileges will be required...") unless options[:quiet]
71
+ sudo(remove_command) && sudo(add_command)
72
+ end
73
+ with_other_vms { |vm| channel.sudo(vm.remove_command(:uuid => uuid, :hosts_path => hosts_path)) && channel.sudo(vm.add_command(:uuid => uuid, :hosts_path => hosts_path)) } if process_guests?(options)
74
+ end
75
+
76
+ protected
77
+ def add_command(options = {})
78
+ uuid = options[:uuid] || self.uuid
79
+ hosts_path = options[:hosts_path] || self.class.hosts_path
80
+ %Q(sh -c 'echo "#{host_entry(uuid)}" >>#{hosts_path}')
81
+ end
82
+
83
+ def address
84
+ # network parameters consist of an address and a hash of options
85
+ @address ||= (network_parameters && network_parameters.first)
86
+ end
87
+
88
+ def host_aliases
89
+ @host_aliases ||= Array(config.hosts.aliases)
90
+ end
91
+
92
+ def host_entry(uuid = self.uuid)
93
+ %Q(#{address} #{host_names.join(' ')} #{signature(uuid)})
94
+ end
95
+
96
+ def host_name
97
+ @host_name ||= (config.hosts.name || config.vm.host_name)
98
+ end
99
+
100
+ def host_names
101
+ @host_names ||= (Array(host_name) + host_aliases)
102
+ end
103
+
104
+ def process_guests?(options = {})
105
+ {:guests => true}.merge(options)[:guests]
106
+ end
107
+
108
+ def process_local?(options = {})
109
+ {:local => true}.merge(options)[:local]
110
+ end
111
+
112
+ def list_command(options = {})
113
+ uuid = options[:uuid] || self.uuid
114
+ hosts_path = options[:hosts_path] || self.class.hosts_path
115
+ %Q(grep '#{signature(uuid)}$' #{hosts_path})
116
+ end
117
+
118
+ def network
119
+ # hostonly networks are the only ones we're interested in
120
+ @network ||= networks.find { |type,network_parameters| type == :hostonly }
121
+ end
122
+
123
+ def network_parameters
124
+ # network is a pair of a network type and the network parameters
125
+ @network_parameters ||= (network && network.last)
126
+ end
127
+
128
+ def networks
129
+ @networks ||= config.vm.networks
130
+ end
131
+
132
+ def remove_command(options = {})
133
+ uuid = options[:uuid] || self.uuid
134
+ hosts_path = options[:hosts_path] || self.class.hosts_path
135
+ %Q(sed -e '/#{signature(uuid)}$/ d' -ibak #{hosts_path})
136
+ end
137
+
138
+ def signature(uuid = self.uuid)
139
+ %Q(# VAGRANT: #{uuid} (#{name}))
140
+ end
141
+
142
+ def sudo(command)
143
+ if Util::Platform.windows?
144
+ `#{command}`
145
+ else
146
+ `sudo #{command}`
147
+ end
148
+ end
149
+
150
+ def with_other_vms
151
+ env.vms.each do |name,vm|
152
+ yield Hostmaster::VM.new(vm) if vm.config.vm.networks.any? { |type,network_parameters| type == :hostonly } && vm.name != self.name && vm.state == :running
153
+ end
154
+ end
155
+
156
+ def config_to_h
157
+ {
158
+ :local => config.hosts.local.nil? ? true : config.hosts.local,
159
+ :guests => config.hosts.guests.nil? ? true : config.hosts.guests,
160
+ :quiet => config.hosts.quiet.nil? ? false : config.hosts.quiet
161
+ }
162
+ end
163
+ end
164
+ end
165
+ end