chef-metal-docker 0.2 → 0.4.1
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 +62 -1
- data/lib/chef/provider/docker_container.rb +3 -109
- data/lib/chef/resource/docker_container.rb +1 -7
- data/lib/chef_metal/driver_init/docker.rb +3 -0
- data/lib/chef_metal_docker.rb +2 -2
- data/lib/chef_metal_docker/chef_zero_http_proxy.rb +92 -0
- data/lib/chef_metal_docker/docker_container_machine.rb +26 -0
- data/lib/chef_metal_docker/docker_driver.rb +238 -0
- data/lib/chef_metal_docker/docker_transport.rb +41 -65
- data/lib/chef_metal_docker/version.rb +1 -1
- metadata +23 -13
- data/lib/chef_metal/provisioner_init/docker_init.rb +0 -4
- data/lib/chef_metal_docker/docker_provisioner.rb +0 -272
- data/lib/chef_metal_docker/docker_unix_machine.rb +0 -9
- data/lib/chef_metal_docker/helpers.rb +0 -146
- data/lib/chef_metal_docker/helpers/container.rb +0 -15
- data/lib/chef_metal_docker/helpers/container/actions.rb +0 -313
- data/lib/chef_metal_docker/helpers/container/helpers.rb +0 -156
@@ -6,15 +6,18 @@ require 'uri'
|
|
6
6
|
require 'socket'
|
7
7
|
require 'em-proxy'
|
8
8
|
require 'mixlib/shellout'
|
9
|
+
require 'sys/proctable'
|
10
|
+
require 'chef_metal_docker/chef_zero_http_proxy'
|
9
11
|
|
10
12
|
module ChefMetalDocker
|
11
13
|
class DockerTransport < ChefMetal::Transport
|
12
|
-
def initialize(
|
13
|
-
@repository_name =
|
14
|
+
def initialize(container_name, base_image_name, credentials, connection, tunnel_transport = nil)
|
15
|
+
@repository_name = 'chef'
|
14
16
|
@container_name = container_name
|
15
|
-
@image = Docker::Image.get(
|
17
|
+
@image = Docker::Image.get(base_image_name, connection)
|
16
18
|
@credentials = credentials
|
17
19
|
@connection = connection
|
20
|
+
@tunnel_transport = tunnel_transport
|
18
21
|
end
|
19
22
|
|
20
23
|
include Chef::Mixin::ShellOut
|
@@ -24,12 +27,16 @@ module ChefMetalDocker
|
|
24
27
|
attr_reader :image
|
25
28
|
attr_reader :credentials
|
26
29
|
attr_reader :connection
|
30
|
+
attr_reader :tunnel_transport
|
27
31
|
|
28
32
|
def execute(command, options={})
|
29
33
|
Chef::Log.debug("execute '#{command}' with options #{options}")
|
34
|
+
|
30
35
|
begin
|
31
36
|
connection.post("/containers/#{container_name}/stop?t=0", '')
|
32
37
|
Chef::Log.debug("stopped /containers/#{container_name}")
|
38
|
+
rescue Excon::Errors::NotModified
|
39
|
+
Chef::Log.debug("Already stopped #{container_name}")
|
33
40
|
rescue Docker::Error::NotFoundError
|
34
41
|
end
|
35
42
|
begin
|
@@ -45,15 +52,17 @@ module ChefMetalDocker
|
|
45
52
|
live_stream = nil
|
46
53
|
live_stream = STDOUT if options[:stream]
|
47
54
|
live_stream = options[:stream_stdout] if options[:stream_stdout]
|
48
|
-
cmd = Mixlib::ShellOut.new(Shellwords.join(['docker', 'run', '--name', container_name,
|
55
|
+
cmd = Mixlib::ShellOut.new(Shellwords.join(['docker', 'run', '--name', container_name, @image.id ] + command),
|
49
56
|
:live_stream => live_stream, :timeout => execute_timeout(options))
|
57
|
+
|
58
|
+
Chef::Log.debug("Executing #{cmd}")
|
50
59
|
cmd.run_command
|
51
60
|
|
52
61
|
|
53
62
|
unless options[:read_only]
|
54
|
-
Chef::Log.debug("Committing #{container_name} as #{repository_name}")
|
63
|
+
Chef::Log.debug("Committing #{container_name} as #{repository_name}:#{container_name}")
|
55
64
|
container = Docker::Container.get(container_name)
|
56
|
-
@image = container.commit('repo' => repository_name)
|
65
|
+
@image = container.commit('repo' => repository_name, 'tag' => container_name)
|
57
66
|
end
|
58
67
|
|
59
68
|
Chef::Log.debug("Execute complete: status #{cmd.exitstatus}")
|
@@ -62,7 +71,7 @@ module ChefMetalDocker
|
|
62
71
|
|
63
72
|
def read_file(path)
|
64
73
|
container = Docker::Container.create({
|
65
|
-
'Image' =>
|
74
|
+
'Image' => @image.id,
|
66
75
|
'Cmd' => %w(echo true)
|
67
76
|
}, connection)
|
68
77
|
begin
|
@@ -99,7 +108,7 @@ module ChefMetalDocker
|
|
99
108
|
Tempfile.open('metal_docker_write_file') do |file|
|
100
109
|
file.write(content)
|
101
110
|
file.close
|
102
|
-
@image = @image.insert_local('localPath' => file.path, 'outputPath' => path, 't' => "#{repository_name}
|
111
|
+
@image = @image.insert_local('localPath' => file.path, 'outputPath' => path, 't' => "#{repository_name}:#{container_name}")
|
103
112
|
end
|
104
113
|
end
|
105
114
|
|
@@ -115,26 +124,38 @@ module ChefMetalDocker
|
|
115
124
|
end
|
116
125
|
|
117
126
|
def upload_file(local_path, path)
|
118
|
-
@image = @image.insert_local('localPath' => local_path, 'outputPath' => path, 't' => "#{repository_name}
|
127
|
+
@image = @image.insert_local('localPath' => local_path, 'outputPath' => path, 't' => "#{repository_name}:#{container_name}")
|
119
128
|
end
|
120
129
|
|
121
130
|
def make_url_available_to_remote(url)
|
122
131
|
# The host is already open to the container. Just find out its address and return it!
|
123
132
|
uri = URI(url)
|
124
133
|
host = Socket.getaddrinfo(uri.host, uri.scheme, nil, :STREAM)[0][3]
|
134
|
+
Chef::Log.debug("Making URL available: #{host}")
|
135
|
+
|
125
136
|
if host == '127.0.0.1' || host == '[::1]'
|
126
137
|
result = execute('ip route ls', :read_only => true)
|
138
|
+
|
139
|
+
Chef::Log.debug("IP route: #{result.stdout}")
|
140
|
+
|
127
141
|
if result.stdout =~ /default via (\S+)/
|
128
|
-
|
142
|
+
|
143
|
+
uri.host = if using_boot2docker?
|
144
|
+
# Intermediate VM does NAT, so local address should be fine here
|
145
|
+
Chef::Log.debug("Using boot2docker!")
|
146
|
+
IPSocket.getaddress(Socket.gethostname)
|
147
|
+
else
|
148
|
+
$1
|
149
|
+
end
|
129
150
|
|
130
151
|
if !@proxy_thread
|
131
152
|
# Listen to docker instances only, and forward to localhost
|
132
153
|
@proxy_thread = Thread.new do
|
133
|
-
|
134
|
-
|
135
|
-
end
|
154
|
+
Chef::Log.debug("Starting proxy thread: #{uri.host}:#{uri.port} <--> #{host}:#{uri.port}")
|
155
|
+
ChefZeroHttpProxy.new(uri.host, uri.port, host, uri.port).run
|
136
156
|
end
|
137
157
|
end
|
158
|
+
Chef::Log.debug("Using Chef server URL: #{uri.to_s}")
|
138
159
|
|
139
160
|
return uri.to_s
|
140
161
|
else
|
@@ -153,60 +174,15 @@ module ChefMetalDocker
|
|
153
174
|
|
154
175
|
private
|
155
176
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
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}"
|
177
|
+
# boot2docker introduces an intermediate VM so we need to use a slightly different
|
178
|
+
# mechanism for getting to the running chef-zero
|
179
|
+
def using_boot2docker?
|
180
|
+
Sys::ProcTable.ps do |proc|
|
181
|
+
if proc.respond_to?(:cmdline)
|
182
|
+
if proc.send(:cmdline).to_s =~ /.*--comment boot2docker.*/
|
183
|
+
return true
|
185
184
|
end
|
186
185
|
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
186
|
end
|
211
187
|
end
|
212
188
|
|
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:
|
4
|
+
version: 0.4.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-
|
11
|
+
date: 2014-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sys-proctable
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rspec
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,21 +116,18 @@ extra_rdoc_files:
|
|
102
116
|
- README.md
|
103
117
|
- LICENSE
|
104
118
|
files:
|
105
|
-
- Rakefile
|
106
119
|
- LICENSE
|
107
120
|
- README.md
|
121
|
+
- Rakefile
|
108
122
|
- lib/chef/provider/docker_container.rb
|
109
123
|
- lib/chef/resource/docker_container.rb
|
110
|
-
- lib/chef_metal/
|
111
|
-
- lib/chef_metal_docker
|
124
|
+
- lib/chef_metal/driver_init/docker.rb
|
125
|
+
- lib/chef_metal_docker.rb
|
126
|
+
- lib/chef_metal_docker/chef_zero_http_proxy.rb
|
127
|
+
- lib/chef_metal_docker/docker_container_machine.rb
|
128
|
+
- lib/chef_metal_docker/docker_driver.rb
|
112
129
|
- lib/chef_metal_docker/docker_transport.rb
|
113
|
-
- lib/chef_metal_docker/docker_unix_machine.rb
|
114
|
-
- lib/chef_metal_docker/helpers/container/actions.rb
|
115
|
-
- lib/chef_metal_docker/helpers/container/helpers.rb
|
116
|
-
- lib/chef_metal_docker/helpers/container.rb
|
117
|
-
- lib/chef_metal_docker/helpers.rb
|
118
130
|
- lib/chef_metal_docker/version.rb
|
119
|
-
- lib/chef_metal_docker.rb
|
120
131
|
homepage: https://github.com/opscode/chef-metal-docker
|
121
132
|
licenses: []
|
122
133
|
metadata: {}
|
@@ -136,9 +147,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
147
|
version: '0'
|
137
148
|
requirements: []
|
138
149
|
rubyforge_project:
|
139
|
-
rubygems_version: 2.
|
150
|
+
rubygems_version: 2.2.2
|
140
151
|
signing_key:
|
141
152
|
specification_version: 4
|
142
153
|
summary: Provisioner for creating Docker containers in Chef Metal.
|
143
154
|
test_files: []
|
144
|
-
has_rdoc:
|
@@ -1,272 +0,0 @@
|
|
1
|
-
require 'chef_metal/provisioner'
|
2
|
-
require 'chef_metal/convergence_strategy/no_converge'
|
3
|
-
require 'chef_metal/convergence_strategy/install_cached'
|
4
|
-
require 'chef_metal_docker/helpers/container'
|
5
|
-
require 'chef_metal_docker/docker_transport'
|
6
|
-
require 'chef_metal_docker/docker_unix_machine'
|
7
|
-
require 'chef_metal/transport/ssh'
|
8
|
-
require 'docker'
|
9
|
-
|
10
|
-
module ChefMetalDocker
|
11
|
-
class DockerProvisioner < ChefMetal::Provisioner
|
12
|
-
|
13
|
-
include ChefMetalDocker::Helpers::Container
|
14
|
-
|
15
|
-
def initialize(credentials = nil, connection = Docker.connection)
|
16
|
-
@credentials = credentials
|
17
|
-
@connection = connection
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_reader :credentials
|
21
|
-
attr_reader :connection
|
22
|
-
|
23
|
-
# Inflate a provisioner from node information; we don't want to force the
|
24
|
-
# driver to figure out what the provisioner really needs, since it varies
|
25
|
-
# from provisioner to provisioner.
|
26
|
-
#
|
27
|
-
# ## Parameters
|
28
|
-
# node - node to inflate the provisioner for
|
29
|
-
#
|
30
|
-
# returns a DockerProvisioner
|
31
|
-
def self.inflate(node)
|
32
|
-
self.new
|
33
|
-
end
|
34
|
-
|
35
|
-
#
|
36
|
-
# Acquire a machine, generally by provisioning it. Returns a Machine
|
37
|
-
# object pointing at the machine, allowing useful actions like setup,
|
38
|
-
# converge, execute, file and directory. The Machine object will have a
|
39
|
-
# "node" property which must be saved to the server (if it is any
|
40
|
-
# different from the original node object).
|
41
|
-
#
|
42
|
-
# ## Parameters
|
43
|
-
# action_handler - the action_handler object that plugs into the host.
|
44
|
-
# node - node object (deserialized json) representing this machine. If
|
45
|
-
# the node has a provisioner_options hash in it, these will be used
|
46
|
-
# instead of options provided by the provisioner. TODO compare and
|
47
|
-
# fail if different?
|
48
|
-
# node will have node['normal']['provisioner_options'] in it with any options.
|
49
|
-
# It is a hash with this format:
|
50
|
-
#
|
51
|
-
# -- provisioner_url: docker:<URL of Docker API endpoint>
|
52
|
-
# -- base_image: Base image name to use, or repository_name:tag_name to use a specific tagged revision of that image
|
53
|
-
# -- create_container: hash of a container to create. If present, no image will be created, just a container.
|
54
|
-
# Hash options:
|
55
|
-
# - command: command to run (if unspecified or nil, will spin up the container. If false, will not run anything and will just leave the image alone.)
|
56
|
-
# - container_options: options for container create (see http://docs.docker.io/en/latest/reference/api/docker_remote_api_v1.10/#create-a-container)
|
57
|
-
# - host_options: options for container start (see http://docs.docker.io/en/latest/reference/api/docker_remote_api_v1.10/#start-a-container)
|
58
|
-
# - ssh_options: hash of ssh options. Presence of hash indicates sshd is running in the container. Net::SSH.new(ssh_options['username'], ssh_options) will be called. Set 'sudo' to true to sudo all commands (will be detected if username != root)
|
59
|
-
#
|
60
|
-
# node['normal']['provisioner_output'] will be populated with information
|
61
|
-
# about the created machine. For lxc, it is a hash with this
|
62
|
-
# format:
|
63
|
-
#
|
64
|
-
# -- provisioner_url: docker:<URL of Docker API endpoint>
|
65
|
-
# -- container_name: docker container name
|
66
|
-
# -- repository_name: docker image repository name from which container was inflated
|
67
|
-
#
|
68
|
-
def acquire_machine(action_handler, node)
|
69
|
-
# Set up the modified node data
|
70
|
-
provisioner_options = node['normal']['provisioner_options']
|
71
|
-
provisioner_output = node['normal']['provisioner_output'] || {
|
72
|
-
'provisioner_url' => "docker:", # TODO put in the Docker API endpoint
|
73
|
-
'repository_name' => "#{node['name']}_image", # TODO disambiguate with chef_server_url/path!
|
74
|
-
'container_name' => node['name'] # TODO disambiguate with chef_server_url/path!
|
75
|
-
}
|
76
|
-
|
77
|
-
repository_name = provisioner_output['repository_name']
|
78
|
-
container_name = provisioner_output['container_name']
|
79
|
-
base_image_name = provisioner_options['base_image']
|
80
|
-
raise "base_image not specified in provisioner options!" if !base_image_name
|
81
|
-
|
82
|
-
if provisioner_options['create_container']
|
83
|
-
create_container(action_handler, provisioner_options, provisioner_output)
|
84
|
-
# We don't bother waiting ... our only job is to bring it up.
|
85
|
-
else # We are in image build mode. Get prepped.
|
86
|
-
# Tag the initial image. We aren't going to actually DO anything yet.
|
87
|
-
# We will start up after we converge!
|
88
|
-
base_image = Docker::Image.get(base_image_name)
|
89
|
-
begin
|
90
|
-
repository_image = Docker::Image.get("#{repository_name}:latest")
|
91
|
-
# If the current image does NOT have the base_image as an ancestor,
|
92
|
-
# we are going to have to re-tag it and rebuild.
|
93
|
-
if repository_image.history.any? { |entry| entry['Id'] == base_image.id }
|
94
|
-
tag_base_image = false
|
95
|
-
else
|
96
|
-
tag_base_image = true
|
97
|
-
end
|
98
|
-
rescue Docker::Error::NotFoundError
|
99
|
-
tag_base_image = true
|
100
|
-
end
|
101
|
-
if tag_base_image
|
102
|
-
action_handler.perform_action "Tag base image #{base_image_name} as #{repository_name}" do
|
103
|
-
base_image.tag('repo' => repository_name, 'force' => true)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
node['normal']['provisioner_output'] = provisioner_output
|
109
|
-
|
110
|
-
if provisioner_options['create_container'] && provisioner_options['create_container']['ssh_options']
|
111
|
-
action_handler.perform_action "wait for node to start ssh" do
|
112
|
-
transport = transport_for(node)
|
113
|
-
Timeout::timeout(5*60) do
|
114
|
-
while !transport.available?
|
115
|
-
sleep(0.5)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# Nothing else needs to happen until converge. We already have the image we need!
|
122
|
-
machine_for(node)
|
123
|
-
end
|
124
|
-
|
125
|
-
def connect_to_machine(node)
|
126
|
-
machine_for(node)
|
127
|
-
end
|
128
|
-
|
129
|
-
def delete_machine(action_handler, node)
|
130
|
-
if node['normal'] && node['normal']['provisioner_output']
|
131
|
-
container_name = node['normal']['provisioner_output']['container_name']
|
132
|
-
ChefMetal.inline_resource(action_handler) do
|
133
|
-
docker_container container_name do
|
134
|
-
action [:kill, :remove]
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
convergence_strategy_for(node).cleanup_convergence(action_handler, node)
|
139
|
-
end
|
140
|
-
|
141
|
-
def stop_machine(action_handler, node)
|
142
|
-
if node['normal'] && node['normal']['provisioner_output']
|
143
|
-
container_name = node['normal']['provisioner_output']['container_name']
|
144
|
-
ChefMetal.inline_resource(action_handler) do
|
145
|
-
docker_container container_name do
|
146
|
-
action [:stop]
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# This is docker-only, not Metal, at the moment.
|
153
|
-
# TODO this should be metal. Find a nice interface.
|
154
|
-
def snapshot(action_handler, node, name=nil)
|
155
|
-
container_name = node['normal']['provisioner_output']['container_name']
|
156
|
-
ChefMetal.inline_resource(action_handler) do
|
157
|
-
docker_container container_name do
|
158
|
-
action [:commit]
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
# Output Docker tar format image
|
164
|
-
# TODO this should be metal. Find a nice interface.
|
165
|
-
def save_repository(action_handler, node, path)
|
166
|
-
container_name = node['normal']['provisioner_output']['container_name']
|
167
|
-
ChefMetal.inline_resource(action_handler) do
|
168
|
-
docker_container container_name do
|
169
|
-
action [:export]
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
# Load Docker tar format image into Docker repository
|
175
|
-
def load_repository(path)
|
176
|
-
end
|
177
|
-
|
178
|
-
# Push an image back to Docker
|
179
|
-
def push_image(name)
|
180
|
-
end
|
181
|
-
|
182
|
-
# Pull an image from Docker
|
183
|
-
def pull_image(name)
|
184
|
-
end
|
185
|
-
|
186
|
-
private
|
187
|
-
|
188
|
-
def machine_for(node)
|
189
|
-
strategy = convergence_strategy_for(node)
|
190
|
-
ChefMetalDocker::DockerUnixMachine.new(node, transport_for(node), convergence_strategy_for(node))
|
191
|
-
end
|
192
|
-
|
193
|
-
def convergence_strategy_for(node)
|
194
|
-
provisioner_output = node['normal']['provisioner_output']
|
195
|
-
provisioner_options = node['normal']['provisioner_options']
|
196
|
-
strategy = begin
|
197
|
-
options = {}
|
198
|
-
provisioner_options = node['normal']['provisioner_options'] || {}
|
199
|
-
options[:chef_client_timeout] = provisioner_options['chef_client_timeout'] if provisioner_options.has_key?('chef_client_timeout')
|
200
|
-
ChefMetal::ConvergenceStrategy::InstallCached.new(options)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def transport_for(node)
|
205
|
-
provisioner_options = node['normal']['provisioner_options']
|
206
|
-
provisioner_output = node['normal']['provisioner_output']
|
207
|
-
if provisioner_options['create_container'] && provisioner_options['create_container']['ssh_options']
|
208
|
-
container = Docker::Container.get(provisioner_output['container_name'])
|
209
|
-
ssh_options = {
|
210
|
-
# TODO create a user known hosts file
|
211
|
-
# :user_known_hosts_file => vagrant_ssh_config['UserKnownHostsFile'],
|
212
|
-
# :paranoid => true,
|
213
|
-
:host_key_alias => "#{container.id}.docker"
|
214
|
-
}.merge(provisioner_options['create_container']['ssh_options'])
|
215
|
-
username = ssh_options.delete(:username)
|
216
|
-
options = {}
|
217
|
-
if ssh_options[:sudo] || (!ssh_options.has_key?(:sudo) && username != 'root')
|
218
|
-
if ssh_options[:password]
|
219
|
-
options[:prefix] = "echo #{ssh_options[:password]} | sudo -S -p '' "
|
220
|
-
else
|
221
|
-
options[:prefix] = 'sudo '
|
222
|
-
end
|
223
|
-
end
|
224
|
-
ssh_options.delete(:sudo)
|
225
|
-
ip_address = container.info['NetworkSettings']['IPAddress']
|
226
|
-
Chef::Log.debug("Container #{provisioner_output['container_name']} address is #{ip_address}")
|
227
|
-
ChefMetal::Transport::SSH.new(ip_address, username, ssh_options, options)
|
228
|
-
else
|
229
|
-
ChefMetalDocker::DockerTransport.new(
|
230
|
-
provisioner_output['repository_name'],
|
231
|
-
provisioner_output['container_name'],
|
232
|
-
credentials,
|
233
|
-
connection)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
def create_container(action_handler, provisioner_options, provisioner_output)
|
238
|
-
container_name = provisioner_output['container_name']
|
239
|
-
|
240
|
-
container_configuration = provisioner_options['create_container']['container_configuration'] || {}
|
241
|
-
host_configuration = provisioner_options['create_container']['host_configuration'] || {}
|
242
|
-
command = provisioner_options['create_container']['command']
|
243
|
-
raise "Must pass create_container.command if creating a container" if !command
|
244
|
-
command = command.split(/\s+/) if command.is_a?(String)
|
245
|
-
container_configuration['Cmd'] = command
|
246
|
-
need_to_create = false
|
247
|
-
begin
|
248
|
-
# Try to get the container; if that fails, it doesn't exist and we start it.
|
249
|
-
container = Docker::Container.get(container_name)
|
250
|
-
if !container.info['State']['Running']
|
251
|
-
action_handler.perform_action "Delete old, non-running container" do
|
252
|
-
container.delete
|
253
|
-
end
|
254
|
-
need_to_create = true
|
255
|
-
end
|
256
|
-
|
257
|
-
rescue Docker::Error::NotFoundError
|
258
|
-
need_to_create = true
|
259
|
-
end
|
260
|
-
|
261
|
-
if need_to_create
|
262
|
-
action_handler.perform_action "Create new container and run container_configuration['Cmd']" do
|
263
|
-
container = Docker::Container.create({
|
264
|
-
'name' => container_name,
|
265
|
-
'Image' => provisioner_options['base_image']
|
266
|
-
}.merge(container_configuration), connection)
|
267
|
-
container.start!(host_configuration)
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|