chef-provisioning-docker 0.11.0 → 1.0.0.beta.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: a042e9a753dc5de10f2238f555c255fa725816f52432b826c51aeb356ef0c929
4
- data.tar.gz: 0bee673f49e227e01f2a74b2cca37c9842779e65409bcd132864b1ff2392ea2d
2
+ SHA1:
3
+ metadata.gz: a24a00feb49b30d7a76c5f0d2c6441114b961264
4
+ data.tar.gz: 4c24b6bd38a87d0afd01127e9266610e5efe1624
5
5
  SHA512:
6
- metadata.gz: c303b979b6558672db6bf8d7056ecc80751f30d0fd1e61e3e590a10bd7c10eb4f02073343409a3501b94aca50a3f66c20fd51830526deb6edb97b6b636c23b99
7
- data.tar.gz: 6c9ec2a45a4ec5399d91e3cd378af31ba9753ab079756eae4f684f41d4d431dda94d4831a2f811956169b58bdff0dd1b6716845c9a79b7dc7e4cebeb67ee9c94
6
+ metadata.gz: c86add037f7fcb734e8884ab2116d2b13cc5eb9cbb2cd0c976e58f7e37313bde3ba82979aa950c6313c84d3ca5b048201d0b1ab7a067a378508d897773e7eeb2
7
+ data.tar.gz: ea5067b1773a9ec1eb218989de89d5023723a5fdfb3bdca40aa07d417f31e36f3ebe283847ca26d39f790c96eaac3b32b4b250633fe6bfe74f39562bb1cf172b
data/Gemfile CHANGED
@@ -1,2 +1,5 @@
1
1
  source "https://rubygems.org"
2
+ gemfile
2
3
  gemspec
4
+
5
+ gem 'chef-provisioning', :git => 'https://github.com/opscode/chef-provisioning.git', :branch => 'master'
data/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  # chef-provisioning-docker
2
2
 
3
- [![Build Status](https://travis-ci.org/chef/chef-provisioning-docker.svg?branch=master)](https://travis-ci.org/chef/chef-provisioning-docker) [![Gem Version](https://badge.fury.io/rb/chef-provisioning-docker.svg)](http://badge.fury.io/rb/chef-provisioning-docker)
4
-
5
3
  How to use:
6
4
 
7
- First you need to ensure that Docker is running. This can be done on a Linux host using Docker's installers or on OSX using boot2docker. Once you have that, you can install the dependencies with Bundler and then use the Docker like the following:
5
+ First you need to ensure that Docker is running. This can be done on a Linux host using Docker's installers or on OSX using boot2docker. Once you have that, you can install the dependencies with Bundler and then use the Docker like the following:
8
6
 
9
7
  ```
10
8
  CHEF_DRIVER=docker bundle exec chef-client -z docker_ubuntu_image.rb
@@ -18,66 +16,58 @@ Using this , you can then define a machine similar to the following example:
18
16
 
19
17
  ```ruby
20
18
  require 'chef/provisioning/docker_driver'
21
- with_driver 'docker'
22
19
 
23
20
  machine 'wario' do
24
- recipe 'openssh::default'
25
-
26
- machine_options(
27
- docker_options: {
28
- base_image: {
29
- name: 'ubuntu',
30
- repository: 'ubuntu',
31
- tag: '14.04'
32
- },
33
- :command => '/usr/sbin/sshd -p 8022 -D',
34
-
35
- #ENV (Environment Variables)
36
- #Set any env var in the container by using one or more -e flags, even overriding those already defined by the developer with a Dockerfile ENV
37
- :env => {
38
- "deep" => 'purple',
39
- "led" => 'zeppelin'
40
- },
41
-
42
- # Ports can be one of two forms:
43
- # src_port (string or integer) is a pass-through, i.e 8022 or "9933"
44
- # src:dst (string) is a map from src to dst, i.e "8022:8023" maps 8022 externally to 8023 in the container
45
-
46
- # Example (multiple):
47
- :ports => [8022, "8023:9000", "9500"],
48
-
49
- # Examples (single):
50
- :ports => 1234,
51
- :ports => "2345:6789",
52
-
53
- # Volumes can be one of three forms:
54
- # src_volume (string) is volume to add to container, i.e. creates new volume inside container at "/tmp"
55
- # src:dst (string) mounts host's directory src to container's dst, i.e "/tmp:/tmp1" mounts host's directory /tmp to container's /tmp1
56
- # src:dst:mode (string) mounts host's directory src to container's dst with the specified mount option, i.e "/:/rootfs:ro" mounts read-only host's root (/) folder to container's /rootfs
57
- # See more details on Docker volumes at https://github.com/docker/docker/blob/master/docs/sources/userguide/dockervolumes.md .
58
-
59
- # Example (single):
60
- :volumes => "/tmp",
61
-
62
- # Example (multiple):
63
- :volumes => ["/tmp:/tmp", "/:/rootfs:ro"],
64
-
65
- # if you need to keep stdin open (i.e docker run -i)
66
- # :keep_stdin_open => true
21
+ recipe 'openssh::default'
22
+
23
+ machine_options :docker_options => {
24
+ :base_image => {
25
+ :name => 'ubuntu',
26
+ :repository => 'ubuntu',
27
+ :tag => '14.04'
28
+ },
29
+ :command => '/usr/sbin/sshd -p 8022 -D',
67
30
 
31
+ #ENV (Environment Variables)
32
+ #Set any env var in the container by using one or more -e flags, even overriding those already defined by the developer with a Dockerfile ENV
33
+ :env => {
34
+ "deep" => 'purple',
35
+ "led" => 'zeppelin'
68
36
  },
69
- # optional, default timeout is 600
70
- docker_connection: {
71
- :read_timeout => 1000,
72
- }
73
- )
74
37
 
38
+ # Ports can be one of two forms:
39
+ # src_port (string or integer) is a pass-through, i.e 8022 or "9933"
40
+ # src:dst (string) is a map from src to dst, i.e "8022:8023" maps 8022 externally to 8023 in the container
41
+
42
+ # Example (multiple):
43
+ :ports => [8022, "8023:9000", "9500"],
44
+
45
+ # Examples (single):
46
+ :ports => 1234,
47
+ :ports => "2345:6789",
48
+
49
+ # Volumes can be one of three forms:
50
+ # src_volume (string) is volume to add to container, i.e. creates new volume inside container at "/tmp"
51
+ # src:dst (string) mounts host's directory src to container's dst, i.e "/tmp:/tmp1" mounts host's directory /tmp to container's /tmp1
52
+ # src:dst:mode (string) mounts host's directory src to container's dst with the specified mount option, i.e "/:/rootfs:ro" mounts read-only host's root (/) folder to container's /rootfs
53
+ # See more details on Docker volumes at https://github.com/docker/docker/blob/master/docs/sources/userguide/dockervolumes.md .
54
+
55
+ # Example (single):
56
+ :volumes => "/tmp",
57
+
58
+ # Example (multiple):
59
+ :volumes => ["/tmp:/tmp", "/:/rootfs:ro"],
60
+
61
+ # if you need to keep stdin open (i.e docker run -i)
62
+ # :keep_stdin_open => true
63
+
64
+ }
75
65
  end
76
66
  ```
77
67
 
78
68
  ## Machine images
79
69
 
80
- This supports the new machine image paradigm; with Docker you can build a base image, save that and use it to create a new container. Here is an example of this:
70
+ This supports the new machine image paradigm; with Docker you can build a base image, save that and use it to create a new container. Here is an example of this:
81
71
 
82
72
  ```ruby
83
73
  require 'chef/provisioning/docker_driver'
@@ -85,27 +75,26 @@ require 'chef/provisioning/docker_driver'
85
75
  machine_image 'ssh_server' do
86
76
  recipe 'openssh'
87
77
 
88
- machine_options(
89
- :docker_options => {
78
+ machine_options :docker_options => {
90
79
  :base_image => {
91
80
  :name => 'ubuntu',
92
81
  :repository => 'ubuntu',
93
82
  :tag => '14.04'
94
83
  }
95
- }
96
- )
84
+ }
97
85
  end
98
86
 
99
87
  machine 'ssh00' do
100
88
  from_image 'ssh_server'
101
89
 
102
- machine_options(
103
- :docker_options => {
90
+ machine_options :docker_options => {
104
91
  :command => '/usr/sbin/sshd -D -o UsePAM=no -o UsePrivilegeSeparation=no -o PidFile=/tmp/sshd.pid',
105
92
  :ports => [22]
106
- }
107
- )
93
+ }
108
94
  end
109
95
  ```
110
96
 
111
- This will create a docker container based on Ubuntu 14.04 and then execute the openssh recipe and run the /usr/sbin/sshd command as the container's run command.
97
+ This will create a docker container based on Ubuntu 14.04 and
98
+ then execute the Apache recipe and run the /usr/sbin/httpd command
99
+ as the container's run command.
100
+
@@ -9,12 +9,12 @@ Gem::Specification.new do |s|
9
9
  s.summary = 'Provisioner for creating Docker containers in Chef Provisioning.'
10
10
  s.description = s.summary
11
11
  s.author = 'Tom Duffield'
12
- s.email = 'tom@chef.io'
13
- s.homepage = 'https://github.com/chef/chef-provisioning-docker'
12
+ s.email = 'tom@getchef.com'
13
+ s.homepage = 'https://github.com/opscode/chef-provisioning-docker'
14
14
 
15
15
  s.add_dependency 'chef'
16
- s.add_dependency 'chef-provisioning', '>= 2.0', '< 3.0'
17
- s.add_dependency 'docker-api', '~> 1.26', '>= 1.26.2'
16
+ s.add_dependency 'chef-provisioning', '~> 1.0'
17
+ s.add_dependency 'docker-api', '~> 1.25'
18
18
  s.add_dependency 'minitar'
19
19
  s.add_dependency 'sys-proctable'
20
20
 
@@ -1,5 +1,4 @@
1
1
  require 'chef/provisioning/machine/unix_machine'
2
- require 'chef/provisioning/docker_driver/docker_run_options'
3
2
 
4
3
  class Chef
5
4
  module Provisioning
@@ -10,214 +9,29 @@ module DockerDriver
10
9
  # Options is expected to contain the optional keys
11
10
  # :command => the final command to execute
12
11
  # :ports => a list of port numbers to listen on
13
- def initialize(machine_spec, transport, convergence_strategy, connection, command = nil)
12
+ def initialize(machine_spec, transport, convergence_strategy, command = nil)
14
13
  super(machine_spec, transport, convergence_strategy)
15
14
  @command = command
16
15
  @transport = transport
17
- @connection = connection
18
- end
19
-
20
- def setup_convergence(action_handler)
21
- # Build a converge container to converge in
22
- transport.container = build_converge_container(action_handler)
23
- unless transport.container.info['State']['Running']
24
- action_handler.perform_action "start converge container chef-converge.#{machine_spec.name}" do
25
- transport.container.start!
26
- end
27
- end
28
- super(action_handler)
29
- # Commit after convergence setup (such as the install of Chef)
30
- # to break up the cost of the commit and avoid read timeouts
31
- transport.container.commit
32
16
  end
33
17
 
34
18
  def converge(action_handler)
35
- # First, grab and start the converge container if it's there ...
36
- transport.container = converge_container_for(machine_spec)
37
- if !transport.container
38
- raise "No converge container found! Did you run `:converge` without first running `:setup`?"
39
- end
40
- unless transport.container.info['State']['Running']
41
- action_handler.perform_action "start converge container chef-converge.#{machine_spec.name}" do
42
- transport.container.start!
43
- end
44
- end
45
-
46
- # Then, converge ...
47
- super(action_handler)
48
-
49
- # Save the converged image ...
50
- converged_image = commit_converged_image(action_handler, machine_spec, transport.container)
51
-
52
- # Build the new container
53
- transport.container = create_container(action_handler, machine_spec, converged_image)
54
-
55
- # Finally, start it!
56
- action_handler.perform_action "start container #{machine_spec.name}" do
57
- transport.container.start!
58
- end
59
- end
60
-
61
- private
62
-
63
- def container_config(action_handler, machine_spec)
64
- docker_options = machine_spec.reference['docker_options'] || {}
65
-
66
- # We're going to delete things to make it easier on ourselves, back it up
67
- docker_options = docker_options.dup
68
-
69
- # Bring in from_image
70
- if machine_spec.from_image
71
- docker_options['base_image'] ||= {}
72
- docker_options['base_image']['name'] = machine_spec.from_image
73
- end
74
-
75
- # Respect :container_config
76
- config = stringize_keys(docker_options.delete('container_config') || {})
77
-
78
- # Respect :base_image
79
- image = base_image(action_handler, docker_options.delete('base_image'))
80
- config['Image'] = image if image
81
-
82
- # Respect everything else
83
- DockerRunOptions.include_command_line_options_in_container_config(config, docker_options)
84
- end
85
-
86
- # Get the converge container for this machine
87
- def converge_container_for(machine_spec)
88
- begin
89
- Docker::Container.get("chef-converge.#{machine_spec.name}", {}, @connection)
90
- rescue Docker::Error::NotFoundError
91
- end
92
- end
93
-
94
- def container_for(machine_spec)
95
- begin
96
- Docker::Container.get(machine_spec.name, {}, @connection)
97
- rescue Docker::Error::NotFoundError
98
- end
99
- end
100
-
101
- # Builds a container that has the same properties as the final container,
102
- # but with a couple of tweaks to allow processes to run and converge the
103
- # container.
104
- def build_converge_container(action_handler)
105
- # If a converge container already exists, do nothing. TODO check if it's different!!!
106
- converge_container = converge_container_for(machine_spec)
107
- if converge_container
108
- return converge_container
109
- end
110
-
111
- # Create a chef-capable container (just like the final one, but with --net=host
112
- # and a command that keeps it open). Base it on the image.
113
- config = container_config(action_handler, machine_spec)
114
- config.merge!(
115
- 'name' => "chef-converge.#{machine_spec.reference['container_name']}",
116
- 'Cmd' => [ "/bin/sh", "-c", "while true;do sleep 1000; done" ],
19
+ super action_handler
20
+ Chef::Log.debug("DockerContainerMachine converge complete, executing #{@command} in #{@container_name}")
21
+ image = transport.container.commit(
22
+ 'repo' => 'chef',
23
+ 'tag' => machine_spec.reference['container_name']
117
24
  )
118
- # If we're using Docker Toolkit, we need to use host networking for the converge
119
- # so we can open up the port we need. Don't force it in other cases, though.
120
- if transport.is_local_machine(URI(transport.config[:chef_server_url]).host) &&
121
- transport.docker_toolkit_transport(@connection.url)
122
- config['HostConfig'] ||= {}
123
- config['HostConfig'].merge!('NetworkMode' => 'host')
124
- # These are incompatible with NetworkMode: host
125
- config['HostConfig'].delete('Links')
126
- config['HostConfig'].delete('ExtraHosts')
127
- config.delete('NetworkSettings')
128
- end
129
- # Don't use any resources that need to be shared (such as exposed ports)
130
- config.delete('ExposedPorts')
131
-
132
- Chef::Log.debug("Creating converge container with config #{config} ...")
133
- action_handler.perform_action "create container to converge #{machine_spec.name}" do
134
- # create deletes the name :(
135
- Docker::Container.create(config.dup, @connection)
136
- converge_container = Docker::Container.get(config['name'], {}, @connection)
137
- Chef::Log.debug("Created converge container #{converge_container.id}")
138
- end
139
- converge_container
140
- end
141
-
142
- # Commit the converged container to an image. Called by converge.
143
- def commit_converged_image(action_handler, machine_spec, converge_container)
144
- # Commit the converged container to an image
145
- converged_image = nil
146
- action_handler.perform_action "commit and delete converged container for #{machine_spec.name}" do
147
- converged_image = converge_container.commit
148
- converge_container.stop!
149
- converge_container.delete
150
- end
151
- converged_image
152
- end
153
-
154
- # Create the final container from the converged image
155
- def create_container(action_handler, machine_spec, converged_image)
156
- # Check if the container already exists.
157
- container = container_for(machine_spec)
158
- if container
159
- # If it's the same image, just return; don't stop and start.
160
- if container.info['Image'] == converged_image.id
161
- return container
162
- else
163
- # If the container exists but is based on an old image, destroy it.
164
- action_handler.perform_action "stop and delete running container for #{machine_spec.name}" do
165
- container.stop!
166
- container.delete
167
- end
168
- end
169
- end
25
+ machine_spec.reference['image_id'] = image.id
170
26
 
171
- # Create the new container
172
- config = container_config(action_handler, machine_spec)
173
- config.merge!(
174
- 'name' => machine_spec.reference['container_name'],
175
- 'Image' => converged_image.id
176
- )
177
- action_handler.perform_action "create final container for #{machine_spec.name}" do
178
- container = Docker::Container.create(config, @connection)
27
+ if @command && transport.container.info['Config']['Cmd'].join(' ') != @command
28
+ transport.container.delete(:force => true)
29
+ container = image.run(Shellwords.split(@command))
30
+ container.rename(machine_spec.reference['container_name'])
179
31
  machine_spec.reference['container_id'] = container.id
180
- machine_spec.save(action_handler)
181
- end
182
- container
183
- end
184
-
185
- def stringize_keys(hash)
186
- hash.each_with_object({}) do |(k,v),hash|
187
- v = stringize_keys(v) if v.is_a?(Hash)
188
- hash[k.to_s] = v
189
- end
190
- end
191
-
192
- def base_image(action_handler, base_image_value)
193
- case base_image_value
194
- when Hash
195
- params = base_image_value.dup
196
- if !params['fromImage']
197
- params['fromImage'] = params.delete('name')
198
- params['fromImage'] = "#{params['fromImage']}:#{params.delete('tag')}" if params['tag']
199
- end
200
- when String
201
- params = { 'fromImage' => base_image_value }
202
- when nil
203
- return nil
204
- else
205
- raise "Unexpected type #{base_image_value.class} for docker_options[:base_image]!"
206
- end
207
-
208
- image_name = params['fromImage']
209
- repo, image_name = params['fromImage'].split('/', 2) if params['fromImage'].include?('/')
210
-
211
- begin
212
- image = Docker::Image.get(image_name, {}, @connection)
213
- rescue Docker::Error::NotFoundError
214
- # If it's not found, pull it.
215
- action_handler.perform_action "pull #{params}" do
216
- image = Docker::Image.create(params, @connection)
217
- end
32
+ transport.container = container
218
33
  end
219
-
220
- image.id
34
+ machine_spec.save(action_handler)
221
35
  end
222
36
  end
223
37
  end
@@ -1,6 +1,5 @@
1
1
  require 'chef/provisioning/transport'
2
2
  require 'chef/provisioning/transport/ssh'
3
- require 'chef/provisioning/docker_driver/chef_zero_http_proxy'
4
3
  require 'docker'
5
4
  require 'archive/tar/minitar'
6
5
  require 'shellwords'
@@ -22,12 +21,11 @@ module DockerDriver
22
21
  attr_reader :config
23
22
  attr_accessor :container
24
23
 
25
- def execute(command, timeout: nil, keep_stdin_open: nil, tty: nil, detached: nil, **options)
24
+ def execute(command, options={})
26
25
  opts = {}
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?
26
+ if options[:keep_stdin_open]
27
+ opts[:stdin] = true
28
+ end
31
29
 
32
30
  command = Shellwords.split(command) if command.is_a?(String)
33
31
  Chef::Log.debug("execute #{command.inspect} on container #{container.id} with options #{opts}'")
@@ -81,7 +79,7 @@ module DockerDriver
81
79
  end
82
80
 
83
81
  def download_file(path, local_path)
84
- file = File.open(local_path, 'wb')
82
+ file = File.open(local_path, 'w')
85
83
  begin
86
84
  file.write(read_file(path))
87
85
  file.close
@@ -91,7 +89,7 @@ module DockerDriver
91
89
  end
92
90
 
93
91
  def upload_file(local_path, path)
94
- write_file(path, IO.read(local_path, mode: "rb"))
92
+ write_file(path, IO.read(local_path))
95
93
  end
96
94
 
97
95
  def make_url_available_to_remote(local_url)
@@ -117,35 +115,16 @@ module DockerDriver
117
115
  Chef::Log.debug("Session loop completed normally")
118
116
  end
119
117
  else
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 = ENV["PROXY_HOST_OVERRIDE"] ? ENV["PROXY_HOST_OVERRIDE"] : $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
-
118
+ # We are the host. The docker machine was run with --net=host, so it
119
+ # will be able to talk to us automatically.
148
120
  end
121
+ else
122
+ old_uri = uri.dup
123
+ # Find out our external network address of the URL and report it
124
+ # to the container in case it has no DNS (often the case).
125
+ uri.scheme = 'http' if 'chefzero' == uri.scheme && uri.host == 'localhost'
126
+ uri.host = Socket.getaddrinfo(uri.host, uri.scheme, nil, :STREAM)[0][3]
127
+ Chef::Log.debug("Looked up IP address of #{old_uri} and modified URL to point at it: #{uri}")
149
128
  end
150
129
 
151
130
  uri.to_s
@@ -161,6 +140,8 @@ module DockerDriver
161
140
  def available?
162
141
  end
163
142
 
143
+ private
144
+
164
145
  def is_local_machine(host)
165
146
  local_addrs = Socket.ip_address_list
166
147
  host_addrs = Addrinfo.getaddrinfo(host, nil)
@@ -171,7 +152,7 @@ module DockerDriver
171
152
  end
172
153
  end
173
154
 
174
- def docker_toolkit_transport(connection_url=nil)
155
+ def docker_toolkit_transport
175
156
  if !defined?(@docker_toolkit_transport)
176
157
  # Figure out which docker-machine this container is in
177
158
  begin
@@ -181,21 +162,18 @@ module DockerDriver
181
162
  @docker_toolkit_transport = nil
182
163
  return
183
164
  end
184
-
185
- connection_url ||= container.connection.url
186
-
187
165
  Chef::Log.debug("Found docker machines:")
188
166
  docker_machine = nil
189
167
  docker_machines.lines.each do |line|
190
168
  machine_name, machine_url = line.chomp.split(',', 2)
191
169
  Chef::Log.debug("- #{machine_name} at URL #{machine_url.inspect}")
192
- if machine_url == connection_url
193
- Chef::Log.debug("Docker machine #{machine_name} at URL #{machine_url} matches the container's URL #{connection_url}! Will use it for port forwarding.")
170
+ if machine_url == container.connection.url
171
+ Chef::Log.debug("Docker machine #{machine_name} at URL #{machine_url} matches the container's URL #{container.connection.url}! Will use it for port forwarding.")
194
172
  docker_machine = machine_name
195
173
  end
196
174
  end
197
175
  if !docker_machine
198
- Chef::Log.debug("Docker Toolkit is installed, but no Docker machine's URL matches #{connection_url.inspect}. Assuming docker must be installed as well ...")
176
+ Chef::Log.debug("Docker Toolkit is installed, but no Docker machine's URL matches #{container.connection.url.inspect}. Assuming docker must be installed as well ...")
199
177
  @docker_toolkit_transport = nil
200
178
  return
201
179
  end