landrush 1.0.0 → 1.1.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -8
  3. data/.rubocop.yml +1 -0
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG.md +4 -4
  6. data/CONTRIBUTING.md +54 -17
  7. data/Gemfile +4 -8
  8. data/README.md +152 -40
  9. data/features/dns_resolution.feature +9 -0
  10. data/features/landrush-ip.feature +57 -0
  11. data/features/step_definitions/ip.rb +13 -0
  12. data/landrush.gemspec +3 -1
  13. data/lib/landrush/action/setup.rb +49 -10
  14. data/lib/landrush/cap/all/read_host_visible_ip_address.rb +49 -0
  15. data/lib/landrush/config.rb +17 -11
  16. data/lib/landrush/plugin.rb +2 -2
  17. data/lib/landrush/resolver_config.rb +3 -7
  18. data/lib/landrush/server.rb +48 -22
  19. data/lib/landrush/util/retry.rb +16 -0
  20. data/lib/landrush/version.rb +1 -1
  21. data/lib/landrush/win_network_config.rb +185 -0
  22. data/lib/landrush.rb +6 -1
  23. data/test/landrush/action/setup_test.rb +44 -1
  24. data/test/landrush/action/teardown_test.rb +1 -1
  25. data/test/landrush/cap/all/read_host_visible_ip_address_test.rb +87 -0
  26. data/test/landrush/cap/linux/configured_dns_servers_test.rb +1 -1
  27. data/test/landrush/cap/linux/redirect_dns_test.rb +1 -1
  28. data/test/landrush/config_test.rb +1 -1
  29. data/test/landrush/dependent_vms_test.rb +1 -1
  30. data/test/landrush/resolver_config_test.rb +1 -3
  31. data/test/landrush/server_test.rb +1 -1
  32. data/test/landrush/store_test.rb +1 -1
  33. data/test/landrush/util/rety_test.rb +50 -0
  34. data/test/landrush/win_network_config_test.rb +70 -0
  35. data/test/support/fake_ui.rb +1 -0
  36. data/test/test_helper.rb +26 -11
  37. metadata +46 -12
  38. data/Gemfile.lock +0 -178
  39. data/examples/Vagrantfile +0 -20
  40. data/issues/vbox/Vagrantfile +0 -122
  41. data/lib/landrush/cap/linux/read_host_visible_ip_address.rb +0 -47
  42. data/lib/landrush/os.rb +0 -19
  43. data/test/landrush/cap/linux/read_host_visible_ip_address_test.rb +0 -37
@@ -15,24 +15,41 @@ module Landrush
15
15
  # This is after the middleware stack returns, which, since we're right
16
16
  # before the Network action, should mean that all interfaces are good
17
17
  # to go.
18
- record_machine_dns_entry if enabled?
19
- setup_static_dns if enabled?
18
+ post_boot_setup if enabled?
20
19
  end
21
20
 
21
+ def host_ip_address
22
+ static_private_network_ip || machine.guest.capability(:read_host_visible_ip_address)
23
+ end
24
+
25
+ private
26
+
22
27
  def pre_boot_setup
23
28
  record_dependent_vm
24
29
  add_prerequisite_network_interface
25
- setup_host_resolver
26
30
  configure_server
27
31
  start_server
28
32
  end
29
33
 
34
+ def post_boot_setup
35
+ record_machine_dns_entry
36
+ setup_static_dns
37
+ setup_host_resolver(env)
38
+ end
39
+
30
40
  def record_dependent_vm
31
41
  DependentVMs.add(machine_hostname)
32
42
  end
33
43
 
34
- def setup_host_resolver
35
- ResolverConfig.new(env).ensure_config_exists!
44
+ def setup_host_resolver(env)
45
+ if Vagrant::Util::Platform.windows?
46
+ network_config = WinNetworkConfig.new(env)
47
+ if network_config.ensure_prerequisites
48
+ network_config.update_network_adapter(host_ip_address, '127.0.0.1', config.tld)
49
+ end
50
+ elsif Vagrant::Util::Platform.darwin?
51
+ ResolverConfig.new(env).ensure_config_exists!
52
+ end
36
53
  end
37
54
 
38
55
  def add_prerequisite_network_interface
@@ -54,18 +71,25 @@ module Landrush
54
71
 
55
72
  def setup_static_dns
56
73
  config.hosts.each do |hostname, dns_value|
57
- dns_value ||= machine.guest.capability(:read_host_visible_ip_address)
74
+ dns_value ||= host_ip_address
58
75
  unless Store.hosts.has?(hostname, dns_value)
59
- info "adding static entry: #{hostname} => #{dns_value}"
76
+ info "adding static DNS entry: #{hostname} => #{dns_value}"
60
77
  Store.hosts.set hostname, dns_value
61
- Store.hosts.set(IPAddr.new(dns_value).reverse, hostname)
78
+ if ip_address?(dns_value)
79
+ reverse_dns = IPAddr.new(dns_value).reverse
80
+ info "adding static reverse DNS entry: #{reverse_dns} => #{dns_value}"
81
+ Store.hosts.set(reverse_dns, hostname)
82
+ end
62
83
  end
63
84
  end
64
85
  end
65
86
 
87
+ def ip_address?(value)
88
+ !(value =~ Resolv::IPv4::Regex).nil?
89
+ end
90
+
66
91
  def record_machine_dns_entry
67
- ip_address = machine.config.landrush.host_ip_address ||
68
- machine.guest.capability(:read_host_visible_ip_address)
92
+ ip_address = machine.config.landrush.host_ip_address || host_ip_address
69
93
 
70
94
  unless machine_hostname.match(config.tld)
71
95
  log :error, "hostname #{machine_hostname} does not match the configured TLD: #{config.tld}"
@@ -82,6 +106,21 @@ module Landrush
82
106
  def private_network_exists?
83
107
  machine.config.vm.networks.any? { |type, _| type == :private_network }
84
108
  end
109
+
110
+ # machine.config.vm.networks is an array of two elements. The first containing the type as symbol, the second is a
111
+ # hash containing other config data which varies between types
112
+ def static_private_network_ip
113
+ # select all staticlly defined private network ip
114
+ private_networks = machine.config.vm.networks.select {|network| :private_network == network[0] && !network[1][:ip].nil?}
115
+ .map {|network| network[1][:ip]}
116
+ if machine.config.landrush.host_ip_address.nil?
117
+ private_networks[0] if private_networks.length == 1
118
+ elsif private_networks.include? machine.config.landrush.host_ip_address
119
+ machine.config.landrush.host_ip_address
120
+ end
121
+ # If there is more than one private network or there is no match between config.landrush.host_ip_address
122
+ # and the discovered addresses we will pass on to read_host_visible_ip_address capability
123
+ end
85
124
  end
86
125
  end
87
126
  end
@@ -0,0 +1,49 @@
1
+ module Landrush
2
+ module Cap
3
+ module All
4
+ module ReadHostVisibleIpAddress
5
+ def self.filter_addresses(addresses)
6
+ unless @machine.config.landrush.host_interface_excludes.nil?
7
+ re = Regexp.union(@machine.config.landrush.host_interface_excludes)
8
+
9
+ addresses = addresses.select do |addr|
10
+ !addr['name'].match(re)
11
+ end
12
+ end
13
+
14
+ addresses
15
+ end
16
+
17
+ def self.read_host_visible_ip_address(machine)
18
+ @machine = machine
19
+
20
+ addr = nil
21
+ addresses = machine.guest.capability(:landrush_ip_get)
22
+
23
+ # Short circuit this one first: if an explicit interface is defined, look for it and return it if found.
24
+ # Technically, we could do a single loop, but execution time is not vital here.
25
+ # This allows us to be more accurate, especially with logging what's going on.
26
+ unless machine.config.landrush.host_interface.nil?
27
+ addr = addresses.detect { |a| a['name'] == machine.config.landrush.host_interface }
28
+
29
+ machine.env.ui.warn "[landrush] Unable to find interface #{machine.config.landrush.host_interface}" if addr.nil?
30
+ end
31
+
32
+ if addr.nil?
33
+ addresses = filter_addresses addresses
34
+
35
+ raise 'No addresses found' if addresses.empty?
36
+
37
+ addr = addresses.last
38
+ end
39
+
40
+ ip = IPAddr.new(addr['ipv4'])
41
+
42
+ machine.env.ui.info "[landrush] Using #{addr['name']} (#{addr['ipv4']})"
43
+
44
+ ip.to_s
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -6,22 +6,28 @@ module Landrush
6
6
  attr_accessor :upstream_servers
7
7
  attr_accessor :host_ip_address
8
8
  attr_accessor :guest_redirect_dns
9
+ attr_accessor :host_interface
10
+ attr_accessor :host_interface_excludes
9
11
 
10
12
  DEFAULTS = {
11
- :enabled => false,
12
- :tld => 'vagrant.test',
13
- :upstream_servers => [[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]],
14
- :host_ip_address => nil,
15
- :guest_redirect_dns => true
13
+ :enabled => false,
14
+ :tld => 'vagrant.test',
15
+ :upstream_servers => [[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]],
16
+ :host_ip_address => nil,
17
+ :guest_redirect_dns => true,
18
+ :host_interface => nil,
19
+ :host_interface_excludes => [/lo[0-9]*/, /docker[0-9]+/, /tun[0-9]+/]
16
20
  }.freeze
17
21
 
18
22
  def initialize
19
- @hosts = {}
20
- @enabled = UNSET_VALUE
21
- @tld = UNSET_VALUE
22
- @upstream_servers = UNSET_VALUE
23
- @host_ip_address = UNSET_VALUE
24
- @guest_redirect_dns = UNSET_VALUE
23
+ @hosts = {}
24
+ @enabled = UNSET_VALUE
25
+ @tld = UNSET_VALUE
26
+ @upstream_servers = UNSET_VALUE
27
+ @host_ip_address = UNSET_VALUE
28
+ @guest_redirect_dns = UNSET_VALUE
29
+ @host_interface = UNSET_VALUE
30
+ @host_interface_excludes = UNSET_VALUE
25
31
  end
26
32
 
27
33
  def enable
@@ -98,8 +98,8 @@ module Landrush
98
98
  end
99
99
 
100
100
  guest_capability('linux', 'read_host_visible_ip_address') do
101
- require_relative 'cap/linux/read_host_visible_ip_address'
102
- Cap::Linux::ReadHostVisibleIpAddress
101
+ require_relative 'cap/all/read_host_visible_ip_address'
102
+ Cap::All::ReadHostVisibleIpAddress
103
103
  end
104
104
  end
105
105
  end
@@ -29,10 +29,6 @@ module Landrush
29
29
  EOS
30
30
  end
31
31
 
32
- def osx?
33
- `uname`.chomp == 'Darwin'
34
- end
35
-
36
32
  def config_dir
37
33
  self.class.config_dir
38
34
  end
@@ -46,7 +42,7 @@ module Landrush
46
42
  end
47
43
 
48
44
  def write_config!
49
- info "Momentarily using sudo to put the host config in place..."
45
+ info 'Momentarily using sudo to put the host config in place...'
50
46
  system "#{self.class.sudo} mkdir #{config_dir}" unless config_dir.directory?
51
47
  Tempfile.open('vagrant_landrush_host_config') do |f|
52
48
  f.write(desired_contents)
@@ -58,9 +54,9 @@ module Landrush
58
54
 
59
55
  def ensure_config_exists!
60
56
  if contents_match?
61
- info "Host DNS resolver config looks good."
57
+ info 'Host DNS resolver config looks good.'
62
58
  else
63
- info "Need to configure the host."
59
+ info 'Need to configure the host.'
64
60
  write_config!
65
61
  end
66
62
  end
@@ -1,12 +1,11 @@
1
1
  require 'rubydns'
2
2
  require 'ipaddr'
3
+ require 'vagrant/util/platform'
4
+
3
5
  require_relative 'store'
4
- require_relative 'os'
5
6
 
6
7
  module Landrush
7
8
  class Server
8
- include Landrush::OS
9
-
10
9
  Name = Resolv::DNS::Name
11
10
  IN = Resolv::DNS::Resource::IN
12
11
 
@@ -31,12 +30,12 @@ module Landrush
31
30
  File.join(working_dir, 'log')
32
31
  end
33
32
 
34
- def self.log_file
33
+ def self.log_file_path
35
34
  File.join(log_directory, 'landrush.log')
36
35
  end
37
36
 
38
37
  def self.port
39
- if OS.windows?
38
+ if Vagrant::Util::Platform.windows?
40
39
  # On Windows we need to use the default DNS port, since there seems to be no way to configure it otherwise
41
40
  @port ||= 53
42
41
  else
@@ -66,14 +65,19 @@ module Landrush
66
65
 
67
66
  # Used to start the Landrush DNS server as a child process using ChildProcess gem
68
67
  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)
68
+ if Vagrant::Util::Platform.windows?
69
+ # Need to handle Windows differently. Kernel.spawn fails to work, if the shell creating the process is closed.
70
+ # See https://github.com/vagrant-landrush/landrush/issues/199
71
+ info = Process.create(:command_line => "ruby #{__FILE__} #{port} #{working_dir}",
72
+ :creation_flags => Process::DETACHED_PROCESS,
73
+ :process_inherit => false,
74
+ :thread_inherit => true,
75
+ :cwd => working_dir.to_path)
76
+ pid = info.process_id
73
77
  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)
78
+ pid = spawn('ruby', __FILE__, port.to_s, working_dir.to_s, :chdir => working_dir.to_path, :pgroup => true)
79
+ Process.detach pid
75
80
  end
76
- Process.detach pid
77
81
 
78
82
  write_pid(pid)
79
83
  end
@@ -119,7 +123,16 @@ module Landrush
119
123
  def self.running?
120
124
  pid = read_pid
121
125
  return false if pid.nil?
122
- !!Process.kill(0, pid) rescue false
126
+ if Vagrant::Util::Platform.windows?
127
+ begin
128
+ Process.get_exitcode(pid).nil?
129
+ # Need to handle this explicitly since this error gets thrown in case we call get_exitcode with a stale pid
130
+ rescue SystemCallError => e
131
+ raise e unless e.class.name.start_with?('Errno::ENXIO')
132
+ end
133
+ else
134
+ !!Process.kill(0, pid) rescue false
135
+ end
123
136
  end
124
137
 
125
138
  def self.status
@@ -131,7 +144,7 @@ module Landrush
131
144
  else
132
145
  puts 'Daemon status: unknown'
133
146
  puts "#{pid_file} exists, but process is not running"
134
- puts "Check log file: #{log_file}"
147
+ puts "Check log file: #{log_file_path}"
135
148
  end
136
149
  end
137
150
 
@@ -140,10 +153,14 @@ module Landrush
140
153
  server.port = port
141
154
  server.working_dir = working_dir
142
155
 
143
- # Start the DNS server
144
- RubyDNS.run_server(:listen => interfaces) do
145
- @logger.level = Logger::INFO
156
+ ensure_path_exits(log_file_path)
157
+ log_file = File.open(log_file_path, 'w')
158
+ log_file.sync = true
159
+ @logger = Logger.new(log_file)
160
+ @logger.level = Logger::INFO
146
161
 
162
+ # Start the DNS server
163
+ run_dns_server(:listen => interfaces, :logger => @logger) do
147
164
  match(/.*/, IN::A) do |transaction|
148
165
  host = Store.hosts.find(transaction.name)
149
166
  if host
@@ -170,6 +187,20 @@ module Landrush
170
187
  end
171
188
  end
172
189
 
190
+ def self.run_dns_server(options = {}, &block)
191
+ server = RubyDNS::RuleBasedServer.new(options, &block)
192
+
193
+ EventMachine.run do
194
+ trap("INT") do
195
+ EventMachine.stop
196
+ end
197
+
198
+ server.run(options)
199
+ end
200
+
201
+ server.fire(:stop)
202
+ end
203
+
173
204
  def self.check_a_record(host, transaction)
174
205
  value = Store.hosts.get(host)
175
206
  if value.nil?
@@ -221,16 +252,11 @@ module Landrush
221
252
  end
222
253
 
223
254
  def self.terminate_process(pid)
224
- Process.kill("INT", pid)
225
- sleep 0.1
226
-
227
- sleep 1 if running?
228
-
229
255
  # Kill/Term loop - if the daemon didn't die easily, shoot
230
256
  # it a few more times.
231
257
  attempts = 5
232
258
  while running? && attempts > 0
233
- sig = (attempts >= 2) ? "KILL" : "TERM"
259
+ sig = (attempts >= 2) ? 'KILL' : 'TERM'
234
260
 
235
261
  puts "Sending #{sig} to process #{pid}..."
236
262
  Process.kill(sig, pid)
@@ -0,0 +1,16 @@
1
+ module Landrush
2
+ module Util
3
+ module Retry
4
+ def retry(opts=nil)
5
+ opts = {tries: 1}.merge(opts || {})
6
+ n = 0
7
+ while n < opts[:tries]
8
+ return true if yield
9
+ sleep opts[:sleep].to_f if opts[:sleep]
10
+ n += 1
11
+ end
12
+ false
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module Landrush
2
- VERSION = '1.0.0'.freeze
2
+ VERSION = '1.1.0.beta.1'.freeze
3
3
  end
@@ -0,0 +1,185 @@
1
+ # This file needs to be able to execute out of the Vagrant context. Do not require any non core or non relative files
2
+ require 'ipaddr'
3
+ require_relative 'util/retry'
4
+
5
+ # This class configures the network interface on Windows for use with the Landrush DNS server.
6
+ # It makes use of the netsh executable which is assumed to be available on the Windows host.
7
+ module Landrush
8
+ class WinNetworkConfig
9
+ include Landrush::Util::Retry
10
+
11
+ # Windows registry path under which network interface configuration is stored
12
+ INTERFACES = 'SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces'.freeze
13
+
14
+ def initialize(env={})
15
+ @env = env
16
+ end
17
+
18
+ # Checks that all required tools are on the PATH and that the Wired AutoConfig service is started
19
+ def ensure_prerequisites
20
+ return false unless command_found('netsh')
21
+ return false unless command_found('net')
22
+ return false unless command_found('reg')
23
+
24
+ unless wired_autoconfig_service_running?
25
+ info('starting \'Wired AutoConfig\' service')
26
+ if self.class.admin_mode?
27
+ `net start dot3svc`
28
+ else
29
+ require 'win32ole'
30
+ shell = WIN32OLE.new('Shell.Application')
31
+ shell.ShellExecute('net', 'start dot3svc', nil, 'runas', 1)
32
+ end
33
+ service_has_started = self.retry(tries: 5, sleep: 1) do
34
+ wired_autoconfig_service_running?
35
+ end
36
+ unless service_has_started
37
+ info('Unable to start \'Wired AutoConfig\' service. Unable to configure DNS on host. Try manual configuration.')
38
+ return false
39
+ end
40
+ info('\'Wired AutoConfig\' service has started.')
41
+ end
42
+ true
43
+ end
44
+
45
+ # Does the actual update of the network configuration
46
+ def update_network_adapter(ip, name_server, domain)
47
+ # Need to defer loading to ensure cross OS compatibility
48
+ require 'win32/registry'
49
+ ensure_admin_privileges(__FILE__.to_s, ip, name_server, domain)
50
+
51
+ network_name = get_network_name(ip)
52
+ if network_name.nil?
53
+ info("unable to determine network interface for #{ip}. DNS on host cannot be configured. Try manual configuration.")
54
+ return
55
+ else
56
+ info("adding Landrush'es DNS server to network '#{network_name}' using DNS IP '#{ip}'' and search domain '#{domain}'")
57
+ end
58
+ network_guid = get_guid(network_name)
59
+ if network_guid.nil?
60
+ info("unable to determine network GUID for #{ip}. DNS on host cannot be configured. Try manual configuration.")
61
+ return
62
+ end
63
+ interface_path = INTERFACES + "\\{#{network_guid}}"
64
+ Win32::Registry::HKEY_LOCAL_MACHINE.open(interface_path, Win32::Registry::KEY_ALL_ACCESS) do |reg|
65
+ reg['NameServer'] = name_server
66
+ reg['Domain'] = domain
67
+ end
68
+ end
69
+
70
+ # If this registry query succeeds we assume we have Admin rights
71
+ # http://stackoverflow.com/questions/8268154/run-ruby-script-in-elevated-mode/27954953
72
+ def self.admin_mode?
73
+ (`reg query HKU\\S-1-5-19 2>&1` =~ /ERROR/).nil?
74
+ end
75
+
76
+ private
77
+
78
+ # Given a network name (as displayed on 'Control Panel\Network and Internet\Network Connections'),
79
+ # determines the GUID of this network interface using 'netsh'.
80
+ #
81
+ # To make this work the "Wired Autoconfig" service must be started (go figure).
82
+ #
83
+ # Output of netsh command which is being processed:
84
+ #
85
+ # There are 4 interfaces on the system:
86
+ #
87
+ # Name : Ethernet
88
+ # Description : Intel(R) Ethernet Connection (3) I218-LM
89
+ # GUID : fd9270f6-aff6-4f24-bc4a-1f90c032d5c3
90
+ # Physical Address : 50-7B-9D-AB-25-1D
91
+ # \n\n
92
+ # ...
93
+ def get_guid(network_name)
94
+ cmd_out = `netsh lan show interfaces`
95
+ interface_details = cmd_out.split(/\n\n/).select { |settings| settings.match(/#{Regexp.quote(network_name)}/m) }
96
+ return nil if interface_details.empty?
97
+ interface_details[0].split(/\n/)[2].match(/.*:(.*)/).captures[0].strip
98
+ end
99
+
100
+ # Given an IP determines the network name, if any. Uses netsh which generates output like this:
101
+ #
102
+ # ...
103
+ # \n\n
104
+ # Configuration for interface "Ethernet 2"
105
+ # DHCP enabled: Yes
106
+ # IP Address: 10.10.10.1
107
+ # Subnet Prefix: 10.10.10.0/24 (mask 255.255.255.0)
108
+ # InterfaceMetric: 10
109
+ # DNS servers configured through DHCP: None
110
+ # Register with which suffix: Primary only
111
+ # WINS servers configured through DHCP: None
112
+ # \n\n
113
+ # ...
114
+ def get_network_name(ip)
115
+ cmd_out = `netsh interface ip show config`
116
+ network_details = cmd_out.split(/\n\n/).select do |settings|
117
+ begin
118
+ lines = settings.split(/\n/).reject(&:empty?)
119
+ subnet = lines[3]
120
+ next false unless subnet =~ /Subnet Prefix/
121
+
122
+ mask = IPAddr.new(subnet.match(%r{.* (\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}/\d{1,3}).*}).captures[0])
123
+ address = IPAddr.new(ip)
124
+
125
+ mask.include?(address)
126
+ rescue
127
+ false
128
+ end
129
+ end
130
+ return nil if network_details[0].nil?
131
+ network_details[0].split(/\n/)[0].match(/Configuration for interface "(.*)"/).captures[0].strip
132
+ end
133
+
134
+ # Makes sure that we have admin privileges and if nor starts a new shell with the required
135
+ # privileges
136
+ def ensure_admin_privileges(file, *args)
137
+ unless self.class.admin_mode?
138
+ require 'win32ole'
139
+ shell = WIN32OLE.new('Shell.Application')
140
+ shell.ShellExecute('ruby', "#{file} #{args.join(' ')}", nil, 'runas', 1)
141
+ # need to exit current execution, changes will occur in new environment
142
+ exit
143
+ end
144
+ end
145
+
146
+ def info(msg)
147
+ @env[:ui].info("[landrush] #{msg}") unless @env.nil?
148
+ end
149
+
150
+ def wired_autoconfig_service_running?
151
+ cmd_out = `net start`
152
+ cmd_out =~ /Wired AutoConfig/m
153
+ end
154
+
155
+ def command_found(cmd)
156
+ if which(cmd).nil?
157
+ info("Cannot find '#{cmd}' on the PATH. Unable to configure DNS. Try manual configuration.")
158
+ false
159
+ else
160
+ true
161
+ end
162
+ end
163
+
164
+ # Cross-platform way of finding an executable in the $PATH.
165
+ #
166
+ # which('ruby') #=> /usr/bin/ruby
167
+ def which(cmd)
168
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
169
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
170
+ exts.each do |ext|
171
+ exe = File.join(path, "#{cmd}#{ext}")
172
+ return exe if File.executable?(exe) && !File.directory?(exe)
173
+ end
174
+ end
175
+ nil
176
+ end
177
+ end
178
+ end
179
+
180
+ # Only run the following code when this file is the main file being run
181
+ # instead of having been required or loaded by another file
182
+ if __FILE__ == $0
183
+ config = Landrush::WinNetworkConfig.new nil
184
+ config.update_network_adapter(ARGV[0], ARGV[1], ARGV[2])
185
+ end
data/lib/landrush.rb CHANGED
@@ -4,12 +4,17 @@ rescue LoadError
4
4
  raise 'The Vagrant landrush plugin must be run within Vagrant.'
5
5
  end
6
6
 
7
+ # Only load the gem on Windows since it replaces some methods in Ruby's Process class
8
+ # Also load before Process.uid is called the first time by Vagrant
9
+ require 'win32/process' if Vagrant::Util::Platform.windows?
10
+
7
11
  require 'rubydns'
8
- require 'ipaddr'
9
12
 
10
13
  require 'landrush/dependent_vms'
11
14
  require 'landrush/plugin'
12
15
  require 'landrush/resolver_config'
16
+ require 'landrush/win_network_config'
13
17
  require 'landrush/server'
14
18
  require 'landrush/store'
15
19
  require 'landrush/version'
20
+ require 'landrush-ip'