landrush 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +10 -0
- data/examples/Vagrantfile +26 -0
- data/landrush.gemspec +35 -0
- data/lib/ext/rexec.rb +10 -0
- data/lib/landrush.rb +27 -0
- data/lib/landrush/action/redirect_dns.rb +35 -0
- data/lib/landrush/action/setup.rb +42 -0
- data/lib/landrush/action/teardown.rb +46 -0
- data/lib/landrush/command.rb +45 -0
- data/lib/landrush/config.rb +32 -0
- data/lib/landrush/dependent_vms.rb +40 -0
- data/lib/landrush/plugin.rb +32 -0
- data/lib/landrush/resolver_config.rb +53 -0
- data/lib/landrush/server.rb +69 -0
- data/lib/landrush/store.rb +49 -0
- data/lib/landrush/util.rb +25 -0
- data/lib/landrush/version.rb +3 -0
- data/test/landrush/action/setup_test.rb +73 -0
- data/test/landrush/action/teardown_test.rb +92 -0
- data/test/landrush/dependent_vms_test.rb +33 -0
- data/test/landrush/resolver_config_test.rb +20 -0
- data/test/landrush/server_test.rb +22 -0
- data/test/landrush/store_test.rb +55 -0
- data/test/support/clear_dependent_vms.rb +10 -0
- data/test/support/fake_resolver_config.rb +21 -0
- data/test/support/fake_ui.rb +4 -0
- data/test/support/fake_working_dir.rb +16 -0
- data/test/support/test_server_daemon.rb +40 -0
- data/test/test_helper.rb +54 -0
- metadata +156 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
# We depend on Vagrant for development, but we don't add it as a
|
7
|
+
# gem dependency because we expect to be installed within the
|
8
|
+
# Vagrant environment itself using `vagrant plugin`.
|
9
|
+
gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
|
10
|
+
|
11
|
+
gem "debugger"
|
12
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Paul Hinze
|
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,72 @@
|
|
1
|
+
# Landrush: DNS for Vagrant
|
2
|
+
|
3
|
+
Simple DNS that's visible on both the guest and the host.
|
4
|
+
|
5
|
+
> Because even a Vagrant needs a place to settle down once in a while.
|
6
|
+
|
7
|
+
Spins up a small DNS server and redirects DNS traffic from your VMs to use it,
|
8
|
+
automatically registers/deregisters IP addresseses of guests as they come up
|
9
|
+
and down.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Install under Vagrant (1.1 or later):
|
14
|
+
|
15
|
+
$ vagrant plugin install landrush
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
Enable the plugin in your `Vagrantfile`:
|
20
|
+
|
21
|
+
config.landrush.enable
|
22
|
+
|
23
|
+
Bring up a machine that has a private network IP address and a hostname (see the `Vagrantfile` for an example)
|
24
|
+
|
25
|
+
$ vagrant up
|
26
|
+
|
27
|
+
And you should be able to get your hostname from your host:
|
28
|
+
|
29
|
+
$ dig -p 10053 @localhost myhost.vagrant.dev
|
30
|
+
|
31
|
+
If you shut down your guest, the entries associated with it will be removed.
|
32
|
+
|
33
|
+
You can add static host entries to the DNS server in your `Vagrantfile` like so:
|
34
|
+
|
35
|
+
config.landrush.host 'myhost.example.com', '1.2.3.4'
|
36
|
+
|
37
|
+
Any DNS queries that do not match will be passed through to an upstream DNS server, so this will be able to serve as the one-stop shop for your guests' DNS needs.
|
38
|
+
|
39
|
+
### Visibility on the Guest
|
40
|
+
|
41
|
+
Linux guests using iptables should automatically have their DNS traffic redirected properly to our DNS server. File an issue if this does not work for you.
|
42
|
+
|
43
|
+
### Visibility on the Host
|
44
|
+
|
45
|
+
I'm currently developing this on OS X 10.8, and there's a nice trick you can pull to unobtrusibly add a secondary DNS server only for specific domains.
|
46
|
+
|
47
|
+
All you do is drop a file in `/etc/resolvers/$DOMAIN` with information on how to connect to the DNS server you'd like to use for that domain.
|
48
|
+
|
49
|
+
So what I do is name all of my vagrant servers with the pattern `$host.vagrant.dev` and then drop a file called `/etc/resolvers/vagrant.dev` with these contents:
|
50
|
+
|
51
|
+
```
|
52
|
+
# Use landrush server for this domain
|
53
|
+
nameserver 127.0.0.1
|
54
|
+
port 10053
|
55
|
+
```
|
56
|
+
|
57
|
+
This gives us automatic access to the landrush hosts without having to worry about it getting in the way of our normal DNS config.
|
58
|
+
|
59
|
+
## Work in Progress - Lots to do!
|
60
|
+
|
61
|
+
* The guest visibility strategy assumes iptables-based firewall.
|
62
|
+
* Lots of static values that need configurin' - config location, ports, etc.
|
63
|
+
* VirtualBox only right now, need to support VMWare
|
64
|
+
* Tests tests tests.
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
1. Fork it
|
69
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
70
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
71
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
72
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#
|
2
|
+
# This serves as a simple example, and it's what I'm using for testing locally.
|
3
|
+
#
|
4
|
+
# If you're doing development and want to run this locally you can simply
|
5
|
+
# `bundle install`, then prefix all your vagrant commands with `bundle exec`, like so:
|
6
|
+
#
|
7
|
+
# VAGRANT_CWD=examples bundle exec vagrant up
|
8
|
+
# VAGRANT_CWD=examples bundle exce vagrant halt
|
9
|
+
#
|
10
|
+
|
11
|
+
# This line is unnecessary when the plugin is installed normally; it's just
|
12
|
+
# here for the development / testing use case.
|
13
|
+
Vagrant.require_plugin "landrush"
|
14
|
+
|
15
|
+
Vagrant.configure("2") do |config|
|
16
|
+
config.vm.box = "precise64"
|
17
|
+
|
18
|
+
config.landrush.enable
|
19
|
+
|
20
|
+
config.vm.network :private_network, ip: '172.16.32.111'
|
21
|
+
|
22
|
+
config.vm.hostname = "myhost.vagrant.dev"
|
23
|
+
|
24
|
+
config.landrush.host 'static1.example.com', '1.2.3.4'
|
25
|
+
config.landrush.host 'static2.example.com', '2.3.4.5'
|
26
|
+
end
|
data/landrush.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'landrush/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "landrush"
|
8
|
+
spec.version = Landrush::VERSION
|
9
|
+
spec.authors = ["Paul Hinze"]
|
10
|
+
spec.email = ["paul.t.hinze@gmail.com"]
|
11
|
+
spec.description = <<-DESCRIP.gsub(/^ /, '')
|
12
|
+
Even a Vagrant needs a place to settle down once in a while.
|
13
|
+
|
14
|
+
This Vagrant plugin spins up a lightweight DNS server and makes it visible
|
15
|
+
to your guests and your host, so that you can easily access all your
|
16
|
+
machines without having to fiddle with IP addresses.
|
17
|
+
|
18
|
+
DNS records are automatically added and removed as machines are brought up
|
19
|
+
and down, and you can configure static entries to be returned from the
|
20
|
+
server as well. See the README for more documentation.
|
21
|
+
DESCRIP
|
22
|
+
spec.summary = %q{a vagrant plugin providing consistent DNS visible on host and guests}
|
23
|
+
spec.homepage = "https://github.com/phinze/landrush"
|
24
|
+
spec.license = "MIT"
|
25
|
+
|
26
|
+
spec.files = `git ls-files`.split($/)
|
27
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
28
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_dependency "rubydns"
|
32
|
+
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
34
|
+
spec.add_development_dependency "rake"
|
35
|
+
end
|
data/lib/ext/rexec.rb
ADDED
data/lib/landrush.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require 'vagrant'
|
3
|
+
rescue LoadError
|
4
|
+
raise 'The Vagrant landrush plugin must be run within Vagrant.'
|
5
|
+
end
|
6
|
+
|
7
|
+
module Landrush
|
8
|
+
def self.working_dir
|
9
|
+
@working_dir ||= Pathname(File.expand_path('~/.vagrant.d/data/landrush')).tap(&:mkpath)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.working_dir=(working_dir)
|
13
|
+
@working_dir = Pathname(working_dir).tap(&:mkpath)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'rubydns'
|
18
|
+
|
19
|
+
require 'landrush/dependent_vms'
|
20
|
+
require 'landrush/plugin'
|
21
|
+
require 'landrush/resolver_config'
|
22
|
+
require 'landrush/server'
|
23
|
+
require 'landrush/store'
|
24
|
+
require 'landrush/util'
|
25
|
+
require 'landrush/version'
|
26
|
+
|
27
|
+
require 'ext/rexec'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Landrush
|
2
|
+
module Action
|
3
|
+
class RedirectDns
|
4
|
+
def initialize(app, env)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
@machine = env[:machine]
|
10
|
+
|
11
|
+
@machine.ui.info "setting up machine's DNS to point to our server"
|
12
|
+
|
13
|
+
redirect_dns('10.0.2.3', 53, '10.0.2.2', 10053)
|
14
|
+
end
|
15
|
+
|
16
|
+
def redirect_dns(original_server, original_port, target_server, target_port)
|
17
|
+
%w[tcp udp].each do |protocol|
|
18
|
+
rule = "OUTPUT -t nat -d #{original_server} -p #{protocol} --dport #{original_port} -j DNAT --to-destination #{target_server}:#{target_port}"
|
19
|
+
command = %Q(iptables -C #{rule} 2> /dev/null || iptables -A #{rule})
|
20
|
+
_run_command(command)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def _run_command(command)
|
25
|
+
@machine.communicate.sudo(command) do |data, type|
|
26
|
+
if [:stderr, :stdout].include?(type)
|
27
|
+
color = (type == :stdout) ? :green : :red
|
28
|
+
@machine.env.ui.info(data.chomp, :color => color, :prefix => false)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Landrush
|
2
|
+
module Action
|
3
|
+
class Setup
|
4
|
+
def initialize(app, env)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
if env[:global_config].landrush.enabled?
|
10
|
+
DependentVMs.add(env[:machine])
|
11
|
+
start_server_if_necessary(env)
|
12
|
+
setup_machine_dns(env)
|
13
|
+
setup_static_dns(env)
|
14
|
+
env[:machine].config.vm.provision :landrush
|
15
|
+
end
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def start_server_if_necessary(env)
|
20
|
+
if Server.running?
|
21
|
+
env[:ui].info "[landrush] dns server already running"
|
22
|
+
else
|
23
|
+
env[:ui].info "[landrush] starting dns server"
|
24
|
+
Server.start
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_machine_dns(env)
|
29
|
+
hostname, ip_address = Util.host_and_ip(env[:machine])
|
30
|
+
env[:ui].info "[landrush] adding machine entry: #{hostname} => #{ip_address}"
|
31
|
+
Store.hosts.set(hostname, ip_address)
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_static_dns(env)
|
35
|
+
env[:global_config].landrush.hosts.each do |hostname, ip_address|
|
36
|
+
env[:ui].info "[landrush] adding static entry: #{hostname} => #{ip_address}"
|
37
|
+
Store.hosts.set hostname, ip_address
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Landrush
|
2
|
+
module Action
|
3
|
+
class Teardown
|
4
|
+
def initialize(app, env)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
if env[:global_config].landrush.enabled?
|
10
|
+
teardown_static_dns(env)
|
11
|
+
teardown_machine_dns(env)
|
12
|
+
|
13
|
+
DependentVMs.remove(env[:machine])
|
14
|
+
stop_server_if_necessary(env)
|
15
|
+
end
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop_server_if_necessary(env)
|
20
|
+
if Server.running?
|
21
|
+
if DependentVMs.none?
|
22
|
+
env[:ui].info "[landrush] no dependent vms left, stopping dns server"
|
23
|
+
Server.stop
|
24
|
+
else
|
25
|
+
env[:ui].info "[landrush] there are dependent vms left, leaving dns server"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
env[:ui].info "[landrush] dns server already stopped"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def teardown_machine_dns(env)
|
33
|
+
hostname = Util.hostname(env[:machine])
|
34
|
+
env[:ui].info "[landrush] removing machine entry: #{hostname}"
|
35
|
+
Store.hosts.delete(hostname)
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown_static_dns(env)
|
39
|
+
env[:global_config].landrush.hosts.each do |hostname, _|
|
40
|
+
env[:ui].info "[landrush] removing static entry: #{hostname}"
|
41
|
+
Store.hosts.delete hostname
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Landrush
|
2
|
+
class Command < Vagrant.plugin('2', :command)
|
3
|
+
DAEMON_COMMANDS = %w(start stop restart status)
|
4
|
+
|
5
|
+
def execute
|
6
|
+
ARGV.shift # flush landrush from ARGV, RExec wants to use it for daemon commands
|
7
|
+
|
8
|
+
command = ARGV.first
|
9
|
+
if DAEMON_COMMANDS.include?(command)
|
10
|
+
Server.daemonize
|
11
|
+
elsif command == 'dependentvms'
|
12
|
+
if DependentVMs.any?
|
13
|
+
@env.ui.info(DependentVMs.list.map { |dvm| " - #{dvm}" }.join("\n"))
|
14
|
+
else
|
15
|
+
@env.ui.info("No dependent VMs")
|
16
|
+
end
|
17
|
+
elsif command == 'install'
|
18
|
+
ResolverConfg.ensure_config_exists
|
19
|
+
else
|
20
|
+
boom("'#{command}' is not a command")
|
21
|
+
end
|
22
|
+
|
23
|
+
0 # happy exit code
|
24
|
+
end
|
25
|
+
|
26
|
+
def boom(msg)
|
27
|
+
raise Vagrant::Errors::CLIInvalidOptions, :help => usage(msg)
|
28
|
+
end
|
29
|
+
|
30
|
+
def usage(msg); <<-EOS.gsub(/^ /, '')
|
31
|
+
ERROR: #{msg}
|
32
|
+
|
33
|
+
vagrant landrush <command>
|
34
|
+
|
35
|
+
commands:
|
36
|
+
{start|stop|restart|status}
|
37
|
+
control the landrush server daemon
|
38
|
+
dependentvms
|
39
|
+
list vms currently dependent on the landrush server
|
40
|
+
install
|
41
|
+
install resolver config for host visbility (requires sudo)
|
42
|
+
EOS
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Landrush
|
2
|
+
class Config < Vagrant.plugin('2', :config)
|
3
|
+
attr_accessor :hosts
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@hosts = {}
|
7
|
+
@enabled = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def enable(enabled=true)
|
11
|
+
@enabled = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def disable
|
15
|
+
@enabled = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def enabled?
|
19
|
+
@enabled
|
20
|
+
end
|
21
|
+
|
22
|
+
def host(hostname, ip_address)
|
23
|
+
@hosts[hostname] = ip_address
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge(other)
|
27
|
+
super.tap do |result|
|
28
|
+
result.hosts = @hosts.merge(other.hosts)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|