landrush 0.19.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|