landrush 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +12 -178
  3. data/.travis.yml +6 -1
  4. data/CHANGELOG.md +18 -1
  5. data/CONTRIBUTING.adoc +112 -0
  6. data/Gemfile +6 -9
  7. data/Guardfile +10 -0
  8. data/README.adoc +100 -0
  9. data/Rakefile +14 -2
  10. data/appveyor.yml +20 -0
  11. data/doc/Development.adoc +112 -0
  12. data/doc/ProxyMobile.adoc +66 -0
  13. data/doc/Troubleshooting.adoc +42 -0
  14. data/doc/Usage.adoc +271 -0
  15. data/features/commands.feature +35 -0
  16. data/features/dns_resolution.feature +6 -5
  17. data/features/{landrush-ip.feature → landrush_ip.feature} +0 -0
  18. data/features/step_definitions/landrush_custom_steps.rb +48 -0
  19. data/features/support/env.rb +25 -1
  20. data/landrush.gemspec +3 -3
  21. data/lib/landrush/action/common.rb +3 -11
  22. data/lib/landrush/action/install_prerequisites.rb +2 -3
  23. data/lib/landrush/action/redirect_dns.rb +1 -1
  24. data/lib/landrush/action/setup.rb +25 -30
  25. data/lib/landrush/action/teardown.rb +8 -11
  26. data/lib/landrush/cap/guest/all/read_host_visible_ip_address.rb +28 -4
  27. data/lib/landrush/cap/guest/linux/add_iptables_rule.rb +1 -1
  28. data/lib/landrush/cap/guest/linux/redirect_dns.rb +2 -2
  29. data/lib/landrush/cap/guest/suse/add_iptables_rule.rb +20 -0
  30. data/lib/landrush/cap/guest/suse/install_iptables.rb +14 -0
  31. data/lib/landrush/cap/guest/suse/iptables_installed.rb +11 -0
  32. data/lib/landrush/cap/host/suse/dnsmasq_installed.rb +11 -0
  33. data/lib/landrush/cap/host/suse/install_dnsmasq.rb +14 -0
  34. data/lib/landrush/cap/host/suse/restart_dnsmasq.rb +21 -0
  35. data/lib/landrush/cap/host/windows/configure_visibility_on_host.rb +1 -1
  36. data/lib/landrush/command.rb +42 -17
  37. data/lib/landrush/config.rb +29 -14
  38. data/lib/landrush/plugin.rb +30 -0
  39. data/lib/landrush/server.rb +96 -138
  40. data/lib/landrush/start_server.rb +11 -0
  41. data/lib/landrush/store.rb +6 -2
  42. data/lib/landrush/util/path.rb +32 -0
  43. data/lib/landrush/util/process_helper.rb +46 -0
  44. data/lib/landrush/util/retry.rb +2 -2
  45. data/lib/landrush/version.rb +1 -1
  46. data/test/landrush/action/setup_test.rb +19 -25
  47. data/test/landrush/action/teardown_test.rb +18 -15
  48. data/test/landrush/cap/guest/all/read_host_visible_ip_address_test.rb +35 -1
  49. data/test/landrush/cap/guest/linux/configured_dns_servers_test.rb +8 -8
  50. data/test/landrush/cap/guest/linux/redirect_dns_test.rb +4 -4
  51. data/test/landrush/config_test.rb +23 -2
  52. data/test/landrush/dependent_vms_test.rb +5 -5
  53. data/test/landrush/issues/255.rb +115 -0
  54. data/test/landrush/server_test.rb +22 -4
  55. data/test/landrush/store_test.rb +28 -13
  56. data/test/support/test_server_daemon.rb +2 -4
  57. data/test/test_helper.rb +37 -14
  58. metadata +30 -15
  59. data/CONTRIBUTING.md +0 -103
  60. data/NOTES.md +0 -28
  61. data/README.md +0 -406
  62. data/doc/proxy-mobile/README.md +0 -50
  63. data/features/step_definitions/dns.rb +0 -19
  64. data/features/step_definitions/ip.rb +0 -13
@@ -1,7 +1,7 @@
1
1
  require_relative '../test_helper'
2
2
 
3
3
  describe 'Landrush::Config' do
4
- it "supports enabling via accessor style" do
4
+ it 'supports enabling via accessor style' do
5
5
  machine = fake_machine
6
6
  config = machine.config.landrush
7
7
 
@@ -11,7 +11,7 @@ describe 'Landrush::Config' do
11
11
  config.enabled?.must_equal false
12
12
  end
13
13
 
14
- it "is backwards-compatible with the old method call style" do
14
+ it 'is backwards-compatible with the old method call style' do
15
15
  machine = fake_machine
16
16
  config = machine.config.landrush
17
17
 
@@ -20,4 +20,25 @@ describe 'Landrush::Config' do
20
20
  machine.config.landrush.disable
21
21
  config.enabled?.must_equal false
22
22
  end
23
+
24
+ it 'should validate host_interface_class' do
25
+ machine = fake_machine
26
+ config = machine.config.landrush
27
+
28
+ validation_success = []
29
+ validation_error = [Landrush::Config::INTERFACE_CLASS_INVALID, { fields: 'host_interface_class' }]
30
+
31
+ Landrush::Config::INTERFACE_CLASSES.each do |sym|
32
+ machine.config.landrush.host_interface_class = sym
33
+ config.validate(machine).must_equal('landrush' => validation_success)
34
+
35
+ machine.config.landrush.host_interface_class = sym.to_s
36
+ config.validate(machine).must_equal('landrush' => validation_success)
37
+ end
38
+
39
+ [:invalid_symbol, 'invalid_string', 4].each do |v|
40
+ machine.config.landrush.host_interface_class = v
41
+ config.validate(machine).must_equal('landrush' => validation_error)
42
+ end
43
+ end
23
44
  end
@@ -2,23 +2,23 @@ require_relative '../test_helper'
2
2
 
3
3
  module Landrush
4
4
  describe DependentVMs do
5
- describe "any?" do
6
- it "reports false when nothing has happened" do
5
+ describe 'any?' do
6
+ it 'reports false when nothing has happened' do
7
7
  DependentVMs.any?.must_equal false
8
8
  end
9
9
 
10
- it "reports true once a machine has been added" do
10
+ it 'reports true once a machine has been added' do
11
11
  DependentVMs.add('recordme.example.test')
12
12
  DependentVMs.any?.must_equal true
13
13
  end
14
14
 
15
- it "reports false if a machine has been added then removed" do
15
+ it 'reports false if a machine has been added then removed' do
16
16
  DependentVMs.add('recordme.example.test')
17
17
  DependentVMs.remove('recordme.example.test')
18
18
  DependentVMs.any?.must_equal false
19
19
  end
20
20
 
21
- it "reports true if not all machines have been removed" do
21
+ it 'reports true if not all machines have been removed' do
22
22
  DependentVMs.add('recordme.example.test')
23
23
  DependentVMs.add('alsome.example.test')
24
24
  DependentVMs.remove('recordme.example.test')
@@ -0,0 +1,115 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Landrush
4
+ module Cap
5
+ module All
6
+ describe ReadHostVisibleIpAddress do
7
+ let(:landrush_ip_output) do
8
+ <<YAML
9
+ - name: br-44ba74744d5d
10
+ ipv4: 172.17.0.1
11
+ ipv6: fe80::42:e1ff:fe01:ae98
12
+ - name: br-7884014b4104
13
+ ipv4: 172.19.0.1
14
+ ipv6: fe80::42:c0ff:fe4b:900c
15
+ - name: br-efce9da0c1fd
16
+ ipv4: 172.18.0.1
17
+ ipv6: fe80::42:2ff:fe46:f1d1
18
+ - name: docker0
19
+ ipv4: 172.16.0.1
20
+ ipv6: fe80::42:dbff:fe1b:6e92
21
+ - name: docker_gwbridge
22
+ ipv4: 172.20.0.1
23
+ ipv6: fe80::42:72ff:fe96:c6df
24
+ - name: enp4s0
25
+ ipv4: 192.168.88.97
26
+ ipv6: fe80::323d:9fa0:ef2a:ddf5
27
+ - name: wlp3s0
28
+ ipv4: 192.168.88.118
29
+ ipv6: fe80::6b80:15d4:e83c:a59d
30
+ - name: lo
31
+ ipv4: 127.0.0.1
32
+ ipv6: ::1/128
33
+ - name: veth050aa01
34
+ ipv4: ""
35
+ ipv6: fe80::c83a:8eff:fe7a:3244
36
+ - name: veth1c191f7
37
+ ipv4: ""
38
+ ipv6: fe80::b498:f3ff:fea1:3243
39
+ - name: veth38aa771
40
+ ipv4: ""
41
+ ipv6: fe80::8c97:e2ff:fe1a:b14f
42
+ - name: veth5f49498
43
+ ipv4: ""
44
+ ipv6: fe80::6825:20ff:fef5:a00d
45
+ - name: veth7803c65
46
+ ipv4: ""
47
+ ipv6: fe80::34d7:6cff:fe28:54ce
48
+ - name: veth8a09803
49
+ ipv4: ""
50
+ ipv6: fe80::b436:30ff:fed1:598e
51
+ - name: veth8bf1652
52
+ ipv4: ""
53
+ ipv6: fe80::60a8:67ff:fe85:cce4
54
+ - name: veth95ef8de
55
+ ipv4: ""
56
+ ipv6: fe80::9c45:e8ff:fe69:e62f
57
+ - name: vethc75f284
58
+ ipv4: ""
59
+ ipv6: fe80::78b2:7fff:fe55:59
60
+ - name: vethe533ef0
61
+ ipv4: ""
62
+ ipv6: fe80::b83e:93ff:fe52:aac7
63
+ YAML
64
+ end
65
+
66
+ let(:machine) { fake_machine }
67
+ let(:addresses) { YAML.load(landrush_ip_output) }
68
+
69
+ def call_cap(machine)
70
+ Landrush::Cap::All::ReadHostVisibleIpAddress.read_host_visible_ip_address(machine)
71
+ end
72
+
73
+ before do
74
+ # TODO: Is there a way to only unstub it for read_host_visible_ip_address?
75
+ machine.guest.unstub(:capability)
76
+ machine.guest.stubs(:capability).with(:landrush_ip_installed).returns(true)
77
+ machine.guest.stubs(:capability).with(:landrush_ip_get).returns(addresses)
78
+
79
+ machine.config.landrush.host_interface = nil
80
+ machine.config.landrush.host_interface_excludes = [/lo[0-9]*/, /docker[0-9]+/, /tun[0-9]+/, /br-(.+)/]
81
+ end
82
+
83
+ describe 'Issue 255: read_host_visible_ip_address failure in presence of interface without IPv4, with IPv6 address' do
84
+ # Test IPv4
85
+ it 'should return the last non-empty IPv4 address' do
86
+ expected = addresses.detect { |a| a['name'] == 'wlp3s0' }
87
+ expected = expected['ipv4']
88
+
89
+ call_cap(machine).must_equal expected
90
+ end
91
+
92
+ # Test IPv6 selection
93
+ it 'should return the last non-empty IPv6 address' do
94
+ machine.config.landrush.host_interface_class = :ipv6
95
+
96
+ expected = addresses.detect { |a| a['name'] == 'vethe533ef0' }
97
+ expected = expected['ipv6']
98
+
99
+ call_cap(machine).must_equal expected
100
+ end
101
+
102
+ # Test ANY selection
103
+ it 'should return the last non-empty address of either class' do
104
+ machine.config.landrush.host_interface_class = :any
105
+
106
+ expected = addresses.detect { |a| a['name'] == 'vethe533ef0' }
107
+ expected = expected['ipv6']
108
+
109
+ call_cap(machine).must_equal expected
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -1,16 +1,34 @@
1
- require_relative '../test_helper'
2
1
  require 'resolv'
2
+ require 'tmpdir'
3
+ require 'fileutils'
4
+
5
+ require_relative '../test_helper'
3
6
 
4
7
  module Landrush
5
8
  describe Server do
6
9
  def query(host)
7
- Resolv::DNS.open(:nameserver_port => [["127.0.0.1", Server.port]]) do |r|
10
+ Resolv::DNS.open(nameserver_port: [['127.0.0.1', Server.port]]) do |r|
8
11
  r.getaddress(host).to_s
9
12
  end
10
13
  end
11
14
 
12
15
  def wait_for_port
13
- sleep 1 until (TCPSocket.open('127.0.0.1', Server.port) rescue nil)
16
+ sleep 1 until begin
17
+ TCPSocket.open('127.0.0.1', Server.port)
18
+ rescue
19
+ nil
20
+ end
21
+ end
22
+
23
+ before do
24
+ @tmp_dir = Dir.mktmpdir('landrush-server-test-')
25
+ Server.working_dir = @tmp_dir
26
+ Server.gems_dir = gem_dir
27
+ end
28
+
29
+ after do
30
+ Server.stop
31
+ FileUtils.rm_rf(@tmp_dir) if File.exist?(@tmp_dir)
14
32
  end
15
33
 
16
34
  describe 'start/stop' do
@@ -32,7 +50,7 @@ module Landrush
32
50
 
33
51
  wait_for_port
34
52
 
35
- query("phinze.com").must_match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
53
+ query('phinze.com').must_match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
36
54
  end
37
55
 
38
56
  it 'responds properly to configured machine entries' do
@@ -3,7 +3,7 @@ require_relative '../test_helper'
3
3
  module Landrush
4
4
  describe Store do
5
5
  before do
6
- @temp_file = Tempfile.new(%w[landrush_test_store .json])
6
+ @temp_file = Tempfile.new(%w(landrush_test_store .json))
7
7
  @store = Store.new(@temp_file)
8
8
  end
9
9
 
@@ -11,14 +11,14 @@ module Landrush
11
11
  @temp_file.unlink
12
12
  end
13
13
 
14
- describe "set" do
15
- it "sets the key to the value and makes it available for getting" do
14
+ describe 'set' do
15
+ it 'sets the key to the value and makes it available for getting' do
16
16
  @store.set('foo', 'bar')
17
17
 
18
18
  @store.get('foo').must_equal 'bar'
19
19
  end
20
20
 
21
- it "allows updating keys that already exist" do
21
+ it 'allows updating keys that already exist' do
22
22
  @store.set('foo', 'bar')
23
23
  @store.set('foo', 'qux')
24
24
 
@@ -26,12 +26,12 @@ module Landrush
26
26
  end
27
27
  end
28
28
 
29
- describe "get" do
30
- it "returns nil for unset values" do
29
+ describe 'get' do
30
+ it 'returns nil for unset values' do
31
31
  @store.get('notakey').must_equal nil
32
32
  end
33
33
 
34
- it "returns the latest set value (no caching)" do
34
+ it 'returns the latest set value (no caching)' do
35
35
  @store.set('foo', 'first')
36
36
  @store.get('foo').must_equal 'first'
37
37
  @store.set('foo', 'second')
@@ -41,8 +41,8 @@ module Landrush
41
41
  end
42
42
  end
43
43
 
44
- describe "delete" do
45
- it "removes the key from the store" do
44
+ describe 'delete' do
45
+ it 'removes the key from the store' do
46
46
  @store.set('now', 'you see me')
47
47
 
48
48
  @store.get('now').must_equal 'you see me'
@@ -53,8 +53,8 @@ module Landrush
53
53
  end
54
54
  end
55
55
 
56
- describe "find" do
57
- it "returns the key that matches the end of the search term" do
56
+ describe 'find' do
57
+ it 'returns the key that matches the end of the search term' do
58
58
  @store.set('somehost.vagrant.test', 'here')
59
59
 
60
60
  @store.find('foo.somehost.vagrant.test').must_equal 'somehost.vagrant.test'
@@ -63,12 +63,12 @@ module Landrush
63
63
  @store.find('host.vagrant.test').must_equal nil
64
64
  end
65
65
 
66
- it "returns exact matches too" do
66
+ it 'returns exact matches too' do
67
67
  @store.set('somehost.vagrant.test', 'here')
68
68
  @store.find('somehost.vagrant.test').must_equal 'somehost.vagrant.test'
69
69
  end
70
70
 
71
- it "returns for prefix searches as well" do
71
+ it 'returns for prefix searches as well' do
72
72
  @store.set('somehost.vagrant.test', 'here')
73
73
 
74
74
  @store.find('somehost').must_equal 'somehost.vagrant.test'
@@ -77,5 +77,20 @@ module Landrush
77
77
  @store.find('someh').must_equal nil
78
78
  end
79
79
  end
80
+
81
+ describe 'clear' do
82
+ it 'clears all keys from the store' do
83
+ @store.set('foo', 'bar')
84
+ @store.set('foo', 'qux')
85
+
86
+ @store.clear!
87
+
88
+ count = 0
89
+ @store.each do
90
+ count += 1
91
+ end
92
+ count.must_equal 0
93
+ end
94
+ end
80
95
  end
81
96
  end
@@ -16,7 +16,7 @@ module SilenceOutput
16
16
  def self.included(base)
17
17
  orig_stop_method = base.method(:stop)
18
18
  base.define_singleton_method :stop do
19
- SilenceOutput.silence {orig_stop_method.call}
19
+ SilenceOutput.silence { orig_stop_method.call }
20
20
  end
21
21
  end
22
22
  end
@@ -31,9 +31,7 @@ module TestServerHooks
31
31
  def teardown
32
32
  super
33
33
  # Cleanup any stray server instances from tests
34
- if Landrush::Server.running?
35
- Landrush::Server.stop
36
- end
34
+ Landrush::Server.stop if Landrush::Server.running?
37
35
  Landrush::Store.reset
38
36
  end
39
37
  end
@@ -1,4 +1,4 @@
1
- $:.push(File.expand_path('../../lib', __FILE__))
1
+ $LOAD_PATH.push(File.expand_path('../../lib', __FILE__))
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'minitest/spec'
@@ -19,32 +19,53 @@ require 'mocha/mini_test'
19
19
  # Putting include/exclude out of order is kind of the point though ;)
20
20
  def fake_addresses
21
21
  [
22
- {'name' => 'exclude1', 'ipv4' => '172.28.128.1', 'ipv6' => '::1'},
23
- {'name' => 'include1', 'ipv4' => '172.28.128.2', 'ipv6' => '::2'},
24
- {'name' => 'include2', 'ipv4' => '172.28.128.3', 'ipv6' => '::3'},
25
- {'name' => 'include3', 'ipv4' => '172.28.128.4', 'ipv6' => '::4'},
26
- {'name' => 'exclude2', 'ipv4' => '172.28.128.5', 'ipv6' => '::5'},
27
- {'name' => 'exclude3', 'ipv4' => '172.28.128.6', 'ipv6' => '::6'}
22
+ { 'name' => 'ipv6empty1', 'ipv4' => '172.28.128.10', 'ipv6' => '' },
23
+ { 'name' => 'ipv4empty1', 'ipv4' => '', 'ipv6' => '::10' },
24
+ { 'name' => 'ipv6empty2', 'ipv4' => '172.28.128.11', 'ipv6' => '' },
25
+ { 'name' => 'ipv4empty2', 'ipv4' => '', 'ipv6' => '::11' },
26
+ { 'name' => 'exclude1', 'ipv4' => '172.28.128.1', 'ipv6' => '::1' },
27
+ { 'name' => 'include1', 'ipv4' => '172.28.128.2', 'ipv6' => '::2' },
28
+ { 'name' => 'include2', 'ipv4' => '172.28.128.3', 'ipv6' => '::3' },
29
+ { 'name' => 'include3', 'ipv4' => '172.28.128.4', 'ipv6' => '::4' },
30
+ { 'name' => 'exclude2', 'ipv4' => '172.28.128.5', 'ipv6' => '::5' },
31
+ { 'name' => 'exclude3', 'ipv4' => '172.28.128.6', 'ipv6' => '::6' }
28
32
  ]
29
33
  end
30
34
 
31
- def fake_environment(options = {enabled: true})
35
+ def fake_environment(options = { enabled: true })
32
36
  # For the home_path we want the base Vagrant directory
33
37
  vagrant_test_home = Pathname(Landrush::Server.working_dir).parent.parent
34
- {machine: fake_machine(options), ui: FakeUI.new, home_path: vagrant_test_home}
38
+ machine = fake_machine(options)
39
+ { machine: machine, ui: FakeUI.new, home_path: vagrant_test_home, gems_path: machine.env.gems_path }
40
+ end
41
+
42
+ # Returns the gem directory for running unit tests
43
+ def gem_dir
44
+ `gem environment gemdir`.strip!
35
45
  end
36
46
 
37
47
  class FakeUI
48
+ attr_reader :received_detail_messages
38
49
  attr_reader :received_info_messages
50
+ attr_reader :received_error_messages
39
51
 
40
52
  def initialize
53
+ @received_detail_messages = []
41
54
  @received_info_messages = []
55
+ @received_error_messages = []
56
+ end
57
+
58
+ def detail(*args)
59
+ @received_detail_messages << args[0]
42
60
  end
43
61
 
44
62
  def info(*args)
45
- # puts "#{args}"
46
63
  @received_info_messages << args[0]
47
64
  end
65
+
66
+ def error(*args)
67
+ @received_error_messages << args[0]
68
+ end
48
69
  end
49
70
 
50
71
  class RecordingCommunicator
@@ -111,8 +132,10 @@ module Landrush
111
132
  end
112
133
  end
113
134
 
114
- def fake_machine(options={})
135
+ def fake_machine(options = {})
136
+ gem_path = Pathname.new(gem_dir)
115
137
  env = options.fetch(:env, Vagrant::Environment.new)
138
+ env.stubs(:gems_path).returns(gem_path)
116
139
  machine = Vagrant::Machine.new(
117
140
  'fake_machine',
118
141
  'fake_provider',
@@ -122,11 +145,11 @@ def fake_machine(options={})
122
145
  env.vagrantfile.config, # config
123
146
  Pathname('data_dir'),
124
147
  'box',
125
- options.fetch(:env, Vagrant::Environment.new),
148
+ env,
126
149
  env.vagrantfile
127
150
  )
128
151
 
129
- machine.instance_variable_set("@communicator", RecordingCommunicator.new)
152
+ machine.instance_variable_set('@communicator', RecordingCommunicator.new)
130
153
 
131
154
  machine.config.landrush.enabled = options.fetch(:enabled, false)
132
155
  machine.config.landrush.host_interface = nil
@@ -145,7 +168,7 @@ end
145
168
 
146
169
  module MiniTest
147
170
  class Spec
148
- alias_method :hush, :capture_io
171
+ alias hush capture_io
149
172
  end
150
173
  end
151
174