landrush 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +2 -0
  3. data/.rubocop_todo.yml +100 -12
  4. data/.travis.yml +1 -2
  5. data/CHANGELOG.md +11 -0
  6. data/Gemfile +11 -11
  7. data/README.adoc +8 -1
  8. data/Rakefile +3 -3
  9. data/appveyor.yml +3 -1
  10. data/doc/Development.adoc +24 -19
  11. data/doc/Usage.adoc +17 -6
  12. data/features/dns_resolution.feature +3 -0
  13. data/features/docker_provider.feature +32 -0
  14. data/features/support/env.rb +2 -2
  15. data/landrush.gemspec +3 -3
  16. data/lib/landrush.rb +1 -0
  17. data/lib/landrush/action/common.rb +7 -2
  18. data/lib/landrush/action/redirect_dns.rb +3 -0
  19. data/lib/landrush/action/setup.rb +16 -12
  20. data/lib/landrush/action/teardown.rb +2 -0
  21. data/lib/landrush/cap/guest/all/read_host_visible_ip_address.rb +2 -2
  22. data/lib/landrush/cap/guest/linux/add_iptables_rule.rb +2 -2
  23. data/lib/landrush/cap/guest/linux/configured_dns_servers.rb +1 -0
  24. data/lib/landrush/cap/guest/linux/redirect_dns.rb +1 -1
  25. data/lib/landrush/cap/guest/suse/add_iptables_rule.rb +2 -2
  26. data/lib/landrush/cap/host/arch/dnsmasq_installed.rb +11 -0
  27. data/lib/landrush/cap/host/arch/install_dnsmasq.rb +16 -0
  28. data/lib/landrush/cap/host/arch/restart_dnsmasq.rb +21 -0
  29. data/lib/landrush/cap/host/darwin/configure_visibility_on_host.rb +21 -18
  30. data/lib/landrush/cap/host/debian/host.rb +1 -0
  31. data/lib/landrush/cap/host/linux/configure_visibility_on_host.rb +5 -3
  32. data/lib/landrush/cap/host/linux/create_dnsmasq_config.rb +3 -0
  33. data/lib/landrush/cap/host/redhat/restart_dnsmasq.rb +8 -2
  34. data/lib/landrush/cap/host/ubuntu/host.rb +1 -0
  35. data/lib/landrush/cap/host/windows/configure_visibility_on_host.rb +14 -6
  36. data/lib/landrush/command.rb +18 -3
  37. data/lib/landrush/config.rb +6 -2
  38. data/lib/landrush/dns_server.rb +82 -0
  39. data/lib/landrush/plugin.rb +18 -0
  40. data/lib/landrush/server.rb +147 -205
  41. data/lib/landrush/start_server.rb +1 -1
  42. data/lib/landrush/store.rb +53 -24
  43. data/lib/landrush/util/dnsmasq.rb +10 -0
  44. data/lib/landrush/util/process_helper.rb +16 -16
  45. data/lib/landrush/util/retry.rb +1 -0
  46. data/lib/landrush/version.rb +1 -1
  47. data/test/landrush/action/setup_test.rb +8 -7
  48. data/test/landrush/action/teardown_test.rb +5 -5
  49. data/test/landrush/cap/guest/linux/redirect_dns_test.rb +1 -1
  50. data/test/landrush/cap/host/darwin/configure_visibility_on_host_test.rb +10 -6
  51. data/test/landrush/cap/host/linux/configure_visibility_on_host_test.rb +1 -1
  52. data/test/landrush/cap/host/windows/configure_visibility_on_host_test.rb +35 -4
  53. data/test/landrush/issues/255.rb +55 -55
  54. data/test/landrush/parallel_store_use_test.rb +50 -0
  55. data/test/landrush/server_test.rb +6 -17
  56. data/test/landrush/store_test.rb +8 -8
  57. data/test/landrush/util/dnsmasq_test.rb +42 -0
  58. data/test/support/create_fake_working_dir.rb +3 -2
  59. data/test/support/delete_fake_working_dir.rb +1 -1
  60. data/test/support/test_server_daemon.rb +1 -1
  61. data/test/test_helper.rb +6 -8
  62. metadata +42 -17
@@ -5,7 +5,7 @@ require 'find'
5
5
 
6
6
  Aruba.configure do |config|
7
7
  config.exit_timeout = 3600
8
- config.activate_announcer_on_command_failure = [:stdout, :stderr]
8
+ config.activate_announcer_on_command_failure = %i[stdout stderr]
9
9
  config.working_directory = 'build/aruba'
10
10
  end
11
11
 
@@ -20,7 +20,7 @@ Before do |_scenario|
20
20
  .each { |file| FileUtils.rmtree(File.join(ENV['VAGRANT_HOME'], file)) }
21
21
 
22
22
  # Actual gems are in ~/vagrant.d/gems/gems
23
- gems_path = File.join(vagrant_home, 'gems', 'gems')
23
+ gems_path = File.join(vagrant_home, 'gems', RUBY_VERSION)
24
24
  FileUtils.mkdir_p gems_path
25
25
 
26
26
  # Find the path to the Bundler gems
@@ -1,5 +1,4 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'landrush/version'
5
4
 
@@ -28,7 +27,8 @@ Gem::Specification.new do |spec|
28
27
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
29
28
  spec.require_paths = ['lib']
30
29
 
30
+ spec.add_dependency 'filelock'
31
+ spec.add_dependency 'landrush-ip', '~> 0.2.5'
31
32
  spec.add_dependency 'rubydns', '0.8.5'
32
33
  spec.add_dependency 'win32-process'
33
- spec.add_dependency 'landrush-ip', '~> 0.2.5'
34
34
  end
@@ -16,3 +16,4 @@ require 'landrush/server'
16
16
  require 'landrush/store'
17
17
  require 'landrush/version'
18
18
  require 'landrush-ip'
19
+ require 'socket'
@@ -8,6 +8,7 @@ module Landrush
8
8
  'HashiCorp::VagrantVMwarefusion::Provider' => :vmware_fusion,
9
9
  'VagrantPlugins::Parallels::Provider' => :parallels,
10
10
  'VagrantPlugins::HyperV::Provider' => :hyperv,
11
+ 'VagrantPlugins::DockerProvider::Provider' => :docker,
11
12
  'Landrush::FakeProvider' => :fake_provider
12
13
  }.freeze
13
14
 
@@ -20,6 +21,10 @@ module Landrush
20
21
  @env = env
21
22
  end
22
23
 
24
+ def docker?
25
+ provider == :docker
26
+ end
27
+
23
28
  def virtualbox?
24
29
  provider == :virtualbox
25
30
  end
@@ -69,7 +74,7 @@ module Landrush
69
74
  def read_machine_hostname
70
75
  return machine.config.vm.hostname if machine.config.vm.hostname
71
76
 
72
- "#{Pathname.pwd.basename}.#{config.tld}"
77
+ "#{Pathname.pwd.basename}.#{config.tld_as_array[0]}"
73
78
  end
74
79
 
75
80
  def enabled?
@@ -86,7 +91,7 @@ module Landrush
86
91
 
87
92
  def log(level, msg)
88
93
  # Levels from github.com/mitchellh/vagrant/blob/master/lib/vagrant/ui.rb
89
- valid_levels = [:ask, :detail, :warn, :error, :info, :output, :success]
94
+ valid_levels = %i[ask detail warn error info output success]
90
95
 
91
96
  if valid_levels.include? level
92
97
  env[:ui].send level, "[landrush] #{msg}"
@@ -29,6 +29,9 @@ module Landrush
29
29
  _gateway_for_ip(machine.guest.capability(:configured_dns_servers).first)
30
30
  when :parallels then
31
31
  machine.provider.capability(:host_address)
32
+ else
33
+ # As a fallthrough default use the first non loopback IP. This IP should be reachable from the guest as well
34
+ Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
32
35
  end
33
36
  end
34
37
 
@@ -37,9 +37,10 @@ module Landrush
37
37
  configure_server
38
38
  record_machine_dns_entry
39
39
  setup_static_dns
40
- start_server
40
+ Server.start
41
41
  return unless machine.config.landrush.host_redirect_dns?
42
- env[:host].capability(:configure_visibility_on_host, host_ip_address, config.tld)
42
+
43
+ env[:host].capability(:configure_visibility_on_host, host_ip_address, config.tld_as_array)
43
44
  end
44
45
 
45
46
  def record_dependent_vm
@@ -57,19 +58,15 @@ module Landrush
57
58
  Store.config.set('upstream', config.upstream_servers)
58
59
  end
59
60
 
60
- def start_server
61
- return if Server.running?
62
- info 'starting dns server'
63
- Server.start
64
- end
65
-
66
61
  def setup_static_dns
67
62
  config.hosts.each do |hostname, dns_value|
68
63
  dns_value ||= host_ip_address
69
64
  next if Store.hosts.has?(hostname, dns_value)
65
+
70
66
  info "adding static DNS entry: #{hostname} => #{dns_value}"
71
67
  Store.hosts.set hostname, dns_value
72
68
  next unless ip_address?(dns_value)
69
+
73
70
  reverse_dns = IPAddr.new(dns_value).reverse
74
71
  info "adding static reverse DNS entry: #{reverse_dns} => #{dns_value}"
75
72
  Store.hosts.set(reverse_dns, hostname)
@@ -83,9 +80,16 @@ module Landrush
83
80
  def record_machine_dns_entry
84
81
  ip_address = machine.config.landrush.host_ip_address || host_ip_address
85
82
 
86
- unless machine_hostname.match(config.tld)
87
- log :error, "hostname #{machine_hostname} does not match the configured TLD: #{config.tld}"
88
- log :error, "You will not be able to access #{machine_hostname} from the host"
83
+ tld_match = false
84
+ config.tld_as_array.each do |tld|
85
+ if machine_hostname.match(tld)
86
+ tld_match = true
87
+ break
88
+ end
89
+ end
90
+ unless tld_match
91
+ log :error, "hostname #{machine_hostname} does not match any of the configured TLD: #{config.tld_as_array}"
92
+ log :error, "You will not be able to access #{machine_hostname} from your host"
89
93
  end
90
94
 
91
95
  unless Store.hosts.has?(machine_hostname, ip_address)
@@ -103,7 +107,7 @@ module Landrush
103
107
  def private_network_ips
104
108
  # machine.config.vm.networks is an array of two elements. The first containing the type as symbol, the second is a
105
109
  # hash containing other config data which varies between types
106
- machine.config.vm.networks.select { |network| :private_network == network[0] && !network[1][:ip].nil? }
110
+ machine.config.vm.networks.select { |network| network[0] == :private_network && !network[1][:ip].nil? }
107
111
  .map { |network| network[1][:ip] }
108
112
  end
109
113
  end
@@ -17,12 +17,14 @@ module Landrush
17
17
  DependentVMs.remove(machine_hostname)
18
18
 
19
19
  return unless DependentVMs.none?
20
+
20
21
  teardown_static_dns
21
22
  teardown_server
22
23
  end
23
24
 
24
25
  def teardown_machine_dns
25
26
  return unless Store.hosts.has? machine_hostname
27
+
26
28
  info "removing machine entry: #{machine_hostname}"
27
29
  Store.hosts.delete(machine_hostname)
28
30
  end
@@ -6,8 +6,8 @@ module Landrush
6
6
  unless @machine.config.landrush.host_interface_excludes.nil?
7
7
  re = Regexp.union(@machine.config.landrush.host_interface_excludes)
8
8
 
9
- addresses = addresses.select do |addr|
10
- !addr['name'].match(re)
9
+ addresses = addresses.reject do |addr|
10
+ addr['name'].match(re)
11
11
  end
12
12
  end
13
13
 
@@ -8,8 +8,8 @@ module Landrush
8
8
 
9
9
  def self._run(machine, command)
10
10
  machine.communicate.sudo(command) do |data, type|
11
- if [:stderr, :stdout].include?(type)
12
- color = (type == :stdout) ? :green : :red
11
+ if %i[stderr stdout].include?(type)
12
+ color = type == :stdout ? :green : :red
13
13
  machine.env.ui.info(data.chomp, color: color, prefix: false)
14
14
  end
15
15
  end
@@ -4,6 +4,7 @@ module Landrush
4
4
  module ConfiguredDnsServers
5
5
  def self.configured_dns_servers(machine)
6
6
  return @dns_servers if @dns_servers
7
+
7
8
  machine.communicate.sudo('cat /etc/resolv.conf | grep ^nameserver') do |type, data|
8
9
  if type == :stdout
9
10
  @dns_servers = Array(data.scan(/\d+\.\d+\.\d+\.\d+/))
@@ -4,7 +4,7 @@ module Landrush
4
4
  module RedirectDns
5
5
  def self.redirect_dns(machine, target = {})
6
6
  dns_servers = machine.guest.capability(:configured_dns_servers)
7
- %w(tcp udp).each do |proto|
7
+ %w[tcp udp].each do |proto|
8
8
  dns_servers.each do |dns_server|
9
9
  machine.guest.capability(
10
10
  :add_iptables_rule,
@@ -8,8 +8,8 @@ module Landrush
8
8
 
9
9
  def self._run(machine, command)
10
10
  machine.communicate.sudo(command) do |data, type|
11
- if [:stderr, :stdout].include?(type)
12
- color = (type == :stdout) ? :green : :red
11
+ if %i[stderr stdout].include?(type)
12
+ color = type == :stdout ? :green : :red
13
13
  machine.env.ui.info(data.chomp, color: color, prefix: false)
14
14
  end
15
15
  end
@@ -0,0 +1,11 @@
1
+ module Landrush
2
+ module Cap
3
+ module Arch
4
+ module DnsmasqInstalled
5
+ def self.dnsmasq_installed(_env, *_args)
6
+ system('pacman -Q dnsmasq > /dev/null 2>&1')
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Landrush
2
+ module Cap
3
+ module Arch
4
+ module InstallDnsmasq
5
+ class << self
6
+ def install_dnsmasq(_env)
7
+ system('pacman -Sy --noconfirm > /dev/null 2>&1')
8
+ system('sudo pacman -S --noconfirm dnsmasq > /dev/null 2>&1')
9
+
10
+ system('sudo sed -i "/^#conf-dir=\/etc\/dnsmasq.d$/s/^#//g" /etc/dnsmasq.conf')
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module Landrush
2
+ module Cap
3
+ module Arch
4
+ module RestartDnsmasq
5
+ class << self
6
+ SED_COMMAND = <<-EOF.gsub(/^ +/, '')
7
+ sudo sed -i.orig '1 i\
8
+ # Added by landrush, a vagrant plugin \\
9
+ nameserver 127.0.0.1 \\
10
+ ' /etc/resolv.conf
11
+ EOF
12
+
13
+ def restart_dnsmasq(_env)
14
+ system(SED_COMMAND) unless system("cat /etc/resolv.conf | grep 'nameserver 127.0.0.1' > /dev/null 2>&1")
15
+ system('sudo systemctl restart dnsmasq')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -5,14 +5,16 @@ module Landrush
5
5
  class << self
6
6
  attr_writer :sudo, :config_dir
7
7
 
8
- def configure_visibility_on_host(env, _ip, tld)
8
+ def configure_visibility_on_host(env, _ip, tlds)
9
9
  @env = env
10
- @tld = tld
11
- if contents_match?
12
- info 'Host DNS resolver config looks good.'
13
- else
14
- info 'Need to configure the host.'
15
- write_config!
10
+
11
+ tlds.each do |tld|
12
+ if contents_match?(tld)
13
+ info "Host DNS resolver config for TLD '#{tld}' looks good."
14
+ else
15
+ info "Need to create /etc/resolver entry for TLD '#{tld}'"
16
+ write_config!(tld)
17
+ end
16
18
  end
17
19
  end
18
20
 
@@ -23,7 +25,11 @@ module Landrush
23
25
  end
24
26
 
25
27
  def config_dir
26
- @config_dir ||= Pathname('/etc/resolver')
28
+ @config_dir ||= '/etc/resolver'
29
+ end
30
+
31
+ def config_file(tld)
32
+ File.join(config_dir, tld)
27
33
  end
28
34
 
29
35
  def info(msg)
@@ -38,22 +44,19 @@ module Landrush
38
44
  EOS
39
45
  end
40
46
 
41
- def config_file
42
- config_dir.join(@tld)
43
- end
44
-
45
- def contents_match?
46
- config_file.exist? && File.read(config_file) == desired_contents
47
+ def contents_match?(tld)
48
+ config_file = config_file(tld)
49
+ File.exist?(config_file) && File.read(config_file) == desired_contents
47
50
  end
48
51
 
49
- def write_config!
52
+ def write_config!(tld)
50
53
  info 'Momentarily using sudo to put the host config in place...'
51
- system "#{sudo} mkdir #{config_dir}" unless config_dir.directory?
54
+ system "#{sudo} mkdir #{config_dir}" unless File.directory?(config_dir)
52
55
  Tempfile.open('vagrant_landrush_host_config') do |f|
53
56
  f.write(desired_contents)
54
57
  f.close
55
- system "#{sudo} cp #{f.path} #{config_file}"
56
- system "#{sudo} chmod 644 #{config_file}"
58
+ system "#{sudo} cp #{f.path} #{config_file(tld)}"
59
+ system "#{sudo} chmod 644 #{config_file(tld)}"
57
60
  end
58
61
  end
59
62
  end
@@ -4,6 +4,7 @@ module Landrush
4
4
  class DebianHost < Vagrant.plugin('2', 'host')
5
5
  def detect?(_env)
6
6
  return false unless Pathname('/etc/issue').exist?
7
+
7
8
  system("cat /etc/issue | grep 'Debian' > /dev/null 2>&1")
8
9
  end
9
10
  end
@@ -3,12 +3,14 @@ module Landrush
3
3
  module Linux
4
4
  class ConfigureVisibilityOnHost
5
5
  class << self
6
- def configure_visibility_on_host(env, ip, tld)
6
+ def configure_visibility_on_host(env, ip, tlds)
7
7
  env.host.capability(:install_dnsmasq) unless env.host.capability(:dnsmasq_installed)
8
- env.host.capability(:create_dnsmasq_config, ip, tld)
8
+ tlds.each do |tld|
9
+ env.host.capability(:create_dnsmasq_config, ip, tld)
10
+ end
9
11
  env.host.capability(:restart_dnsmasq)
10
12
  rescue Vagrant::Errors::CapabilityNotFound => e
11
- env.ui.info("Your host was detected as '#{e.extra_data[:cap]}' for which the host capability " \
13
+ env.ui.info("Your host was detected as '#{e.extra_data[:host]}' for which the host capability " \
12
14
  "'#{e.extra_data[:cap]}' is not available.")
13
15
  env.ui.info('Check the documentation for the manual instructions to configure the visibility on the host.')
14
16
  end
@@ -1,3 +1,5 @@
1
+ require_relative '../../../util/dnsmasq'
2
+
1
3
  module Landrush
2
4
  module Cap
3
5
  module Linux
@@ -21,6 +23,7 @@ module Landrush
21
23
  end
22
24
 
23
25
  def config_dir
26
+ @config_dir ||= Pathname('/etc/NetworkManager/dnsmasq.d') if Landrush::Util::Dnsmasq.nm_managed?
24
27
  @config_dir ||= Pathname('/etc/dnsmasq.d')
25
28
  end
26
29
 
@@ -1,3 +1,5 @@
1
+ require_relative '../../../util/dnsmasq'
2
+
1
3
  module Landrush
2
4
  module Cap
3
5
  module Redhat
@@ -13,8 +15,12 @@ module Landrush
13
15
  def restart_dnsmasq(_env)
14
16
  # TODO: At some stage we might want to make create_dnsmasq_config host specific and add the resolv.conf
15
17
  # changes there which seems more natural
16
- system(SED_COMMAND) unless system("cat /etc/resolv.conf | grep 'nameserver 127.0.0.1' > /dev/null 2>&1")
17
- system('sudo systemctl restart dnsmasq')
18
+ if Landrush::Util::Dnsmasq.nm_managed?
19
+ system('sudo systemctl reload NetworkManager')
20
+ else
21
+ system(SED_COMMAND) unless system("cat /etc/resolv.conf | grep 'nameserver 127.0.0.1' > /dev/null 2>&1")
22
+ system('sudo systemctl restart dnsmasq')
23
+ end
18
24
  end
19
25
  end
20
26
  end
@@ -4,6 +4,7 @@ module Landrush
4
4
  class UbuntuHost < Vagrant.plugin('2', 'host')
5
5
  def detect?(_env)
6
6
  return false unless Pathname('/usr/bin/lsb_release').exist?
7
+
7
8
  system("/usr/bin/lsb_release -i | grep 'Ubuntu' >/dev/null 2>&1")
8
9
  end
9
10
  end
@@ -10,9 +10,11 @@ module Landrush
10
10
  INTERFACES = 'SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces'.freeze
11
11
 
12
12
  class << self
13
- def configure_visibility_on_host(env, ip, tld)
13
+ def configure_visibility_on_host(env, ip, tlds)
14
14
  @env = env
15
- update_network_adapter(ip, tld) if ensure_prerequisites
15
+ # tlds is an array. See also issue #177. For now we only support single TLD on windows, hence we select the
16
+ # first element
17
+ update_network_adapter(ip, tlds[0]) if ensure_prerequisites
16
18
  end
17
19
 
18
20
  # If this registry query succeeds we assume we have Admin rights
@@ -96,6 +98,7 @@ module Landrush
96
98
  cmd_out = `netsh lan show interfaces`
97
99
  interface_details = cmd_out.split(/\n\n/).select { |settings| settings.match(/#{Regexp.quote(network_name)}/m) }
98
100
  return nil if interface_details.empty?
101
+
99
102
  interface_details[0].split(/\n/)[2].match(/.*:(.*)/).captures[0].strip
100
103
  end
101
104
 
@@ -125,11 +128,12 @@ module Landrush
125
128
  address = IPAddr.new(ip)
126
129
 
127
130
  mask.include?(address)
128
- rescue
131
+ rescue StandardError
129
132
  false
130
133
  end
131
134
  end
132
135
  return nil if network_details[0].nil?
136
+
133
137
  network_details[0].split(/\n/)[0].match(/Configuration for interface "(.*)"/).captures[0].strip
134
138
  end
135
139
 
@@ -145,9 +149,13 @@ module Landrush
145
149
  @env.ui.info("[landrush] #{msg}") unless @env.nil?
146
150
  end
147
151
 
152
+ def wired_autoconfig_service_state
153
+ `sc query dot3svc`
154
+ end
155
+
148
156
  def wired_autoconfig_service_running?
149
- cmd_out = `net start`
150
- cmd_out =~ /Wired AutoConfig/m
157
+ cmd_out = wired_autoconfig_service_state
158
+ cmd_out =~ /\s*STATE\s+:\s+4\s+RUNNING/m
151
159
  end
152
160
 
153
161
  def command_found(cmd)
@@ -180,6 +188,6 @@ end
180
188
 
181
189
  # Only run the following code when this file is the main file being run
182
190
  # instead of having been required or loaded by another file
183
- if __FILE__ == $PROGRAM_NAME
191
+ if $PROGRAM_NAME == __FILE__
184
192
  Landrush::Cap::Windows::ConfigureVisibilityOnHost.configure_visibility_on_host(nil, ARGV[0], ARGV[1])
185
193
  end