chef-metal-docker 0.1.1 → 0.2

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: a106532b6fa395835377aed7d7e8952db0f78552
4
- data.tar.gz: 3f8998e4a21485428004f1d93273eff5639d1cb3
3
+ metadata.gz: 9f6ac421bc65fa8a3497942dbd04d15efb23badc
4
+ data.tar.gz: 1b23d70778b4bbece79836bb419cb3ecd462fc19
5
5
  SHA512:
6
- metadata.gz: f1d1150a775d7b98c59004b3f365c35aa08a31cbb3241cd5640e1cd14002ce4390f9f90ab21a2a8743e668bd8b0d48384ac22dc5a17457ddd5a0cc64c6972e0b
7
- data.tar.gz: 45407348ba54a5d1ebefc101bd490581261a6e2f7b9957cf01a36bf3af7c8d3f5ea643c8625a79e1cc54b7ff7eaad1f521047ee681e4bcf27da687ed0afc8554
6
+ metadata.gz: ec3d7947e1e67187603842051249713a662ee9f800a8d4abd72fd10334a4e692c0005fd1f25c34a7121b01a5f6a5c3e5aea8f3f18416a2e8d5ccb882c943e3ce
7
+ data.tar.gz: a2df491bf80e944a349f256e333d6e759f2b4e2f46aab7a3ed6e7727507338a9c93dda64331ae516f50761a35b29464e70637891bb43f3dd44f8d47bb7629a72
@@ -3,8 +3,8 @@ require 'chef_metal/convergence_strategy/no_converge'
3
3
  require 'chef_metal/convergence_strategy/install_cached'
4
4
  require 'chef_metal_docker/helpers/container'
5
5
  require 'chef_metal_docker/docker_transport'
6
- require 'chef_metal_docker/docker_convergence_strategy'
7
6
  require 'chef_metal_docker/docker_unix_machine'
7
+ require 'chef_metal/transport/ssh'
8
8
  require 'docker'
9
9
 
10
10
  module ChefMetalDocker
@@ -50,10 +50,12 @@ module ChefMetalDocker
50
50
  #
51
51
  # -- provisioner_url: docker:<URL of Docker API endpoint>
52
52
  # -- base_image: Base image name to use, or repository_name:tag_name to use a specific tagged revision of that image
53
- # -- 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.)
54
- # -- container_options: options for container create (see http://docs.docker.io/en/latest/reference/api/docker_remote_api_v1.10/#create-a-container)
55
- # -- host_options: options for container start (see http://docs.docker.io/en/latest/reference/api/docker_remote_api_v1.10/#start-a-container)
56
- # -- convergence_strategy: :no_converge or :install_cached (former will not converge, latter will set up chef-client and converge)
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)
57
59
  #
58
60
  # node['normal']['provisioner_output'] will be populated with information
59
61
  # about the created machine. For lxc, it is a hash with this
@@ -77,29 +79,45 @@ module ChefMetalDocker
77
79
  base_image_name = provisioner_options['base_image']
78
80
  raise "base_image not specified in provisioner options!" if !base_image_name
79
81
 
80
- # Tag the initial image. We aren't going to actually DO anything yet.
81
- # We will start up after we converge!
82
- base_image = Docker::Image.get(base_image_name)
83
- begin
84
- repository_image = Docker::Image.get("#{repository_name}:latest")
85
- # If the current image does NOT have the base_image as an ancestor,
86
- # we are going to have to re-tag it and rebuild.
87
- if repository_image.history.any? { |entry| entry['Id'] == base_image.id }
88
- tag_base_image = false
89
- else
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
90
99
  tag_base_image = true
91
100
  end
92
- rescue Docker::Error::NotFoundError
93
- tag_base_image = true
94
- end
95
- if tag_base_image
96
- action_handler.perform_action "Tag base image #{base_image_name} as #{repository_name}" do
97
- base_image.tag('repo' => repository_name, 'force' => true)
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
98
105
  end
99
106
  end
100
107
 
101
108
  node['normal']['provisioner_output'] = provisioner_output
102
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
+
103
121
  # Nothing else needs to happen until converge. We already have the image we need!
104
122
  machine_for(node)
105
123
  end
@@ -168,48 +186,87 @@ module ChefMetalDocker
168
186
  private
169
187
 
170
188
  def machine_for(node)
189
+ strategy = convergence_strategy_for(node)
171
190
  ChefMetalDocker::DockerUnixMachine.new(node, transport_for(node), convergence_strategy_for(node))
172
191
  end
173
192
 
174
193
  def convergence_strategy_for(node)
175
194
  provisioner_output = node['normal']['provisioner_output']
176
195
  provisioner_options = node['normal']['provisioner_options']
177
- strategy = case provisioner_options['convergence_strategy']
178
- when 'no_converge'
179
- ChefMetal::ConvergenceStrategy::NoConverge.new
180
- else
181
- options = {}
182
- provisioner_options = node['normal']['provisioner_options'] || {}
183
- options[:chef_client_timeout] = provisioner_options['chef_client_timeout'] if provisioner_options.has_key?('chef_client_timeout')
184
- ChefMetal::ConvergenceStrategy::InstallCached.new(options)
185
- end
186
- container_configuration = provisioner_options['container_configuration'] || {}
187
- if provisioner_options['command']
188
- command = provisioner_options['command']
189
- command = command.split(/\s+/) if command.is_a?(String)
190
- container_configuration['Cmd'] = command
191
- elsif provisioner_options['command'] == false
192
- container_configuration = nil
193
- else
194
- # TODO how do we get things started? runit? cron? wassup here.
195
- container_configuration['Cmd'] = %w(while 1; sleep 1000; end)
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)
196
201
  end
197
- ChefMetalDocker::DockerConvergenceStrategy.new(strategy,
198
- provisioner_output['repository_name'],
199
- provisioner_output['container_name'],
200
- container_configuration,
201
- provisioner_options['host_configuration'] || {},
202
- credentials,
203
- connection)
204
202
  end
205
203
 
206
204
  def transport_for(node)
205
+ provisioner_options = node['normal']['provisioner_options']
207
206
  provisioner_output = node['normal']['provisioner_output']
208
- ChefMetalDocker::DockerTransport.new(
209
- provisioner_output['repository_name'],
210
- provisioner_output['container_name'],
211
- credentials,
212
- connection)
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
213
270
  end
214
271
  end
215
272
  end
@@ -1,3 +1,3 @@
1
1
  module ChefMetalDocker
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2'
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.1
4
+ version: '0.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: 2014-04-12 00:00:00.000000000 Z
11
+ date: 2014-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -108,7 +108,6 @@ files:
108
108
  - lib/chef/provider/docker_container.rb
109
109
  - lib/chef/resource/docker_container.rb
110
110
  - lib/chef_metal/provisioner_init/docker_init.rb
111
- - lib/chef_metal_docker/docker_convergence_strategy.rb
112
111
  - lib/chef_metal_docker/docker_provisioner.rb
113
112
  - lib/chef_metal_docker/docker_transport.rb
114
113
  - lib/chef_metal_docker/docker_unix_machine.rb
@@ -1,55 +0,0 @@
1
- require 'chef_metal/convergence_strategy'
2
- require 'docker'
3
-
4
- module ChefMetalDocker
5
- class DockerConvergenceStrategy < ChefMetal::ConvergenceStrategy
6
- def initialize(real_convergence_strategy, repository_name, container_name, container_configuration, host_configuration, credentials, connection)
7
- @real_convergence_strategy = real_convergence_strategy
8
- @repository_name = repository_name
9
- @container_name = container_name
10
- @container_configuration = container_configuration
11
- @host_configuration = host_configuration
12
- @credentials = credentials
13
- @connection = connection
14
- end
15
-
16
- attr_reader :real_convergence_strategy
17
- attr_reader :repository_name
18
- attr_reader :container_name
19
- attr_reader :container_configuration
20
- attr_reader :host_configuration
21
- attr_reader :credentials
22
- attr_reader :connection
23
-
24
- def setup_convergence(action_handler, machine, machine_resource)
25
- real_convergence_strategy.setup_convergence(action_handler, machine, machine_resource)
26
- end
27
-
28
- def converge(action_handler, machine, chef_server)
29
- real_convergence_strategy.converge(action_handler, machine, chef_server)
30
-
31
- # After converge, we bring up the container command
32
- if container_configuration
33
- begin
34
- container = Docker::Container.get(container_name)
35
- action_handler.perform_action "Delete existing container" do
36
- container.delete
37
- end
38
- rescue Docker::Error::NotFoundError
39
- end
40
- action_handler.perform_action "Create new container and run container_configuration['Cmd']" do
41
- container = Docker::Container.create({
42
- 'name' => container_name,
43
- 'Image' => "#{repository_name}:latest"
44
- }.merge(container_configuration), connection)
45
- container.start!(host_configuration)
46
- end
47
- # We don't bother waiting ... our only job is to bring it up.
48
- end
49
- end
50
-
51
- def cleanup_convergence(action_handler, node)
52
- real_convergence_strategy.cleanup_convergence(action_handler, node)
53
- end
54
- end
55
- end