landrush 0.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/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ tags
19
+
20
+ .vagrant
21
+ .vagrant_dns.json
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,10 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = "test/**/*_test.rb"
7
+ t.libs << 'test'
8
+ end
9
+
10
+ task :default => :test
@@ -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
@@ -0,0 +1,10 @@
1
+ # Monkey patch in a prefix for the RExec daemon log lines.
2
+ module RExec
3
+ module Daemon
4
+ module Controller
5
+ def self.puts(str)
6
+ Kernel.puts "[landrush] #{str}"
7
+ end
8
+ end
9
+ end
10
+ end
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