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.
- checksums.yaml +4 -4
- data/.config/cucumber.yml +7 -0
- data/.gitignore +6 -4
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +32 -259
- data/CHANGELOG.md +8 -1
- data/CONTRIBUTING.md +11 -10
- data/Gemfile +7 -4
- data/Gemfile.lock +178 -0
- data/README.md +148 -35
- data/Rakefile +18 -0
- data/doc/img/advanced-tcp-properties.png +0 -0
- data/doc/img/network-connections.png +0 -0
- data/features/dns_resolution.feature +26 -0
- data/features/step_definitions/dns.rb +19 -0
- data/features/support/env.rb +16 -0
- data/landrush.gemspec +1 -2
- data/lib/landrush.rb +0 -12
- data/lib/landrush/action/common.rb +5 -5
- data/lib/landrush/action/redirect_dns.rb +1 -1
- data/lib/landrush/action/setup.rb +9 -14
- data/lib/landrush/action/teardown.rb +5 -1
- data/lib/landrush/cap/debian/install_iptables.rb +2 -2
- data/lib/landrush/cap/linux/add_iptables_rule.rb +0 -1
- data/lib/landrush/cap/linux/redirect_dns.rb +0 -1
- data/lib/landrush/cap/redhat/install_iptables.rb +2 -2
- data/lib/landrush/command.rb +8 -10
- data/lib/landrush/config.rb +1 -1
- data/lib/landrush/dependent_vms.rb +2 -2
- data/lib/landrush/os.rb +19 -0
- data/lib/landrush/plugin.rb +4 -4
- data/lib/landrush/resolver_config.rb +1 -5
- data/lib/landrush/server.rb +187 -25
- data/lib/landrush/store.rb +12 -4
- data/lib/landrush/version.rb +1 -1
- data/test/landrush/action/setup_test.rb +14 -9
- data/test/landrush/action/teardown_test.rb +8 -9
- data/test/landrush/cap/linux/configured_dns_servers_test.rb +2 -2
- data/test/landrush/cap/linux/read_host_visible_ip_address_test.rb +5 -7
- data/test/landrush/cap/linux/redirect_dns_test.rb +1 -1
- data/test/landrush/resolver_config_test.rb +0 -2
- data/test/landrush/server_test.rb +18 -12
- data/test/landrush/store_test.rb +7 -6
- data/test/support/clear_dependent_vms.rb +4 -2
- data/test/support/create_fake_working_dir.rb +19 -0
- data/test/support/delete_fake_working_dir.rb +12 -0
- data/test/support/fake_resolver_config.rb +8 -3
- data/test/support/test_server_daemon.rb +20 -15
- data/test/test_helper.rb +31 -22
- metadata +26 -28
- data/lib/ext/rexec.rb +0 -10
- 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
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)
|
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
|
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?
|
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
|
-
|
48
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
data/lib/landrush/command.rb
CHANGED
@@ -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
|
-
|
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.
|
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
|
-
|
23
|
-
|
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
|
data/lib/landrush/config.rb
CHANGED
@@ -22,7 +22,7 @@ module Landrush
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.list
|
25
|
-
|
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
|
-
|
37
|
+
Server.working_dir.join('dependent_vms').tap(&:mkpath)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/lib/landrush/os.rb
ADDED
@@ -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
|
data/lib/landrush/plugin.rb
CHANGED
@@ -12,7 +12,7 @@ module Landrush
|
|
12
12
|
Config
|
13
13
|
end
|
14
14
|
|
15
|
-
landrush_setup =
|
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 =
|
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
|
data/lib/landrush/server.rb
CHANGED
@@ -1,13 +1,47 @@
|
|
1
1
|
require 'rubydns'
|
2
|
-
require '
|
2
|
+
require 'ipaddr'
|
3
|
+
require_relative 'store'
|
4
|
+
require_relative 'os'
|
3
5
|
|
4
6
|
module Landrush
|
5
|
-
class Server
|
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
|
-
|
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,
|
25
|
-
[:tcp,
|
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
|
-
|
34
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
110
|
+
def self.restart
|
111
|
+
stop
|
112
|
+
start
|
40
113
|
end
|
41
114
|
|
42
|
-
def self.
|
43
|
-
|
115
|
+
def self.pid
|
116
|
+
IO.read(pid_file).to_i rescue nil
|
44
117
|
end
|
45
118
|
|
46
|
-
def self.
|
47
|
-
|
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.
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
64
|
-
|
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
|