landrush 0.19.0 → 1.0.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.
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