chef-provisioning-docker 1.0.0.beta.1 → 1.0.0.beta.2
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.
- checksums.yaml +4 -4
- data/README.md +7 -7
- data/chef-provisioning-docker.gemspec +1 -1
- data/lib/chef/provisioning/docker_driver/chef_zero_http_proxy.rb +95 -0
- data/lib/chef/provisioning/docker_driver/docker_container_machine.rb +199 -13
- data/lib/chef/provisioning/docker_driver/docker_run_options.rb +591 -0
- data/lib/chef/provisioning/docker_driver/docker_transport.rb +41 -12
- data/lib/chef/provisioning/docker_driver/driver.rb +76 -167
- data/lib/chef/provisioning/docker_driver/version.rb +1 -1
- metadata +12 -5
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'chef/provisioning/transport'
|
2
2
|
require 'chef/provisioning/transport/ssh'
|
3
|
+
require 'chef/provisioning/docker_driver/chef_zero_http_proxy'
|
3
4
|
require 'docker'
|
4
5
|
require 'archive/tar/minitar'
|
5
6
|
require 'shellwords'
|
@@ -21,11 +22,12 @@ module DockerDriver
|
|
21
22
|
attr_reader :config
|
22
23
|
attr_accessor :container
|
23
24
|
|
24
|
-
def execute(command, options
|
25
|
+
def execute(command, timeout: nil, keep_stdin_open: nil, tty: nil, detached: nil, **options)
|
25
26
|
opts = {}
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
opts[:tty] = tty unless tty.nil?
|
28
|
+
opts[:detached] = detached unless detached.nil?
|
29
|
+
opts[:stdin] = keep_stdin_open unless keep_stdin_open.nil?
|
30
|
+
opts[:wait] = timeout unless timeout.nil?
|
29
31
|
|
30
32
|
command = Shellwords.split(command) if command.is_a?(String)
|
31
33
|
Chef::Log.debug("execute #{command.inspect} on container #{container.id} with options #{opts}'")
|
@@ -115,8 +117,34 @@ module DockerDriver
|
|
115
117
|
Chef::Log.debug("Session loop completed normally")
|
116
118
|
end
|
117
119
|
else
|
118
|
-
# We are the host.
|
119
|
-
# will
|
120
|
+
# We are the host. Find the docker machine's gateway (us) and talk to that;
|
121
|
+
# and set up a little proxy that will forward the container's requests to
|
122
|
+
# chef-zero
|
123
|
+
result = execute('ip route list', :read_only => true)
|
124
|
+
|
125
|
+
Chef::Log.debug("IP route: #{result.stdout}")
|
126
|
+
|
127
|
+
if result.stdout =~ /default via (\S+)/
|
128
|
+
|
129
|
+
old_uri = uri.dup
|
130
|
+
|
131
|
+
uri.host = $1
|
132
|
+
|
133
|
+
if !@proxy_thread
|
134
|
+
# Listen to docker instances only, and forward to localhost
|
135
|
+
@proxy_thread = Thread.new do
|
136
|
+
begin
|
137
|
+
Chef::Log.debug("Starting proxy thread: #{old_uri.host}:#{old_uri.port} <--> #{uri.host}:#{uri.port}")
|
138
|
+
ChefZeroHttpProxy.new(uri.host, uri.port, old_uri.host, old_uri.port).run
|
139
|
+
rescue
|
140
|
+
Chef::Log.error("Proxy thread unable to start: #{$!}")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
else
|
145
|
+
raise "Cannot forward port: ip route ls did not show default in expected format.\nSTDOUT: #{result.stdout}"
|
146
|
+
end
|
147
|
+
|
120
148
|
end
|
121
149
|
else
|
122
150
|
old_uri = uri.dup
|
@@ -140,8 +168,6 @@ module DockerDriver
|
|
140
168
|
def available?
|
141
169
|
end
|
142
170
|
|
143
|
-
private
|
144
|
-
|
145
171
|
def is_local_machine(host)
|
146
172
|
local_addrs = Socket.ip_address_list
|
147
173
|
host_addrs = Addrinfo.getaddrinfo(host, nil)
|
@@ -152,7 +178,7 @@ module DockerDriver
|
|
152
178
|
end
|
153
179
|
end
|
154
180
|
|
155
|
-
def docker_toolkit_transport
|
181
|
+
def docker_toolkit_transport(connection_url=nil)
|
156
182
|
if !defined?(@docker_toolkit_transport)
|
157
183
|
# Figure out which docker-machine this container is in
|
158
184
|
begin
|
@@ -162,18 +188,21 @@ module DockerDriver
|
|
162
188
|
@docker_toolkit_transport = nil
|
163
189
|
return
|
164
190
|
end
|
191
|
+
|
192
|
+
connection_url ||= container.connection.url
|
193
|
+
|
165
194
|
Chef::Log.debug("Found docker machines:")
|
166
195
|
docker_machine = nil
|
167
196
|
docker_machines.lines.each do |line|
|
168
197
|
machine_name, machine_url = line.chomp.split(',', 2)
|
169
198
|
Chef::Log.debug("- #{machine_name} at URL #{machine_url.inspect}")
|
170
|
-
if machine_url ==
|
171
|
-
Chef::Log.debug("Docker machine #{machine_name} at URL #{machine_url} matches the container's URL #{
|
199
|
+
if machine_url == connection_url
|
200
|
+
Chef::Log.debug("Docker machine #{machine_name} at URL #{machine_url} matches the container's URL #{connection_url}! Will use it for port forwarding.")
|
172
201
|
docker_machine = machine_name
|
173
202
|
end
|
174
203
|
end
|
175
204
|
if !docker_machine
|
176
|
-
Chef::Log.debug("Docker Toolkit is installed, but no Docker machine's URL matches #{
|
205
|
+
Chef::Log.debug("Docker Toolkit is installed, but no Docker machine's URL matches #{connection_url.inspect}. Assuming docker must be installed as well ...")
|
177
206
|
@docker_toolkit_transport = nil
|
178
207
|
return
|
179
208
|
end
|
@@ -28,6 +28,10 @@ module DockerDriver
|
|
28
28
|
Driver.new(driver_url, config)
|
29
29
|
end
|
30
30
|
|
31
|
+
def driver_url
|
32
|
+
"docker:#{Docker.url}"
|
33
|
+
end
|
34
|
+
|
31
35
|
def initialize(driver_url, config)
|
32
36
|
super
|
33
37
|
url = Driver.connection_url(driver_url)
|
@@ -37,10 +41,14 @@ module DockerDriver
|
|
37
41
|
# to be set for command-line utilities
|
38
42
|
ENV['DOCKER_HOST'] = url
|
39
43
|
Chef::Log.debug("Setting Docker URL to #{url}")
|
40
|
-
Docker.url = url
|
41
44
|
end
|
42
45
|
|
43
|
-
|
46
|
+
ENV['DOCKER_HOST'] ||= url if url
|
47
|
+
Docker.logger = Chef::Log
|
48
|
+
options = Docker.options.dup || {}
|
49
|
+
options.merge!(read_timeout: 600)
|
50
|
+
options.merge!(config.hash_dup) if config
|
51
|
+
@connection = Docker::Connection.new(url || Docker.url, options)
|
44
52
|
end
|
45
53
|
|
46
54
|
def self.canonicalize_url(driver_url, config)
|
@@ -75,6 +83,8 @@ module DockerDriver
|
|
75
83
|
action_handler,
|
76
84
|
machine_spec
|
77
85
|
)
|
86
|
+
|
87
|
+
# Grab options from existing machine (TODO seems wrong) and set the machine_spec to that
|
78
88
|
docker_options = machine_options[:docker_options]
|
79
89
|
container_id = nil
|
80
90
|
image_id = machine_options[:image_id]
|
@@ -84,7 +94,6 @@ module DockerDriver
|
|
84
94
|
image_id ||= machine_spec.reference['image_id']
|
85
95
|
docker_options ||= machine_spec.reference['docker_options']
|
86
96
|
end
|
87
|
-
|
88
97
|
container_name ||= machine_spec.name
|
89
98
|
machine_spec.reference = {
|
90
99
|
'driver_url' => driver_url,
|
@@ -96,125 +105,66 @@ module DockerDriver
|
|
96
105
|
'docker_options' => stringize_keys(docker_options),
|
97
106
|
'container_id' => container_id
|
98
107
|
}
|
99
|
-
build_container(machine_spec, docker_options)
|
100
108
|
end
|
101
109
|
|
102
110
|
def ready_machine(action_handler, machine_spec, machine_options)
|
103
|
-
start_machine(action_handler, machine_spec, machine_options)
|
104
111
|
machine_for(machine_spec, machine_options)
|
105
112
|
end
|
106
113
|
|
107
|
-
def
|
114
|
+
def start_machine(action_handler, machine_spec, machine_options)
|
108
115
|
container = container_for(machine_spec)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
build_image(machine_spec, docker_options)
|
113
|
-
|
114
|
-
args = [
|
115
|
-
'docker',
|
116
|
-
'run',
|
117
|
-
'--name',
|
118
|
-
machine_spec.reference['container_name'],
|
119
|
-
'--detach'
|
120
|
-
]
|
121
|
-
|
122
|
-
if docker_options[:keep_stdin_open]
|
123
|
-
args << '-i'
|
124
|
-
end
|
125
|
-
|
126
|
-
# We create the initial container with --net host so it can access things
|
127
|
-
# while it converges. When the final container starts, it will have its
|
128
|
-
# normal network.
|
129
|
-
args << '--net'
|
130
|
-
args << 'host'
|
131
|
-
|
132
|
-
if docker_options[:env]
|
133
|
-
docker_options[:env].each do |key, value|
|
134
|
-
args << '-e'
|
135
|
-
args << "#{key}=#{value}"
|
116
|
+
if container && !container.info['State']['Running']
|
117
|
+
action_handler.perform_action "start container #{machine_spec.name}" do
|
118
|
+
container.start!
|
136
119
|
end
|
137
120
|
end
|
121
|
+
end
|
138
122
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
123
|
+
# Connect to machine without acquiring it
|
124
|
+
def connect_to_machine(machine_spec, machine_options)
|
125
|
+
Chef::Log.debug('Connect to machine')
|
126
|
+
machine_for(machine_spec, machine_options)
|
127
|
+
end
|
145
128
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
129
|
+
def destroy_machine(action_handler, machine_spec, machine_options)
|
130
|
+
container = container_for(machine_spec)
|
131
|
+
if container
|
132
|
+
image_id = container.info['Image']
|
133
|
+
action_handler.perform_action "stop and destroy container #{machine_spec.name}" do
|
134
|
+
container.stop
|
135
|
+
container.delete
|
150
136
|
end
|
151
137
|
end
|
138
|
+
end
|
152
139
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
140
|
+
def stop_machine(action_handler, machine_spec, machine_options)
|
141
|
+
container = container_for(machine_spec)
|
142
|
+
if container.info['State']['Running']
|
143
|
+
action_handler.perform_action "stop container #{machine_spec.name}" do
|
144
|
+
container.stop!
|
157
145
|
end
|
158
146
|
end
|
159
|
-
|
160
|
-
if docker_options[:dns_search]
|
161
|
-
args << '--dns-search'
|
162
|
-
args << "#{docker_options[:dns_search]}"
|
163
|
-
end
|
164
|
-
|
165
|
-
args << image.id
|
166
|
-
args += Shellwords.split("/bin/sh -c 'while true;do sleep 1000; done'")
|
167
|
-
|
168
|
-
cmdstr = Shellwords.join(args)
|
169
|
-
Chef::Log.debug("Executing #{cmdstr}")
|
170
|
-
|
171
|
-
cmd = Mixlib::ShellOut.new(cmdstr)
|
172
|
-
cmd.run_command
|
173
|
-
|
174
|
-
container = Docker::Container.get(machine_spec.reference['container_name'])
|
175
|
-
|
176
|
-
Chef::Log.debug("Container id: #{container.id}")
|
177
|
-
machine_spec.reference['container_id'] = container.id
|
178
|
-
container
|
179
147
|
end
|
180
148
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
source_repository = base_image[:repository]
|
185
|
-
source_tag = base_image[:tag]
|
186
|
-
|
187
|
-
target_tag = machine_spec.reference['container_name']
|
188
|
-
|
189
|
-
image = Docker::Image.create(
|
190
|
-
'fromImage' => source_name,
|
191
|
-
'repo' => source_repository,
|
192
|
-
'tag' => source_tag
|
193
|
-
)
|
194
|
-
|
195
|
-
Chef::Log.debug("Allocated #{image}")
|
196
|
-
image.tag('repo' => 'chef', 'tag' => target_tag)
|
197
|
-
Chef::Log.debug("Tagged image #{image}")
|
198
|
-
|
199
|
-
machine_spec.reference['image_id'] = image.id
|
200
|
-
image
|
201
|
-
end
|
149
|
+
#
|
150
|
+
# Images
|
151
|
+
#
|
202
152
|
|
203
153
|
def allocate_image(action_handler, image_spec, image_options, machine_spec, machine_options)
|
154
|
+
tag_container_image(action_handler, machine_spec, image_spec)
|
155
|
+
|
204
156
|
# Set machine options on the image to match our newly created image
|
205
157
|
image_spec.reference = {
|
206
158
|
'driver_url' => driver_url,
|
207
159
|
'driver_version' => Chef::Provisioning::DockerDriver::VERSION,
|
208
160
|
'allocated_at' => Time.now.to_i,
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
:tag => image_spec.name
|
214
|
-
},
|
215
|
-
:from_image => true
|
161
|
+
'docker_options' => {
|
162
|
+
'base_image' => {
|
163
|
+
'name' => image_spec.name
|
164
|
+
}
|
216
165
|
}
|
217
166
|
}
|
167
|
+
|
218
168
|
# Workaround for chef/chef-provisioning-docker#37
|
219
169
|
machine_spec.attrs[:keep_image] = true
|
220
170
|
end
|
@@ -225,66 +175,33 @@ module DockerDriver
|
|
225
175
|
|
226
176
|
# workaround for https://github.com/chef/chef-provisioning/issues/358.
|
227
177
|
def destroy_image(action_handler, image_spec, image_options, machine_options={})
|
228
|
-
image =
|
178
|
+
image = image_for(image_spec)
|
229
179
|
image.delete unless image.nil?
|
230
180
|
end
|
231
181
|
|
232
|
-
|
233
|
-
def connect_to_machine(machine_spec, machine_options)
|
234
|
-
Chef::Log.debug('Connect to machine')
|
235
|
-
machine_for(machine_spec, machine_options)
|
236
|
-
end
|
182
|
+
private
|
237
183
|
|
238
|
-
def
|
184
|
+
def tag_container_image(action_handler, machine_spec, image_spec)
|
239
185
|
container = container_for(machine_spec)
|
240
|
-
|
241
|
-
|
242
|
-
container.
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
image = find_image(machine_spec)
|
247
|
-
Chef::Log.debug("Destroying image: chef:#{image.id}")
|
248
|
-
image.delete
|
186
|
+
existing_image = image_for(image_spec)
|
187
|
+
unless existing_image && existing_image.id == container.info['Image']
|
188
|
+
image = Docker::Image.get(container.info['Image'], {}, @connection)
|
189
|
+
action_handler.perform_action "tag image #{container.info['Image']} as chef-images/#{image_spec.name}" do
|
190
|
+
image.tag('repo' => image_spec.name, 'force' => true)
|
191
|
+
end
|
249
192
|
end
|
250
193
|
end
|
251
194
|
|
252
|
-
def
|
253
|
-
|
254
|
-
return if container.nil?
|
255
|
-
|
256
|
-
container.stop if container.info['State']['Running']
|
195
|
+
def to_camel_case(name)
|
196
|
+
name.split('_').map { |x| x.capitalize }.join("")
|
257
197
|
end
|
258
198
|
|
259
|
-
def
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
rescue Docker::Error::NotFoundError
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
if image.nil?
|
270
|
-
image_name = "chef:#{machine_spec.reference['container_name']}"
|
271
|
-
if machine_spec.from_image
|
272
|
-
base_image = base_image_for(machine_spec)
|
273
|
-
image_name = "#{base_image[:repository]}:#{base_image[:tag]}"
|
274
|
-
end
|
275
|
-
|
276
|
-
image = Docker::Image.all.select {
|
277
|
-
|i| i.info['RepoTags'].include? image_name
|
278
|
-
}.first
|
279
|
-
|
280
|
-
if machine_spec.from_image && image.nil?
|
281
|
-
raise "Unable to locate machine_image for #{image_name}"
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
machine_spec.reference['image_id'] = image.id if image
|
286
|
-
|
287
|
-
image
|
199
|
+
def to_snake_case(name)
|
200
|
+
# ExposedPorts -> _exposed_ports
|
201
|
+
name = name.gsub(/[A-Z]/) { |x| "_#{x.downcase}" }
|
202
|
+
# _exposed_ports -> exposed_ports
|
203
|
+
name = name[1..-1] if name.start_with?('_')
|
204
|
+
name
|
288
205
|
end
|
289
206
|
|
290
207
|
def from_image_from_action_handler(action_handler, machine_spec)
|
@@ -298,22 +215,11 @@ module DockerDriver
|
|
298
215
|
end
|
299
216
|
end
|
300
217
|
|
301
|
-
def driver_url
|
302
|
-
"docker:#{Docker.url}"
|
303
|
-
end
|
304
|
-
|
305
|
-
def start_machine(action_handler, machine_spec, machine_options)
|
306
|
-
container = container_for(machine_spec)
|
307
|
-
if container && !container.info['State']['Running']
|
308
|
-
container.start
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
218
|
def machine_for(machine_spec, machine_options)
|
313
219
|
Chef::Log.debug('machine_for...')
|
314
|
-
docker_options = machine_options[:docker_options] || Mash.from_hash(machine_spec.reference['docker_options'])
|
220
|
+
docker_options = machine_options[:docker_options] || Mash.from_hash(machine_spec.reference['docker_options'] || {})
|
315
221
|
|
316
|
-
container =
|
222
|
+
container = container_for(machine_spec)
|
317
223
|
|
318
224
|
if machine_spec.from_image
|
319
225
|
convergence_strategy = Chef::Provisioning::ConvergenceStrategy::NoConverge.new({}, config)
|
@@ -328,28 +234,31 @@ module DockerDriver
|
|
328
234
|
machine_spec,
|
329
235
|
transport,
|
330
236
|
convergence_strategy,
|
237
|
+
@connection,
|
331
238
|
docker_options[:command]
|
332
239
|
)
|
333
240
|
end
|
334
241
|
|
335
242
|
def container_for(machine_spec)
|
336
|
-
container_id = machine_spec.reference['container_id']
|
337
243
|
begin
|
338
|
-
|
244
|
+
Docker::Container.get(machine_spec.name, {}, @connection)
|
339
245
|
rescue Docker::Error::NotFoundError
|
340
246
|
end
|
341
247
|
end
|
342
248
|
|
343
|
-
def
|
344
|
-
|
345
|
-
|
346
|
-
|
249
|
+
def image_for(image_spec)
|
250
|
+
begin
|
251
|
+
Docker::Image.get(image_spec.name, {}, @connection)
|
252
|
+
rescue Docker::Error::NotFoundError
|
253
|
+
end
|
347
254
|
end
|
348
255
|
|
349
256
|
def stringize_keys(hash)
|
350
|
-
|
351
|
-
|
352
|
-
|
257
|
+
if hash
|
258
|
+
hash.each_with_object({}) do |(k,v),hash|
|
259
|
+
v = stringize_keys(v) if v.is_a?(Hash)
|
260
|
+
hash[k.to_s] = v
|
261
|
+
end
|
353
262
|
end
|
354
263
|
end
|
355
264
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chef-provisioning-docker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.beta.
|
4
|
+
version: 1.0.0.beta.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Duffield
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
@@ -44,14 +44,20 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1.
|
47
|
+
version: '1.26'
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 1.26.2
|
48
51
|
type: :runtime
|
49
52
|
prerelease: false
|
50
53
|
version_requirements: !ruby/object:Gem::Requirement
|
51
54
|
requirements:
|
52
55
|
- - "~>"
|
53
56
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1.
|
57
|
+
version: '1.26'
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.26.2
|
55
61
|
- !ruby/object:Gem::Dependency
|
56
62
|
name: minitar
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,7 +142,9 @@ files:
|
|
136
142
|
- Rakefile
|
137
143
|
- chef-provisioning-docker.gemspec
|
138
144
|
- lib/chef/provisioning/docker_driver.rb
|
145
|
+
- lib/chef/provisioning/docker_driver/chef_zero_http_proxy.rb
|
139
146
|
- lib/chef/provisioning/docker_driver/docker_container_machine.rb
|
147
|
+
- lib/chef/provisioning/docker_driver/docker_run_options.rb
|
140
148
|
- lib/chef/provisioning/docker_driver/docker_transport.rb
|
141
149
|
- lib/chef/provisioning/docker_driver/driver.rb
|
142
150
|
- lib/chef/provisioning/docker_driver/version.rb
|
@@ -168,4 +176,3 @@ signing_key:
|
|
168
176
|
specification_version: 4
|
169
177
|
summary: Provisioner for creating Docker containers in Chef Provisioning.
|
170
178
|
test_files: []
|
171
|
-
has_rdoc:
|