landrush 1.2.0 → 1.3.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 (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