docker-provider 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Gemfile +7 -7
  4. data/Gemfile.lock +51 -40
  5. data/LICENSE.txt +1 -1
  6. data/README.md +130 -60
  7. data/Rakefile +6 -1
  8. data/boxes/dind/.gitignore +2 -0
  9. data/boxes/dind/Dockerfile +12 -0
  10. data/boxes/dind/README.md +10 -0
  11. data/boxes/{nginx → dind}/Vagrantfile.sample +2 -1
  12. data/boxes/{nginx → dind}/metadata.json +0 -0
  13. data/boxes/precise/Dockerfile +10 -9
  14. data/boxes/precise/Vagrantfile.sample +0 -1
  15. data/development/Vagrantfile +1 -9
  16. data/docker-provider.gemspec +1 -2
  17. data/example/Vagrantfile +11 -10
  18. data/lib/docker-provider.rb +2 -1
  19. data/lib/docker-provider/action.rb +17 -6
  20. data/lib/docker-provider/action/check_running.rb +1 -1
  21. data/lib/docker-provider/action/create.rb +14 -11
  22. data/lib/docker-provider/action/prepare_nfs_settings.rb +59 -0
  23. data/lib/docker-provider/action/prepare_nfs_valid_ids.rb +19 -0
  24. data/lib/docker-provider/config.rb +14 -7
  25. data/lib/docker-provider/driver.rb +30 -6
  26. data/lib/docker-provider/errors.rb +14 -0
  27. data/lib/docker-provider/plugin.rb +10 -3
  28. data/lib/docker-provider/provider.rb +1 -1
  29. data/lib/docker-provider/synced_folder.rb +20 -0
  30. data/lib/docker-provider/version.rb +1 -1
  31. data/locales/en.yml +13 -2
  32. data/spec/acceptance/provider/basic_spec.rb +94 -0
  33. data/spec/acceptance/provider/network_forwarded_port_spec.rb +29 -0
  34. data/spec/acceptance/provider/synced_folder_spec.rb +39 -0
  35. data/spec/acceptance/provisioner/chef_solo_spec.rb +37 -0
  36. data/spec/acceptance/provisioner/puppet_spec.rb +37 -0
  37. data/spec/acceptance/provisioner/shell_spec.rb +51 -0
  38. data/spec/acceptance/synced_folder/nfs_spec.rb +36 -0
  39. data/spec/unit/driver_spec.rb +70 -11
  40. data/vagrant-spec.config.rb +8 -0
  41. metadata +40 -29
  42. data/boxes/nginx/.gitignore +0 -1
  43. data/boxes/nginx/Dockerfile +0 -4
  44. data/boxes/nginx/README.md +0 -25
  45. data/boxes/nginx/start +0 -5
  46. data/lib/docker-provider/action/share_folders.rb +0 -63
  47. data/spec/acceptance/Vagrantfile +0 -25
  48. data/spec/acceptance/vagrant_ssh.bats +0 -34
  49. data/spec/acceptance/vagrant_up.bats +0 -35
@@ -0,0 +1,14 @@
1
+ require 'vagrant/errors'
2
+
3
+ module VagrantPlugins
4
+ module DockerProvider
5
+ module Errors
6
+ class ImageNotConfiguredError < Vagrant::Errors::VagrantError
7
+ error_key(:docker_provider_image_not_configured)
8
+ end
9
+ class NfsWithoutPrivilegedError < Vagrant::Errors::VagrantError
10
+ error_key(:docker_provider_nfs_without_privileged)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,6 +1,8 @@
1
- require_relative "version"
2
-
3
- require 'vagrant'
1
+ # TODO: Switch to Vagrant.require_version before 1.0.0
2
+ # see: https://github.com/mitchellh/vagrant/blob/bc55081e9ffaa6820113e449a9f76b293a29b27d/lib/vagrant.rb#L202-L228
3
+ unless Gem::Requirement.new('>= 1.4.0').satisfied_by?(Gem::Version.new(Vagrant::VERSION))
4
+ raise 'docker-provider requires Vagrant >= 1.4.0 in order to work!'
5
+ end
4
6
 
5
7
  I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
6
8
  I18n.reload!
@@ -19,6 +21,11 @@ module VagrantPlugins
19
21
  require_relative 'config'
20
22
  Config
21
23
  end
24
+
25
+ synced_folder(:docker) do
26
+ require File.expand_path("../synced_folder", __FILE__)
27
+ SyncedFolder
28
+ end
22
29
  end
23
30
  end
24
31
  end
@@ -25,7 +25,7 @@ module VagrantPlugins
25
25
  # we return nil.
26
26
  return nil if state == :not_created
27
27
 
28
- network = @driver.inspect(@machine.id)['NetworkSettings']
28
+ network = @driver.inspect_container(@machine.id)['NetworkSettings']
29
29
  ip = network['IPAddress']
30
30
 
31
31
  # If we were not able to identify the container's IP, we return nil
@@ -0,0 +1,20 @@
1
+ module VagrantPlugins
2
+ module DockerProvider
3
+ class SyncedFolder < Vagrant.plugin("2", :synced_folder)
4
+ def usable?(machine)
5
+ # These synced folders only work if the provider is Docker
6
+ machine.provider_name == :docker
7
+ end
8
+
9
+ def prepare(machine, folders, _opts)
10
+ # FIXME: Check whether the container has already been created with
11
+ # different synced folders and let the user know about it
12
+ folders.each do |id, data|
13
+ host_path = File.expand_path(data[:hostpath], machine.env.root_path)
14
+ guest_path = data[:guestpath]
15
+ machine.provider_config.volumes << "#{host_path}:#{guest_path}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module DockerProvider
3
- VERSION = "0.0.2"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -17,5 +17,16 @@ en:
17
17
 
18
18
  errors:
19
19
  config:
20
- image_not_set: 'The base Docker image has not been set!'
21
- image_not_set: 'The Docker command has not been set!'
20
+ cmd_not_set: |-
21
+ The Docker command has not been set!
22
+
23
+ vagrant:
24
+ errors:
25
+ docker_provider_nfs_without_privileged: |-
26
+ You've configured a NFS synced folder but didn't enable privileged
27
+ mode for the container. Please set the `privileged` option to true
28
+ on the provider block from your Vagrantfile, recreate the container
29
+ and try again.
30
+
31
+ docker_provider_image_not_configured: |-
32
+ The base Docker image has not been set for the '%{name}' VM!
@@ -0,0 +1,94 @@
1
+ # This tests the basic functionality of a provider: that it can run
2
+ # a machine, provide SSH access, and destroy that machine.
3
+ shared_examples "provider/basic" do |provider, options|
4
+ if !options[:box]
5
+ raise ArgumentError,
6
+ "box option must be specified for provider: #{provider}"
7
+ end
8
+
9
+ include_context "acceptance"
10
+
11
+ before do
12
+ assert_execute("vagrant", "box", "add", "box", options[:box])
13
+ assert_execute("vagrant", "init", "box")
14
+ vagrantfile = environment.workdir.join('Vagrantfile')
15
+ # TODO: Can we just shell out to something?
16
+ new_vagrantfile = "Vagrant.require_plugin('docker-provider')\n#{vagrantfile.read}"
17
+ vagrantfile.open('w') { |f| f.puts(new_vagrantfile) }
18
+ end
19
+
20
+ after do
21
+ # Just always do this just in case
22
+ execute("vagrant", "destroy", "--force", log: false)
23
+ end
24
+
25
+ def assert_running
26
+ result = execute("vagrant", "ssh", "-c", "echo foo")
27
+ expect(result).to exit_with(0)
28
+ expect(result.stdout).to match(/foo\n$/)
29
+ end
30
+
31
+ def assert_not_running
32
+ result = execute("vagrant", "ssh", "-c", "echo foo")
33
+ expect(result).to exit_with(1)
34
+ end
35
+
36
+ =begin
37
+ TODO(mitchellh): These all exit with exit code 0. Unsure if bug.
38
+
39
+ it "can't halt before an up" do
40
+ expect(execute("vagrant", "halt")).to exit_with(1)
41
+ end
42
+
43
+ it "can't resume before an up" do
44
+ expect(execute("vagrant", "resume")).to exit_with(1)
45
+ end
46
+
47
+ it "can't suspend before an up" do
48
+ expect(execute("vagrant", "suspend")).to exit_with(1)
49
+ end
50
+ =end
51
+
52
+ context "after an up" do
53
+ before do
54
+ assert_execute("vagrant", "up", "--provider=#{provider}")
55
+ end
56
+
57
+ after do
58
+ assert_execute("vagrant", "destroy", "--force")
59
+ end
60
+
61
+ it "can manage machine lifecycle" do
62
+ status("Test: machine is running after up")
63
+ assert_running
64
+
65
+ if !options[:features].include?("!suspend")
66
+ status("Test: suspend")
67
+ assert_execute("vagrant", "suspend")
68
+
69
+ status("Test: ssh doesn't work during suspended state")
70
+ assert_not_running
71
+
72
+ status("Test: resume after suspend")
73
+ assert_execute("vagrant", "resume")
74
+ assert_running
75
+ else
76
+ status("Not testing 'suspend', provider doesn't support it")
77
+ end
78
+
79
+ if !options[:features].include?("!halt")
80
+ status("Test: halt")
81
+ assert_execute("vagrant", "halt")
82
+
83
+ status("Test: ssh doesn't work during halted state")
84
+ assert_not_running
85
+
86
+ status("Test: up after halt")
87
+ assert_execute("vagrant", "up")
88
+ assert_running
89
+ else
90
+ status("Not testing 'halt', provider doesn't support it")
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,29 @@
1
+ shared_examples "provider/network/forwarded_port" do |provider, options|
2
+ if !options[:box]
3
+ raise ArgumentError,
4
+ "box option must be specified for provider: #{provider}"
5
+ end
6
+
7
+ include_context "acceptance"
8
+
9
+ before do
10
+ environment.skeleton("network_forwarded_port")
11
+
12
+ vagrantfile = environment.workdir.join('Vagrantfile')
13
+ # TODO: Can we just shell out to something?
14
+ new_vagrantfile = "Vagrant.require_plugin('docker-provider')\n#{vagrantfile.read}"
15
+ vagrantfile.open('w') { |f| f.puts(new_vagrantfile) }
16
+
17
+ assert_execute("vagrant", "box", "add", "box", options[:box])
18
+ assert_execute("vagrant", "up", "--provider=#{provider}")
19
+ end
20
+
21
+ after do
22
+ assert_execute("vagrant", "destroy", "--force")
23
+ end
24
+
25
+ it "properly configures forwarded ports" do
26
+ status("Test: TCP forwarded port (default)")
27
+ assert_network("http://localhost:8080/", 8080)
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ # This tests that synced folders work with a given provider.
2
+ shared_examples "provider/synced_folder" do |provider, options|
3
+ if !options[:box]
4
+ raise ArgumentError,
5
+ "box option must be specified for provider: #{provider}"
6
+ end
7
+
8
+ include_context "acceptance"
9
+
10
+ before do
11
+ environment.skeleton("synced_folders")
12
+
13
+ vagrantfile = environment.workdir.join('Vagrantfile')
14
+ # TODO: Can we just shell out to something?
15
+ new_vagrantfile = "Vagrant.require_plugin('docker-provider')\n#{vagrantfile.read}"
16
+ vagrantfile.open('w') { |f| f.puts(new_vagrantfile) }
17
+
18
+ assert_execute("vagrant", "box", "add", "basic", options[:box])
19
+ assert_execute("vagrant", "up", "--provider=#{provider}")
20
+ end
21
+
22
+ after do
23
+ assert_execute("vagrant", "destroy", "--force")
24
+ end
25
+
26
+ # We put all of this in a single RSpec test so that we can test all
27
+ # the cases within a single VM rather than having to `vagrant up` many
28
+ # times.
29
+ it "properly configures synced folder types" do
30
+ status("Test: mounts the default /vagrant synced folder")
31
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant/foo")
32
+ expect(result.exit_code).to eql(0)
33
+ expect(result.stdout).to match(/hello$/)
34
+
35
+ status("Test: doesn't mount a disabled folder")
36
+ result = execute("vagrant", "ssh", "-c", "test -d /foo")
37
+ expect(result.exit_code).to eql(1)
38
+ end
39
+ end
@@ -0,0 +1,37 @@
1
+ shared_examples "provider/provisioner/chef-solo" do |provider, options|
2
+ box = options[:box_chef] || options[:box]
3
+ if !box
4
+ raise ArgumentError,
5
+ "box_basic option must be specified for provider: #{provider}"
6
+ end
7
+
8
+ include_context "acceptance"
9
+
10
+ before do
11
+ environment.skeleton("provisioner_chef_solo")
12
+
13
+ vagrantfile = environment.workdir.join('Vagrantfile')
14
+ # TODO: Can we just shell out to something?
15
+ new_vagrantfile = "Vagrant.require_plugin('docker-provider')\n#{vagrantfile.read}"
16
+ vagrantfile.open('w') { |f| f.puts(new_vagrantfile) }
17
+
18
+ assert_execute("vagrant", "box", "add", "box", box)
19
+ assert_execute("vagrant", "up", "--provider=#{provider}")
20
+ end
21
+
22
+ after do
23
+ assert_execute("vagrant", "destroy", "--force")
24
+ end
25
+
26
+ it "provisions with chef-solo" do
27
+ status("Test: basic cookbooks and recipes")
28
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant-chef-basic")
29
+ expect(result).to exit_with(0)
30
+ expect(result.stdout).to match(/basic$/)
31
+
32
+ status("Test: works with roles")
33
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant-chef-basic-roles")
34
+ expect(result).to exit_with(0)
35
+ expect(result.stdout).to match(/basic-roles$/)
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ shared_examples "provider/provisioner/puppet" do |provider, options|
2
+ box = options[:box_puppet] || options[:box]
3
+ if !box
4
+ raise ArgumentError,
5
+ "box_basic option must be specified for provider: #{provider}"
6
+ end
7
+
8
+ include_context "acceptance"
9
+
10
+ before do
11
+ environment.skeleton("provisioner_puppet")
12
+
13
+ vagrantfile = environment.workdir.join('Vagrantfile')
14
+ # TODO: Can we just shell out to something?
15
+ new_vagrantfile = "Vagrant.require_plugin('docker-provider')\n#{vagrantfile.read}"
16
+ vagrantfile.open('w') { |f| f.puts(new_vagrantfile) }
17
+
18
+ assert_execute("vagrant", "box", "add", "box", box)
19
+ assert_execute("vagrant", "up", "--provider=#{provider}")
20
+ end
21
+
22
+ after do
23
+ assert_execute("vagrant", "destroy", "--force")
24
+ end
25
+
26
+ it "provisions with puppet" do
27
+ status("Test: basic manifests")
28
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant-puppet-basic")
29
+ expect(result).to exit_with(0)
30
+ expect(result.stdout).to match(/basic$/)
31
+
32
+ status("Test: basic modules")
33
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant-puppet-basic-modules")
34
+ expect(result).to exit_with(0)
35
+ expect(result.stdout).to match(/modules$/)
36
+ end
37
+ end
@@ -0,0 +1,51 @@
1
+ shared_examples "provider/provisioner/shell" do |provider, options|
2
+ if !options[:box]
3
+ raise ArgumentError,
4
+ "box_basic option must be specified for provider: #{provider}"
5
+ end
6
+
7
+ include_context "acceptance"
8
+
9
+ before do
10
+ environment.skeleton("provisioner_shell")
11
+
12
+ vagrantfile = environment.workdir.join('Vagrantfile')
13
+ # TODO: Can we just shell out to something?
14
+ new_vagrantfile = "Vagrant.require_plugin('docker-provider')\n#{vagrantfile.read}"
15
+ vagrantfile.open('w') { |f| f.puts(new_vagrantfile) }
16
+
17
+ assert_execute("vagrant", "box", "add", "box", options[:box])
18
+ assert_execute("vagrant", "up", "--provider=#{provider}")
19
+ end
20
+
21
+ after do
22
+ assert_execute("vagrant", "destroy", "--force")
23
+ end
24
+
25
+ it "provisions with the shell script" do
26
+ status("Test: inline script")
27
+ result = execute("vagrant", "ssh", "-c", "cat /foo")
28
+ expect(result).to exit_with(0)
29
+ expect(result.stdout).to match(/foo\n$/)
30
+
31
+ status("Test: script from path")
32
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant-path")
33
+ expect(result).to exit_with(0)
34
+ expect(result.stdout).to match(/bar\n$/)
35
+
36
+ status("Test: script with args")
37
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant-args")
38
+ expect(result).to exit_with(0)
39
+ expect(result.stdout).to match(/hello\ntwo words\n$/)
40
+
41
+ status("Test: privileged scripts")
42
+ result = execute("vagrant", "ssh", "-c", "cat /tmp/vagrant-user-root")
43
+ expect(result).to exit_with(0)
44
+ expect(result.stdout).to match(/root$/)
45
+
46
+ status("Test: non-privileged scripts")
47
+ result = execute("vagrant", "ssh", "-c", "cat /tmp/vagrant-user")
48
+ expect(result).to exit_with(0)
49
+ expect(result.stdout).to_not match(/root$/)
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ shared_examples "provider/synced_folder/nfs" do |provider, options|
2
+ if !options[:box]
3
+ raise ArgumentError,
4
+ "box option must be specified for provider: #{provider}"
5
+ end
6
+
7
+ include_context "acceptance"
8
+
9
+ before do
10
+ environment.skeleton("synced_folder_nfs")
11
+
12
+ vagrantfile = environment.workdir.join('Vagrantfile')
13
+ new_vagrantfile = "Vagrant.require_plugin('docker-provider')\n#{vagrantfile.read}"
14
+ new_vagrantfile.gsub!(/(config\.vm\.box = "box")/, "\\1\nconfig.vm.provider :docker do |docker|\ndocker.privileged = true\nend\n")
15
+ new_vagrantfile.gsub!(/(, type: "nfs")/, '\1, mount_options: ["rw", "vers=3", "tcp", "nolock"]')
16
+ vagrantfile.open('w') { |f| f.puts(new_vagrantfile) }
17
+
18
+ assert_execute("vagrant", "box", "add", "box", options[:box])
19
+ assert_execute("vagrant", "up", "--provider=#{provider}")
20
+ end
21
+
22
+ after do
23
+ assert_execute("vagrant", "destroy", "--force")
24
+ end
25
+
26
+ it "properly configures NFS" do
27
+ status("Test: mounts the NFS folder")
28
+ result = execute("vagrant", "ssh", "-c", "cat /vagrant-nfs/foo")
29
+ expect(result).to exit_with(0)
30
+ expect(result.stdout).to match(/hello$/)
31
+
32
+ status("Test: doesn't mount a disabled folder")
33
+ result = execute("vagrant", "ssh", "-c", "test -d /foo")
34
+ expect(result.exit_code).to eql(1)
35
+ end
36
+ end
@@ -12,12 +12,13 @@ describe VagrantPlugins::DockerProvider::Driver do
12
12
 
13
13
  describe '#create' do
14
14
  let(:params) { {
15
- image: 'jimi/hendrix:eletric-ladyland',
16
- cmd: ['play', 'voodoo-chile'],
17
- ports: '8080:80',
18
- volumes: '/host/path:guest/path',
19
- name: cid,
20
- hostname: 'jimi-hendrix'
15
+ image: 'jimi/hendrix:eletric-ladyland',
16
+ cmd: ['play', 'voodoo-chile'],
17
+ ports: '8080:80',
18
+ volumes: '/host/path:guest/path',
19
+ name: cid,
20
+ hostname: 'jimi-hendrix',
21
+ privileged: true
21
22
  } }
22
23
 
23
24
  before { subject.create(params) }
@@ -38,6 +39,10 @@ describe VagrantPlugins::DockerProvider::Driver do
38
39
  expect(cmd_executed).to match(/-v #{params[:volumes]} .+ #{Regexp.escape params[:image]}/)
39
40
  end
40
41
 
42
+ it 'is able to run a privileged container' do
43
+ expect(cmd_executed).to match(/-privileged .+ #{Regexp.escape params[:image]}/)
44
+ end
45
+
41
46
  it 'sets the hostname if specified' do
42
47
  expect(cmd_executed).to match(/-h #{params[:hostname]} #{Regexp.escape params[:image]}/)
43
48
  end
@@ -86,6 +91,18 @@ describe VagrantPlugins::DockerProvider::Driver do
86
91
  end
87
92
  end
88
93
 
94
+ describe '#privileged?' do
95
+ it 'identifies privileged containers' do
96
+ subject.stub(inspect_container: {'HostConfig' => {"Privileged" => true}})
97
+ expect(subject).to be_privileged(cid)
98
+ end
99
+
100
+ it 'identifies unprivileged containers' do
101
+ subject.stub(inspect_container: {'HostConfig' => {"Privileged" => false}})
102
+ expect(subject).to_not be_privileged(cid)
103
+ end
104
+ end
105
+
89
106
  describe '#start' do
90
107
  context 'when container is running' do
91
108
  before { subject.stub(running?: true) }
@@ -111,7 +128,7 @@ describe VagrantPlugins::DockerProvider::Driver do
111
128
  before { subject.stub(running?: true) }
112
129
 
113
130
  it 'stops the container' do
114
- subject.should_receive(:execute).with('docker', 'stop', cid)
131
+ subject.should_receive(:execute).with('docker', 'stop', '-t', '1', cid)
115
132
  subject.stop(cid)
116
133
  end
117
134
  end
@@ -120,24 +137,66 @@ describe VagrantPlugins::DockerProvider::Driver do
120
137
  before { subject.stub(running?: false) }
121
138
 
122
139
  it 'does not stop container' do
123
- subject.should_not_receive(:execute).with('docker', 'stop', cid)
140
+ subject.should_not_receive(:execute).with('docker', 'stop', '-t', '1', cid)
124
141
  subject.stop(cid)
125
142
  end
126
143
  end
127
144
  end
128
145
 
129
- describe '#inspect' do
146
+ describe '#rm' do
147
+ context 'when container has been created' do
148
+ before { subject.stub(created?: true) }
149
+
150
+ it 'removes the container' do
151
+ subject.should_receive(:execute).with('docker', 'rm', '-v', cid)
152
+ subject.rm(cid)
153
+ end
154
+ end
155
+
156
+ context 'when container has not been created' do
157
+ before { subject.stub(created?: false) }
158
+
159
+ it 'does not attempt to remove the container' do
160
+ subject.should_not_receive(:execute).with('docker', 'rm', '-v', cid)
161
+ subject.rm(cid)
162
+ end
163
+ end
164
+ end
165
+
166
+ describe '#inspect_container' do
130
167
  let(:data) { '[{"json": "value"}]' }
131
168
 
132
169
  before { subject.stub(execute: data) }
133
170
 
134
171
  it 'inspects the container' do
135
172
  subject.should_receive(:execute).with('docker', 'inspect', cid)
136
- subject.inspect(cid)
173
+ subject.inspect_container(cid)
137
174
  end
138
175
 
139
176
  it 'parses the json output' do
140
- expect(subject.inspect(cid)).to eq('json' => 'value')
177
+ expect(subject.inspect_container(cid)).to eq('json' => 'value')
178
+ end
179
+ end
180
+
181
+ describe '#all_containers' do
182
+ let(:containers) { "container1\ncontainer2" }
183
+
184
+ before { subject.stub(execute: containers) }
185
+
186
+ it 'returns an array of all known containers' do
187
+ subject.should_receive(:execute).with('docker', 'ps', '-a', '-q', '-notrunc')
188
+ expect(subject.all_containers).to eq(['container1', 'container2'])
189
+ end
190
+ end
191
+
192
+ describe '#docker_bridge_ip' do
193
+ let(:containers) { " inet 123.456.789.012/16 " }
194
+
195
+ before { subject.stub(execute: containers) }
196
+
197
+ it 'returns an array of all known containers' do
198
+ subject.should_receive(:execute).with('/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'docker0')
199
+ expect(subject.docker_bridge_ip).to eq('123.456.789.012')
141
200
  end
142
201
  end
143
202
  end