chef-metal-docker 0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c6f926be1ddd326fc9850e14dcb146ce3ff3f5d
4
- data.tar.gz: e8a636cb1fb78e910302806e64bd709bc94d3cc1
3
+ metadata.gz: a106532b6fa395835377aed7d7e8952db0f78552
4
+ data.tar.gz: 3f8998e4a21485428004f1d93273eff5639d1cb3
5
5
  SHA512:
6
- metadata.gz: e4538affcb8653d66726425196d8473372b0901c2320f19ffeacc5539232b2dfade9809bb6c4db5c7e3b7debce6767df9e5068ee98af35368234af3ae7d5e094
7
- data.tar.gz: 790d6e055e0a754a37097a2fae755e722a3c0295b07ef61f6e8e3de9d3394b4b57de1baac94d178abcf85b47be0ddbe4b81f2ee86a9f7f2760f1c19a62c62583
6
+ metadata.gz: f1d1150a775d7b98c59004b3f365c35aa08a31cbb3241cd5640e1cd14002ce4390f9f90ab21a2a8743e668bd8b0d48384ac22dc5a17457ddd5a0cc64c6972e0b
7
+ data.tar.gz: 45407348ba54a5d1ebefc101bd490581261a6e2f7b9957cf01a36bf3af7c8d3f5ea643c8625a79e1cc54b7ff7eaad1f521047ee681e4bcf27da687ed0afc8554
@@ -4,6 +4,8 @@ require 'archive/tar/minitar'
4
4
  require 'shellwords'
5
5
  require 'uri'
6
6
  require 'socket'
7
+ require 'em-proxy'
8
+ require 'mixlib/shellout'
7
9
 
8
10
  module ChefMetalDocker
9
11
  class DockerTransport < ChefMetal::Transport
@@ -15,6 +17,8 @@ module ChefMetalDocker
15
17
  @connection = connection
16
18
  end
17
19
 
20
+ include Chef::Mixin::ShellOut
21
+
18
22
  attr_reader :container_name
19
23
  attr_reader :repository_name
20
24
  attr_reader :image
@@ -34,70 +38,26 @@ module ChefMetalDocker
34
38
  Chef::Log.debug("deleted /containers/#{container_name}")
35
39
  rescue Docker::Error::NotFoundError
36
40
  end
37
- Chef::Log.debug("Creating #{container_name} from #{repository_name}:latest")
38
- @container = Docker::Container.create({
39
- 'name' => container_name,
40
- 'Image' => "#{repository_name}:latest",
41
- 'Cmd' => (command.is_a?(String) ? Shellwords.shellsplit(command) : command),
42
- 'AttachStdout' => true,
43
- 'AttachStderr' => true,
44
- 'TTY' => false
45
- }, connection)
46
41
 
47
- read_timeout = execute_timeout(options)
48
- read_timeout = nil if read_timeout == 0
49
- Docker.options[:read_timeout] = read_timeout
50
- begin
51
- stdout = ''
52
- stderr = ''
53
-
54
- attach_thread = Thread.new do
55
- Chef::Log.debug("Setting timeout to 15 minutes")
56
- Docker.options[:read_timeout] = (15 * 60)
57
-
58
- Chef::Log.debug("Attaching to #{container_name}")
59
- # Capture stdout / stderr
60
- @container.attach do |type, str|
61
- case type
62
- when :stdout
63
- stdout << str
64
- stream_chunk(options, stdout, nil)
65
- when :stderr
66
- stderr << str
67
- stream_chunk(options, nil, stderr)
68
- else
69
- raise "unexpected message type #{type}"
70
- end
71
- end
72
-
73
- Chef::Log.debug("Removing temporary read timeout")
74
- Docker.options.delete(:read_timeout)
75
- end
76
-
77
- begin
78
- Chef::Log.debug("Starting #{container_name}")
79
- # Start the container
80
- @container.start
42
+ command = Shellwords.split(command) if command.is_a?(String)
81
43
 
82
- Chef::Log.debug("Grabbing exit status from #{container_name}")
83
- # Capture exit code
84
- exit_status = @container.wait(read_timeout)
85
- attach_thread.join
44
+ # TODO shell_out has no way to live stream stderr???
45
+ live_stream = nil
46
+ live_stream = STDOUT if options[:stream]
47
+ live_stream = options[:stream_stdout] if options[:stream_stdout]
48
+ cmd = Mixlib::ShellOut.new(Shellwords.join(['docker', 'run', '--name', container_name, "#{repository_name}:latest" ] + command),
49
+ :live_stream => live_stream, :timeout => execute_timeout(options))
50
+ cmd.run_command
86
51
 
87
- unless options[:read_only]
88
- Chef::Log.debug("Committing #{container_name} as #{repository_name}")
89
- @image = @container.commit('repo' => repository_name)
90
- end
91
52
 
92
- Chef::Log.debug("Execute complete: status #{exit_status['StatusCode']}")
93
- DockerResult.new(command, options, stdout, stderr, exit_status['StatusCode'])
94
- ensure
95
- Thread.kill(attach_thread) if attach_thread.alive?
96
- end
97
- ensure
98
- Chef::Log.debug("Removing temporary read timeout")
99
- Docker.options.delete(:read_timeout)
53
+ unless options[:read_only]
54
+ Chef::Log.debug("Committing #{container_name} as #{repository_name}")
55
+ container = Docker::Container.get(container_name)
56
+ @image = container.commit('repo' => repository_name)
100
57
  end
58
+
59
+ Chef::Log.debug("Execute complete: status #{cmd.exitstatus}")
60
+ cmd
101
61
  end
102
62
 
103
63
  def read_file(path)
@@ -162,10 +122,20 @@ module ChefMetalDocker
162
122
  # The host is already open to the container. Just find out its address and return it!
163
123
  uri = URI(url)
164
124
  host = Socket.getaddrinfo(uri.host, uri.scheme, nil, :STREAM)[0][3]
165
- if host == '127.0.0.1'
125
+ if host == '127.0.0.1' || host == '[::1]'
166
126
  result = execute('ip route ls', :read_only => true)
167
127
  if result.stdout =~ /default via (\S+)/
168
128
  uri.host = $1
129
+
130
+ if !@proxy_thread
131
+ # Listen to docker instances only, and forward to localhost
132
+ @proxy_thread = Thread.new do
133
+ Proxy.start(:host => uri.host, :port => uri.port, :debug => true) do |conn|
134
+ conn.server :srv, :host => host, :port => uri.port
135
+ end
136
+ end
137
+ end
138
+
169
139
  return uri.to_s
170
140
  else
171
141
  raise "Cannot forward port: ip route ls did not show default in expected format.\nSTDOUT: #{result.stdout}"
@@ -175,6 +145,7 @@ module ChefMetalDocker
175
145
  end
176
146
 
177
147
  def disconnect
148
+ @proxy_thread.kill if @proxy_thread
178
149
  end
179
150
 
180
151
  def available?
@@ -182,20 +153,83 @@ module ChefMetalDocker
182
153
 
183
154
  private
184
155
 
185
- # Copy of container.attach with timeout support
186
- def attach_with_timeout(container, options = {}, read_timeout, &block)
156
+ def old_execute
157
+ Chef::Log.debug("Creating #{container_name} from #{repository_name}:latest")
158
+ @container = Docker::Container.create({
159
+ 'name' => container_name,
160
+ 'Image' => "#{repository_name}:latest",
161
+ 'Cmd' => (command.is_a?(String) ? Shellwords.shellsplit(command) : command),
162
+ 'AttachStdout' => true,
163
+ 'AttachStderr' => true,
164
+ 'TTY' => false
165
+ }, connection)
166
+
167
+ Docker.options[:read_timeout] = read_timeout
168
+ begin
169
+ stdout = ''
170
+ stderr = ''
171
+
172
+ Chef::Log.debug("Attaching to #{container_name}")
173
+ # Capture stdout / stderr
174
+ excon, attach_datum = attach_with_timeout(@container, read_timeout) do |type, str|
175
+ puts "got something"
176
+ case type
177
+ when :stdout
178
+ stdout << str
179
+ stream_chunk(options, stdout, nil)
180
+ when :stderr
181
+ stderr << str
182
+ stream_chunk(options, nil, stderr)
183
+ else
184
+ raise "unexpected message type #{type}"
185
+ end
186
+ end
187
+
188
+ begin
189
+ Chef::Log.debug("Starting #{container_name}")
190
+ # Start the container
191
+ @container.start
192
+
193
+ Chef::Log.debug("Grabbing exit status from #{container_name}")
194
+ # Capture exit code
195
+ exit_status = @container.wait(read_timeout)
196
+
197
+ Chef::Log.debug("Waiting for attach to complete ...")
198
+ wait_for_attach(excon, attach_datum)
199
+
200
+ Chef::Log.debug("Execute complete: status #{exit_status['StatusCode']}")
201
+ DockerResult.new(command, options, stdout, stderr, exit_status['StatusCode'])
202
+ rescue
203
+ # Make sure we close off outstanding connections if we exit the method
204
+ excon.reset
205
+ raise
206
+ end
207
+ ensure
208
+ Chef::Log.debug("Removing temporary read timeout")
209
+ Docker.options.delete(:read_timeout)
210
+ end
211
+ end
212
+
213
+ # Copy of container.attach with timeout support and pipeline
214
+ def attach_with_timeout(container, read_timeout, options = {}, &block)
187
215
  opts = {
188
216
  :stream => true, :stdout => true, :stderr => true
189
217
  }.merge(options)
190
218
  # Creates list to store stdout and stderr messages
191
219
  msgs = Docker::Messages.new
192
- connection.post(
220
+ connection.start_request(
221
+ :post,
193
222
  "/containers/#{container.id}/attach",
194
223
  opts,
195
224
  :response_block => attach_for(block, msgs),
196
- :read_timeout => read_timeout
225
+ :read_timeout => read_timeout,
226
+ :pipeline => true,
227
+ :persistent => true
197
228
  )
198
- [msgs.stdout_messages, msgs.stderr_messages]
229
+ end
230
+
231
+ def wait_for_attach(excon, datum)
232
+ Excon::Response.new(excon.send(:response, datum)[:response])
199
233
  end
200
234
 
201
235
  # Method that takes chunks and calls the attached block for each mux'd message
@@ -242,3 +276,26 @@ module ChefMetalDocker
242
276
  end
243
277
  end
244
278
  end
279
+
280
+ class Docker::Connection
281
+ def start_request(method, *args, &block)
282
+ request = compile_request_params(method, *args, &block)
283
+ if Docker.logger
284
+ Docker.logger.debug(
285
+ [request[:method], request[:path], request[:query], request[:body]]
286
+ )
287
+ end
288
+ excon = resource
289
+ [ excon, excon.request(request) ]
290
+ rescue Excon::Errors::BadRequest => ex
291
+ raise ClientError, ex.message
292
+ rescue Excon::Errors::Unauthorized => ex
293
+ raise UnauthorizedError, ex.message
294
+ rescue Excon::Errors::NotFound => ex
295
+ raise NotFoundError, ex.message
296
+ rescue Excon::Errors::InternalServerError => ex
297
+ raise ServerError, ex.message
298
+ rescue Excon::Errors::Timeout => ex
299
+ raise TimeoutError, ex.message
300
+ end
301
+ end
@@ -1,3 +1,3 @@
1
1
  module ChefMetalDocker
2
- VERSION = '0.1'
2
+ VERSION = '0.1.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-metal-docker
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Duffield
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-11 00:00:00.000000000 Z
11
+ date: 2014-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: em-proxy
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement