landrush 0.19.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.config/cucumber.yml +7 -0
  3. data/.gitignore +6 -4
  4. data/.rubocop.yml +5 -0
  5. data/.rubocop_todo.yml +32 -259
  6. data/CHANGELOG.md +8 -1
  7. data/CONTRIBUTING.md +11 -10
  8. data/Gemfile +7 -4
  9. data/Gemfile.lock +178 -0
  10. data/README.md +148 -35
  11. data/Rakefile +18 -0
  12. data/doc/img/advanced-tcp-properties.png +0 -0
  13. data/doc/img/network-connections.png +0 -0
  14. data/features/dns_resolution.feature +26 -0
  15. data/features/step_definitions/dns.rb +19 -0
  16. data/features/support/env.rb +16 -0
  17. data/landrush.gemspec +1 -2
  18. data/lib/landrush.rb +0 -12
  19. data/lib/landrush/action/common.rb +5 -5
  20. data/lib/landrush/action/redirect_dns.rb +1 -1
  21. data/lib/landrush/action/setup.rb +9 -14
  22. data/lib/landrush/action/teardown.rb +5 -1
  23. data/lib/landrush/cap/debian/install_iptables.rb +2 -2
  24. data/lib/landrush/cap/linux/add_iptables_rule.rb +0 -1
  25. data/lib/landrush/cap/linux/redirect_dns.rb +0 -1
  26. data/lib/landrush/cap/redhat/install_iptables.rb +2 -2
  27. data/lib/landrush/command.rb +8 -10
  28. data/lib/landrush/config.rb +1 -1
  29. data/lib/landrush/dependent_vms.rb +2 -2
  30. data/lib/landrush/os.rb +19 -0
  31. data/lib/landrush/plugin.rb +4 -4
  32. data/lib/landrush/resolver_config.rb +1 -5
  33. data/lib/landrush/server.rb +187 -25
  34. data/lib/landrush/store.rb +12 -4
  35. data/lib/landrush/version.rb +1 -1
  36. data/test/landrush/action/setup_test.rb +14 -9
  37. data/test/landrush/action/teardown_test.rb +8 -9
  38. data/test/landrush/cap/linux/configured_dns_servers_test.rb +2 -2
  39. data/test/landrush/cap/linux/read_host_visible_ip_address_test.rb +5 -7
  40. data/test/landrush/cap/linux/redirect_dns_test.rb +1 -1
  41. data/test/landrush/resolver_config_test.rb +0 -2
  42. data/test/landrush/server_test.rb +18 -12
  43. data/test/landrush/store_test.rb +7 -6
  44. data/test/support/clear_dependent_vms.rb +4 -2
  45. data/test/support/create_fake_working_dir.rb +19 -0
  46. data/test/support/delete_fake_working_dir.rb +12 -0
  47. data/test/support/fake_resolver_config.rb +8 -3
  48. data/test/support/test_server_daemon.rb +20 -15
  49. data/test/test_helper.rb +31 -22
  50. metadata +26 -28
  51. data/lib/ext/rexec.rb +0 -10
  52. data/test/support/fake_working_dir.rb +0 -16
data/Rakefile CHANGED
@@ -1,12 +1,30 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'rake'
2
3
  require 'rake/testtask'
4
+ require 'rake/clean'
3
5
  require 'rubocop/rake_task'
6
+ require 'cucumber/rake/task'
7
+ require 'fileutils'
4
8
 
9
+ CLOBBER.include('pkg')
10
+ CLEAN.include('build')
11
+
12
+ task :init do
13
+ FileUtils.mkdir_p 'build'
14
+ end
15
+ task :features => :init
16
+
17
+ # Default test task
18
+ desc 'Run all unit tests'
5
19
  Rake::TestTask.new do |t|
6
20
  t.pattern = 'test/**/*_test.rb'
7
21
  t.libs << 'test'
8
22
  end
9
23
 
24
+ # Cucumber acceptance test task
25
+ Cucumber::Rake::Task.new(:features)
26
+ task :features => :init
27
+
10
28
  task default: [
11
29
  :rubocop,
12
30
  :test
Binary file
Binary file
@@ -0,0 +1,26 @@
1
+ Feature: dns_resolution
2
+ Landrush should make a virtual machine's IP address DNS-resolvable.
3
+
4
+ Scenario Outline: booting a box
5
+ Given a file named "Vagrantfile" with:
6
+ """
7
+ Vagrant.configure('2') do |config|
8
+ config.vm.box = '<box>'
9
+ config.vm.hostname = 'my-host.landrush-acceptance-test'
10
+ config.vm.network :private_network, ip: '10.10.10.123'
11
+
12
+ config.vm.synced_folder '.', '/vagrant', disabled: true
13
+
14
+ config.landrush.enabled = true
15
+ config.landrush.tld = 'landrush-acceptance-test'
16
+ end
17
+ """
18
+ When I successfully run `bundle exec vagrant up --provider <provider>`
19
+ Then the hostname "my-host.landrush-acceptance-test" should resolve to "10.10.10.123" on the internal DNS server
20
+ And the hostname "my-host.landrush-acceptance-test" should resolve to "10.10.10.123" on the host
21
+ And the hostname "my-host.landrush-acceptance-test" should resolve to "10.10.10.123" on the guest
22
+
23
+ Examples:
24
+ | box | provider |
25
+ | debian/jessie64 | virtualbox |
26
+ #| ubuntu/wily64 | virtualbox |
@@ -0,0 +1,19 @@
1
+ require 'landrush/server'
2
+
3
+ Then(/^the hostname "([^"]+)" should resolve to "([^"]+)" on the internal DNS server$/) do |host, ip|
4
+ port = Landrush::Server.port
5
+ resolver = Resolv::DNS.new(:nameserver_port => [['localhost', port]], :search => ['local'], :ndots => 1)
6
+ ip_resolved = resolver.getaddress(host).to_s
7
+ expect(ip_resolved).to eq(ip)
8
+ end
9
+
10
+ Then(/^the hostname "([^"]+)" should resolve to "([^"]+)" on the host$/) do |host, ip|
11
+ addrinfo = Addrinfo.getaddrinfo(host, nil, Socket::AF_INET)
12
+ ip_resolved = addrinfo.first.ip_address
13
+ expect(ip_resolved).to eq(ip)
14
+ end
15
+
16
+ Then(/^the hostname "([^"]+)" should resolve to "([^"]+)" on the guest/) do |host, ip|
17
+ run("vagrant ssh -c \"dig +short '#{host}' A\"")
18
+ expect(last_command_started).to have_output(/^#{ip}$/)
19
+ end
@@ -0,0 +1,16 @@
1
+ require 'aruba/cucumber'
2
+ require 'komenda'
3
+
4
+ Aruba.configure do |config|
5
+ config.exit_timeout = 300
6
+ config.activate_announcer_on_command_failure = [:stdout, :stderr]
7
+ config.working_directory = 'build/aruba'
8
+ end
9
+
10
+ After do |_scenario|
11
+ Komenda.run('bundle exec vagrant landrush stop', fail_on_fail: true)
12
+
13
+ if File.exist?(File.join(aruba.config.working_directory, 'Vagrantfile'))
14
+ Komenda.run('bundle exec vagrant destroy -f', cwd: aruba.config.working_directory, fail_on_fail: true)
15
+ end
16
+ end
data/landrush.gemspec CHANGED
@@ -28,6 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
29
29
  spec.require_paths = ['lib']
30
30
 
31
- spec.add_dependency 'rubydns', '1.0.2'
32
- spec.add_dependency 'rexec'
31
+ spec.add_dependency 'rubydns', '0.8.5'
33
32
  end
data/lib/landrush.rb CHANGED
@@ -4,16 +4,6 @@ rescue LoadError
4
4
  raise 'The Vagrant landrush plugin must be run within Vagrant.'
5
5
  end
6
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
7
  require 'rubydns'
18
8
  require 'ipaddr'
19
9
 
@@ -23,5 +13,3 @@ require 'landrush/resolver_config'
23
13
  require 'landrush/server'
24
14
  require 'landrush/store'
25
15
  require 'landrush/version'
26
-
27
- require 'ext/rexec'
@@ -6,8 +6,8 @@ module Landrush
6
6
  'VagrantPlugins::ProviderLibvirt::Provider' => :libvirt,
7
7
  'HashiCorp::VagrantVMwarefusion::Provider' => :vmware_fusion,
8
8
  'VagrantPlugins::Parallels::Provider' => :parallels,
9
- 'Landrush::FakeProvider' => :fake_provider,
10
- }
9
+ 'Landrush::FakeProvider' => :fake_provider
10
+ }.freeze
11
11
 
12
12
  def self.included(base)
13
13
  base.send :attr_reader, :app, :env
@@ -42,11 +42,11 @@ module Landrush
42
42
  end
43
43
 
44
44
  def provider
45
- provider_name = SUPPORTED_PROVIDERS.fetch(machine.provider.class.name) { |key|
45
+ provider_name = SUPPORTED_PROVIDERS.fetch(machine.provider.class.name) do |key|
46
46
  raise "The landrush plugin does not support the #{key} provider yet!"
47
- }
47
+ end
48
48
 
49
- if provider_name == :parallels and Gem::Version.new(VagrantPlugins::Parallels::VERSION) < Gem::Version.new("1.0.3")
49
+ if provider_name == :parallels && Gem::Version.new(VagrantPlugins::Parallels::VERSION) < Gem::Version.new("1.0.3")
50
50
  raise "The landrush plugin supports the Parallels provider v1.0.3 and later. Please, update your 'vagrant-parallels' plugin."
51
51
  end
52
52
 
@@ -9,7 +9,7 @@ module Landrush
9
9
  # This is after the middleware stack returns, which, since we're right
10
10
  # before the Network action, should mean that all interfaces are good
11
11
  # to go.
12
- redirect_dns if enabled? and guest_redirect_dns?
12
+ redirect_dns if enabled? && guest_redirect_dns?
13
13
  end
14
14
 
15
15
  def redirect_dns
@@ -4,6 +4,10 @@ module Landrush
4
4
  include Common
5
5
 
6
6
  def call(env)
7
+ # Make sure we use the right data directory for Landrush
8
+ # Seems Vagrant only makes home_path available in this case, compared to custom commands where there is also data_dir
9
+ Server.working_dir = File.join(env[:home_path], 'data', 'landrush')
10
+
7
11
  handle_action_stack(env) do
8
12
  pre_boot_setup if enabled?
9
13
  end
@@ -44,23 +48,14 @@ module Landrush
44
48
 
45
49
  def start_server
46
50
  return if Server.running?
47
- # We need to avoid forking with libvirt provider since the forked process
48
- # would try to reuse the libvirt connection and fail.
49
- if libvirt?
50
- require 'open3'
51
- Kernel.puts '[landrush] Starting landrush in background...'
52
- _stdout, stderr, status = Open3.capture3('vagrant landrush start')
53
- Kernel.puts stderr unless status
54
- else
55
- info 'starting dns server'
56
- Server.start
57
- end
51
+ info 'starting dns server'
52
+ Server.start
58
53
  end
59
54
 
60
55
  def setup_static_dns
61
56
  config.hosts.each do |hostname, dns_value|
62
57
  dns_value ||= machine.guest.capability(:read_host_visible_ip_address)
63
- if !Store.hosts.has?(hostname, dns_value)
58
+ unless Store.hosts.has?(hostname, dns_value)
64
59
  info "adding static entry: #{hostname} => #{dns_value}"
65
60
  Store.hosts.set hostname, dns_value
66
61
  Store.hosts.set(IPAddr.new(dns_value).reverse, hostname)
@@ -72,12 +67,12 @@ module Landrush
72
67
  ip_address = machine.config.landrush.host_ip_address ||
73
68
  machine.guest.capability(:read_host_visible_ip_address)
74
69
 
75
- if not machine_hostname.match(config.tld)
70
+ unless machine_hostname.match(config.tld)
76
71
  log :error, "hostname #{machine_hostname} does not match the configured TLD: #{config.tld}"
77
72
  log :error, "You will not be able to access #{machine_hostname} from the host"
78
73
  end
79
74
 
80
- if !Store.hosts.has?(machine_hostname, ip_address)
75
+ unless Store.hosts.has?(machine_hostname, ip_address)
81
76
  info "adding machine entry: #{machine_hostname} => #{ip_address}"
82
77
  Store.hosts.set(machine_hostname, ip_address)
83
78
  Store.hosts.set(IPAddr.new(ip_address).reverse, machine_hostname)
@@ -4,6 +4,10 @@ module Landrush
4
4
  include Common
5
5
 
6
6
  def call(env)
7
+ # Make sure we use the right data directory for Landrush
8
+ # Seems Vagrant only makes home_path available in this case, compared to custom commands where there is also data_dir
9
+ Server.working_dir = File.join(env[:home_path], 'data', 'landrush')
10
+
7
11
  handle_action_stack(env) do
8
12
  teardown if enabled?
9
13
  end
@@ -27,7 +31,7 @@ module Landrush
27
31
  end
28
32
 
29
33
  def teardown_static_dns
30
- config.hosts.each do |static_hostname, dns_value|
34
+ config.hosts.each do |static_hostname|
31
35
  if Store.hosts.has? static_hostname
32
36
  info "removing static entry: #{static_hostname}"
33
37
  Store.hosts.delete static_hostname
@@ -3,10 +3,10 @@ module Landrush
3
3
  module Debian
4
4
  module InstallIptables
5
5
  def self.install_iptables(machine)
6
- machine.communicate.tap { |c|
6
+ machine.communicate.tap do |c|
7
7
  c.sudo('apt-get update')
8
8
  c.sudo('apt-get install -y iptables')
9
- }
9
+ end
10
10
  end
11
11
  end
12
12
  end
@@ -18,4 +18,3 @@ module Landrush
18
18
  end
19
19
  end
20
20
  end
21
-
@@ -21,4 +21,3 @@ module Landrush
21
21
  end
22
22
  end
23
23
  end
24
-
@@ -3,10 +3,10 @@ module Landrush
3
3
  module Redhat
4
4
  module InstallIptables
5
5
  def self.install_iptables(machine)
6
- machine.communicate.tap { |c|
6
+ machine.communicate.tap do |c|
7
7
  c.sudo('yum clean all')
8
8
  c.sudo('yum install -y -q iptables')
9
- }
9
+ end
10
10
  end
11
11
  end
12
12
  end
@@ -1,17 +1,19 @@
1
1
  module Landrush
2
2
  class Command < Vagrant.plugin('2', :command)
3
- DAEMON_COMMANDS = %w(start stop restart status)
3
+ DAEMON_COMMANDS = %w(start stop restart status).freeze
4
4
 
5
5
  def self.synopsis
6
6
  "manages DNS for both guest and host"
7
7
  end
8
8
 
9
9
  def execute
10
- ARGV.shift # flush landrush from ARGV, RExec wants to use it for daemon commands
10
+ # Make sure we use the right data directory for Landrush
11
+ Server.working_dir = File.join(@env.data_dir, 'landrush')
11
12
 
13
+ ARGV.shift # flush landrush from ARGV
12
14
  command = ARGV.first || 'help'
13
15
  if DAEMON_COMMANDS.include?(command)
14
- Server.daemonize
16
+ Server.send(command)
15
17
  elsif command == 'dependentvms' || command == 'vms'
16
18
  if DependentVMs.any?
17
19
  @env.ui.info(DependentVMs.list.map { |dvm| " - #{dvm}" }.join("\n"))
@@ -19,14 +21,11 @@ module Landrush
19
21
  @env.ui.info("No dependent VMs")
20
22
  end
21
23
  elsif command == 'ls' || command == 'list'
22
- IO.popen("/usr/bin/pr -2 -t -a", "w") do |io|
23
- Landrush::Store.hosts.each do |key, value|
24
- io.puts "#{key}"
25
- io.puts "#{value}"
26
- end
24
+ Landrush::Store.hosts.each do |key, value|
25
+ printf "%-30s %s\n", key, value
27
26
  end
28
27
  elsif command == 'set'
29
- host, ip = ARGV[1,2]
28
+ host, ip = ARGV[1, 2]
30
29
  Landrush::Store.hosts.set(host, ip)
31
30
  elsif command == 'del' || command == 'rm'
32
31
  key = ARGV[1]
@@ -70,6 +69,5 @@ module Landrush
70
69
  you're lookin at it!
71
70
  EOS
72
71
  end
73
-
74
72
  end
75
73
  end
@@ -13,7 +13,7 @@ module Landrush
13
13
  :upstream_servers => [[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]],
14
14
  :host_ip_address => nil,
15
15
  :guest_redirect_dns => true
16
- }
16
+ }.freeze
17
17
 
18
18
  def initialize
19
19
  @hosts = {}
@@ -22,7 +22,7 @@ module Landrush
22
22
  end
23
23
 
24
24
  def self.list
25
- self.map { |path| path.basename.to_s }
25
+ map { |path| path.basename.to_s }
26
26
  end
27
27
 
28
28
  def self.clear!
@@ -34,7 +34,7 @@ module Landrush
34
34
  end
35
35
 
36
36
  def self.dir
37
- Landrush.working_dir.join('dependent_vms').tap(&:mkpath)
37
+ Server.working_dir.join('dependent_vms').tap(&:mkpath)
38
38
  end
39
39
  end
40
40
  end
@@ -0,0 +1,19 @@
1
+ module Landrush
2
+ module OS
3
+ def self.windows?
4
+ (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
5
+ end
6
+
7
+ def self.mac?
8
+ (/darwin/ =~ RUBY_PLATFORM) != nil
9
+ end
10
+
11
+ def self.unix?
12
+ !windows?
13
+ end
14
+
15
+ def self.linux?
16
+ unix? && !mac?
17
+ end
18
+ end
19
+ end
@@ -12,7 +12,7 @@ module Landrush
12
12
  Config
13
13
  end
14
14
 
15
- landrush_setup = -> (hook) {
15
+ landrush_setup = lambda do |hook|
16
16
  require_relative 'action/common'
17
17
  require_relative 'action/setup'
18
18
  require_relative 'action/install_prerequisites'
@@ -34,7 +34,7 @@ module Landrush
34
34
  if defined?(VagrantPlugins::Parallels)
35
35
  hook.before(VagrantPlugins::Parallels::Action::Network, pre_boot_actions)
36
36
  end
37
- }
37
+ end
38
38
 
39
39
  action_hook 'landrush_setup', :machine_action_up, &landrush_setup
40
40
  action_hook 'landrush_setup', :machine_action_reload, &landrush_setup
@@ -52,11 +52,11 @@ module Landrush
52
52
  end
53
53
  end
54
54
 
55
- landrush_teardown = -> (hook) {
55
+ landrush_teardown = lambda do |hook|
56
56
  require_relative 'action/common'
57
57
  require_relative 'action/teardown'
58
58
  hook.after(Vagrant::Action::Builtin::GracefulHalt, Action::Teardown)
59
- }
59
+ end
60
60
 
61
61
  action_hook 'landrush_teardown', :machine_action_halt, &landrush_teardown
62
62
  action_hook 'landrush_teardown', :machine_action_destroy, &landrush_teardown
@@ -2,7 +2,7 @@ require 'tempfile'
2
2
 
3
3
  module Landrush
4
4
  class ResolverConfig
5
- class << self;
5
+ class << self
6
6
  attr_writer :sudo, :config_dir
7
7
  end
8
8
 
@@ -14,10 +14,6 @@ module Landrush
14
14
  @config_dir ||= Pathname('/etc/resolver')
15
15
  end
16
16
 
17
- def config_dir
18
- self.class.config_dir
19
- end
20
-
21
17
  def initialize(env={})
22
18
  @env = env
23
19
  end
@@ -1,13 +1,47 @@
1
1
  require 'rubydns'
2
- require 'rexec/daemon'
2
+ require 'ipaddr'
3
+ require_relative 'store'
4
+ require_relative 'os'
3
5
 
4
6
  module Landrush
5
- class Server < RExec::Daemon::Base
7
+ class Server
8
+ include Landrush::OS
9
+
6
10
  Name = Resolv::DNS::Name
7
11
  IN = Resolv::DNS::Resource::IN
8
12
 
13
+ def self.working_dir
14
+ # TODO, https://github.com/vagrant-landrush/landrush/issues/178
15
+ # Due to the fact that the whole server is just a bunch of static methods,
16
+ # there is no initalize method to ensure that the working directory is
17
+ # set prior to making calls to this method. Things work, since at the appropriate
18
+ # Vagrant plugin integrtion points (e.g. setup.rb) we set the working dir based
19
+ # on the enviroment passed to us.
20
+ if @working_dir.nil?
21
+ raise 'The Server\s working directory needs to be explicitly set prior to calling this method'
22
+ end
23
+ @working_dir
24
+ end
25
+
26
+ def self.working_dir=(working_dir)
27
+ @working_dir = Pathname(working_dir).tap(&:mkpath)
28
+ end
29
+
30
+ def self.log_directory
31
+ File.join(working_dir, 'log')
32
+ end
33
+
34
+ def self.log_file
35
+ File.join(log_directory, 'landrush.log')
36
+ end
37
+
9
38
  def self.port
10
- @port ||= 10053
39
+ if OS.windows?
40
+ # On Windows we need to use the default DNS port, since there seems to be no way to configure it otherwise
41
+ @port ||= 53
42
+ else
43
+ @port ||= 100_53
44
+ end
11
45
  end
12
46
 
13
47
  def self.port=(port)
@@ -21,8 +55,8 @@ module Landrush
21
55
 
22
56
  def self.interfaces
23
57
  [
24
- [:udp, "0.0.0.0", port],
25
- [:tcp, "0.0.0.0", port]
58
+ [:udp, '0.0.0.0', port],
59
+ [:tcp, '0.0.0.0', port]
26
60
  ]
27
61
  end
28
62
 
@@ -30,38 +64,85 @@ module Landrush
30
64
  @upstream ||= RubyDNS::Resolver.new(upstream_servers)
31
65
  end
32
66
 
33
- def self.pid
34
- RExec::Daemon::ProcessFile.recall(self)
67
+ # Used to start the Landrush DNS server as a child process using ChildProcess gem
68
+ def self.start
69
+ ensure_path_exits(log_file)
70
+
71
+ if OS.windows?
72
+ pid = spawn('ruby', __FILE__, port.to_s, working_dir.to_s, :chdir => working_dir.to_path, [:out, :err] => [log_file, "w"], :new_pgroup => true)
73
+ else
74
+ pid = spawn('ruby', __FILE__, port.to_s, working_dir.to_s, :chdir => working_dir.to_path, [:out, :err] => [log_file, "w"], :pgroup => true)
75
+ end
76
+ Process.detach pid
77
+
78
+ write_pid(pid)
79
+ end
80
+
81
+ def self.stop
82
+ puts 'Stopping daemon...'
83
+
84
+ # Check if the pid file exists...
85
+ unless File.file?(pid_file)
86
+ puts "Pid file #{pid_file} not found. Is the daemon running?"
87
+ return
88
+ end
89
+
90
+ pid = read_pid
91
+
92
+ # Check if the daemon is already stopped...
93
+ unless running?
94
+ puts "Pid #{pid} is not running. Has daemon crashed?"
95
+ return
96
+ end
97
+
98
+ terminate_process pid
99
+
100
+ # If after doing our best the daemon is still running (pretty odd)...
101
+ if running?
102
+ puts 'Daemon appears to be still running!'
103
+ return
104
+ end
105
+
106
+ # Otherwise the daemon has been stopped.
107
+ delete_pid_file
35
108
  end
36
109
 
37
- # For RExec
38
- def self.working_directory
39
- Landrush.working_dir
110
+ def self.restart
111
+ stop
112
+ start
40
113
  end
41
114
 
42
- def self.running?
43
- RExec::Daemon::ProcessFile.status(self) == :running
115
+ def self.pid
116
+ IO.read(pid_file).to_i rescue nil
44
117
  end
45
118
 
46
- def self.prefork
47
- super
119
+ def self.running?
120
+ pid = read_pid
121
+ return false if pid.nil?
122
+ !!Process.kill(0, pid) rescue false
48
123
  end
49
124
 
50
- def self.check_a_record (host, transaction)
51
- value = Store.hosts.get(host)
52
- if (IPAddr.new(value) rescue nil)
53
- name = transaction.name =~ /#{host}/ ? transaction.name : host
54
- transaction.respond!(value, {:ttl => 0, :name => name})
55
- else
56
- transaction.respond!(Name.create(value), resource_class: IN::CNAME, ttl: 0)
57
- check_a_record(value, transaction)
125
+ def self.status
126
+ case process_status
127
+ when :running
128
+ puts "Daemon status: running pid=#{read_pid}"
129
+ when :stopped
130
+ puts 'Daemon status: stopped'
131
+ else
132
+ puts 'Daemon status: unknown'
133
+ puts "#{pid_file} exists, but process is not running"
134
+ puts "Check log file: #{log_file}"
58
135
  end
59
136
  end
60
137
 
61
- def self.run
138
+ def self.run(port, working_dir)
62
139
  server = self
63
- RubyDNS::run_server(:listen => interfaces) do
64
- self.logger.level = Logger::INFO
140
+ server.port = port
141
+ server.working_dir = working_dir
142
+
143
+ # Start the DNS server
144
+ RubyDNS.run_server(:listen => interfaces) do
145
+ @logger.level = Logger::INFO
65
146
 
66
147
  match(/.*/, IN::A) do |transaction|
67
148
  host = Store.hosts.find(transaction.name)
@@ -83,9 +164,90 @@ module Landrush
83
164
 
84
165
  # Default DNS handler
85
166
  otherwise do |transaction|
167
+ # @logger.info "Passing on to upstream: #{transaction.to_s}"
86
168
  transaction.passthrough!(server.upstream)
87
169
  end
88
170
  end
89
171
  end
172
+
173
+ def self.check_a_record(host, transaction)
174
+ value = Store.hosts.get(host)
175
+ if value.nil?
176
+ return
177
+ end
178
+
179
+ if (IPAddr.new(value) rescue nil)
180
+ name = transaction.name =~ /#{host}/ ? transaction.name : host
181
+ transaction.respond!(value, :ttl => 0, :name => name)
182
+ else
183
+ transaction.respond!(Name.create(value), resource_class: IN::CNAME, ttl: 0)
184
+ check_a_record(value, transaction)
185
+ end
186
+ end
187
+
188
+ # private methods
189
+ def self.write_pid(pid)
190
+ ensure_path_exits(pid_file)
191
+ File.open(pid_file, 'w') {|f| f << pid.to_s}
192
+ end
193
+
194
+ def self.read_pid
195
+ IO.read(pid_file).to_i rescue nil
196
+ end
197
+
198
+ def self.delete_pid_file
199
+ if File.exist? pid_file
200
+ FileUtils.rm(pid_file)
201
+ end
202
+ end
203
+
204
+ def self.pid_file
205
+ File.join(working_dir, 'run', 'landrush.pid')
206
+ end
207
+
208
+ def self.process_status
209
+ if File.exist? pid_file
210
+ return running? ? :running : :unknown
211
+ else
212
+ return :stopped
213
+ end
214
+ end
215
+
216
+ def self.ensure_path_exits(file_name)
217
+ dirname = File.dirname(file_name)
218
+ unless File.directory?(dirname)
219
+ FileUtils.mkdir_p(dirname)
220
+ end
221
+ end
222
+
223
+ def self.terminate_process(pid)
224
+ Process.kill("INT", pid)
225
+ sleep 0.1
226
+
227
+ sleep 1 if running?
228
+
229
+ # Kill/Term loop - if the daemon didn't die easily, shoot
230
+ # it a few more times.
231
+ attempts = 5
232
+ while running? && attempts > 0
233
+ sig = (attempts >= 2) ? "KILL" : "TERM"
234
+
235
+ puts "Sending #{sig} to process #{pid}..."
236
+ Process.kill(sig, pid)
237
+
238
+ attempts -= 1
239
+ sleep 1
240
+ end
241
+ end
242
+
243
+ private_class_method :write_pid, :read_pid, :delete_pid_file, :pid_file, :process_status, :ensure_path_exits,
244
+ :terminate_process
90
245
  end
91
246
  end
247
+
248
+ # Only run the following code when this file is the main file being run
249
+ # instead of having been required or loaded by another file
250
+ if __FILE__ == $0
251
+ # TODO, Add some argument checks
252
+ Landrush::Server.run(ARGV[0], ARGV[1])
253
+ end