docker-api 1.6.0 → 1.7.0

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +0 -1
  3. data/README.md +6 -7
  4. data/docker-api.gemspec +3 -4
  5. data/lib/docker.rb +10 -5
  6. data/lib/docker/connection.rb +2 -0
  7. data/lib/docker/container.rb +39 -4
  8. data/lib/docker/error.rb +6 -0
  9. data/lib/docker/event.rb +40 -0
  10. data/lib/docker/image.rb +37 -13
  11. data/lib/docker/util.rb +25 -1
  12. data/lib/docker/version.rb +2 -2
  13. data/spec/docker/container_spec.rb +37 -19
  14. data/spec/docker/event_spec.rb +79 -0
  15. data/spec/docker/image_spec.rb +89 -30
  16. data/spec/docker/util_spec.rb +83 -0
  17. data/spec/docker_spec.rb +47 -2
  18. data/spec/fixtures/{Dockerfile → build_from_dir/Dockerfile} +0 -0
  19. data/spec/fixtures/top/Dockerfile +2 -0
  20. data/spec/support/vcr.rb +1 -4
  21. data/spec/vcr/Docker/_authenticate_/with_valid_credentials/logs_in_and_sets_the_creds.yml +33 -0
  22. data/spec/vcr/Docker/_info/returns_the_info_as_a_Hash.yml +7 -7
  23. data/spec/vcr/Docker/_validate_version/when_nothing_is_raised/validate_version_/.yml +6 -6
  24. data/spec/vcr/Docker/_version/returns_the_version_as_a_Hash.yml +6 -6
  25. data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +27 -97
  26. data/spec/vcr/Docker_Container/_attach/yields_each_chunk.yml +18 -19
  27. data/spec/vcr/Docker_Container/_changes/returns_the_changes_as_an_array.yml +22 -22
  28. data/spec/vcr/Docker_Container/_commit/creates_a_new_Image_from_the_Container_s_changes.yml +18 -18
  29. data/spec/vcr/Docker_Container/_commit/if_run_is_passed_it_saves_the_command_in_the_image/saves_the_command.yml +178 -0
  30. data/spec/vcr/Docker_Container/_copy/when_the_file_does_not_exist/raises_an_error.yml +54 -24
  31. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_directory/yields_each_chunk_of_the_tarred_directory.yml +27 -60
  32. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_file/yields_each_chunk_of_the_tarred_file.yml +27 -60
  33. data/spec/vcr/Docker_Container/_create/when_the_Container_does_not_yet_exist/when_the_HTTP_request_returns_a_200/sets_the_id.yml +7 -7
  34. data/spec/vcr/Docker_Container/_delete/deletes_the_container.yml +16 -46
  35. data/spec/vcr/Docker_Container/_export/yields_each_chunk.yml +24 -17
  36. data/spec/vcr/Docker_Container/_json/returns_the_description_as_a_Hash.yml +14 -14
  37. data/spec/vcr/Docker_Container/_kill/kills_the_container.yml +36 -49
  38. data/spec/vcr/Docker_Container/_restart/restarts_the_container.yml +43 -43
  39. data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_does_not_return_status_code_of_0/raises_an_error.yml +17 -17
  40. data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_returns_a_status_code_of_0/creates_a_new_container_to_run_the_specified_command.yml +47 -47
  41. data/spec/vcr/Docker_Container/_start/starts_the_container.yml +25 -25
  42. data/spec/vcr/Docker_Container/_stop/stops_the_container.yml +40 -53
  43. data/spec/vcr/Docker_Container/_top/returns_the_top_commands_as_an_Array.yml +89 -25
  44. data/spec/vcr/Docker_Container/_wait/waits_for_the_command_to_finish.yml +17 -17
  45. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/and_a_command_runs_for_too_long/raises_a_ServerError.yml +12 -12
  46. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/sets_the_read_timeout_to_that_amount_of_time.yml +17 -17
  47. data/spec/vcr/Docker_Image/_all/materializes_each_Image_into_a_Docker_Image.yml +12 -12
  48. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_an_image_and_tags_it.yml +110 -0
  49. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/{builds_an_image.yml → without_query_parameters/builds_an_image.yml} +5 -5
  50. data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +7 -9
  51. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_no_query_parameters/builds_the_image.yml +121 -0
  52. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_the_image_and_tags_it.yml +151 -0
  53. data/spec/vcr/Docker_Image/_create/when_the_Image_does_not_yet_exist_and_the_body_is_a_Hash/sets_the_id.yml +5 -5
  54. data/spec/vcr/Docker_Image/_history/returns_the_history_of_the_Image.yml +10 -10
  55. data/spec/vcr/Docker_Image/_insert/inserts_the_url_s_file_into_a_new_Image.yml +53 -109
  56. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_exist/creates_a_new_Image_that_has_that_file.yml +32 -68
  57. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_not_exist/raises_an_error.yml +5 -5
  58. data/spec/vcr/Docker_Image/_insert_local/when_there_are_multiple_files_passed/creates_a_new_Image_that_has_each_file.yml +40 -68
  59. data/spec/vcr/Docker_Image/_json/returns_additional_information_about_image_image.yml +10 -10
  60. data/spec/vcr/Docker_Image/_push/pushes_the_Image.yml +161 -0
  61. data/spec/vcr/Docker_Image/_remove/removes_the_Image.yml +17 -17
  62. data/spec/vcr/Docker_Image/_run/when_the_argument_is_a_String/splits_the_String_by_spaces_and_creates_a_new_Container.yml +23 -24
  63. data/spec/vcr/Docker_Image/_run/when_the_argument_is_an_Array/creates_a_new_Container.yml +23 -24
  64. data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/command_configured_in_image/should_normally_show_result_if_image_has_Cmd_configured.yml +148 -0
  65. data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/no_command_configured_in_image/should_raise_an_error_if_no_command_is_specified.yml +68 -0
  66. data/spec/vcr/Docker_Image/_search/materializes_each_Image_into_a_Docker_Image.yml +13 -11
  67. data/spec/vcr/Docker_Image/_tag/tags_the_image_with_the_repo_name.yml +10 -10
  68. metadata +32 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73fb37b59d2a47b3db7d9c8a380f6e62ebdff7eb
4
- data.tar.gz: eb221917606fb54355f075be67c508597749c67e
3
+ metadata.gz: a4a13f5948a8df770804ade2a22dc3c31e7fc1b1
4
+ data.tar.gz: c3ac3bb3d1219fb34fbb1e91b4ee63e7fc4486b9
5
5
  SHA512:
6
- metadata.gz: 089db48c5b0bf31aab2d7a2136ea0a26818a93faa41e27ec1e838037cdf94eb7873b1b099a6cfd6a6f942de7c2bddf356e412a6417a1c66f3a0defebe2c6c9e1
7
- data.tar.gz: e6aa7b45e53e29e09130bf3f39722b5ec8eb8c537e6a01244aaf0411c65b729d38ee4603f7e7be28cb4b665feda025cf1f73e49e9e4b5b3f2be8b7a03585891b
6
+ metadata.gz: ff874b82925ea1dd68a05be8bdad589108967abc86d6a649efaf07606b35266284c4d596e0bdf603f56d7a5d8268a6f327a9e90311b0b7240cd9b517b909ac1f
7
+ data.tar.gz: abd742b0ee713c369d1034b90c96ed6e8c6ba48ccac6fa36129ecd36c5a8c6340860cf89486d90feaacebf105a30f6df8ec17e5954dd63c85cc73dcd0cf19953
data/.cane CHANGED
@@ -1 +0,0 @@
1
- --abc-max 13
data/README.md CHANGED
@@ -219,22 +219,21 @@ ff02::1 ip6-allnodes
219
219
  ff02::2 ip6-allrouters
220
220
  # => Docker::Container { :id => a1759f3e2873, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
221
221
 
222
-
223
-
224
222
  # Wait for the current command to finish executing. If an argument is given,
225
223
  # will timeout after that number of seconds. The default is one minute.
226
224
  container.wait(15)
227
225
  # => {'StatusCode'=>0}
228
226
 
229
227
  # Attach to the Container. Currently, the below options are the only valid ones.
230
- # By default, :stream and :stdout are set.
228
+ # By default, :stream, :stdout, and :stderr are set.
231
229
  container.attach(:stream => true, :stdout => true, :stderr => true, :logs => true)
232
- # => "bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nselinux\nsrv\nsys\ntmp\nusr\nvar"
230
+ # => [["bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nselinux\nsrv\nsys\ntmp\nusr\nvar", []]
233
231
 
234
232
  # If you wish to stream the attach method, a block may be supplied.
235
- container = Docker::Container.create('Image' => 'base', 'Cmd' => %[find / -name *])
236
- container.tap(&:start).attach { |chunk| puts chunk }
237
- # => nil
233
+ container = Docker::Container.create('Image' => 'base', 'Cmd' => ['find / -name *'])
234
+ container.tap(&:start).attach { |stream, chunk| puts "#{stream}: #{chunk}" }
235
+ stderr: 2013/10/30 17:16:24 Unable to locate find / -name *
236
+ # => [[], ["2013/10/30 17:16:24 Unable to locate find / -name *\n"]]
238
237
 
239
238
  # Create an Image from a Container's changes.
240
239
  container.commit
data/docker-api.gemspec CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../lib/docker/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Swipely, Inc."]
6
- gem.email = %w{tomhulihan@swipely.com bright@swipely.com}
6
+ gem.email = %w{tomhulihan@swipely.com bright@swipely.com toddlunter@swipely.com}
7
7
  gem.description = %q{A simple REST client for the Docker Remote API}
8
8
  gem.summary = %q{A simple REST client for the Docker Remote API}
9
9
  gem.homepage = 'https://github.com/swipely/docker-api'
@@ -14,14 +14,13 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "docker-api"
15
15
  gem.require_paths = %w{lib}
16
16
  gem.version = Docker::VERSION
17
- gem.add_dependency 'excon', '>= 0.27.3'
17
+ gem.add_dependency 'excon', '>= 0.28'
18
18
  gem.add_dependency 'json'
19
19
  gem.add_dependency 'archive-tar-minitar'
20
20
  gem.add_development_dependency 'rake'
21
21
  gem.add_development_dependency 'rspec'
22
22
  gem.add_development_dependency 'cane'
23
23
  gem.add_development_dependency 'pry'
24
- gem.add_development_dependency 'webmock', '>= 1.11.0'
25
- gem.add_development_dependency 'vcr', '>= 2.4.0'
24
+ gem.add_development_dependency 'vcr', '>= 2.7.0'
26
25
  gem.add_development_dependency 'simplecov'
27
26
  end
data/lib/docker.rb CHANGED
@@ -2,13 +2,14 @@ require 'cgi'
2
2
  require 'json'
3
3
  require 'excon'
4
4
  require 'tempfile'
5
+ require 'base64'
5
6
  require 'rubygems/package'
6
7
  require 'archive/tar/minitar'
7
8
 
8
9
  # The top-level module for this gem. It's purpose is to hold global
9
10
  # configuration variables that are used as defaults in other classes.
10
11
  module Docker
11
- attr_reader :creds
12
+ attr_accessor :creds
12
13
 
13
14
  def default_socket_url
14
15
  'unix:///var/run/docker.sock'
@@ -56,9 +57,12 @@ module Docker
56
57
 
57
58
  # Login to the Docker registry.
58
59
  def authenticate!(options = {})
59
- @creds = options.to_json
60
- connection.post(:path => '/auth', :body => @creds)
60
+ creds = options.to_json
61
+ connection.post('/auth', {}, :body => creds)
62
+ @creds = creds
61
63
  true
64
+ rescue Docker::Error::ServerError, Docker::Error::UnauthorizedError
65
+ raise Docker::Error::AuthenticationError
62
66
  end
63
67
 
64
68
  # When the correct version of Docker is installed, returns true. Otherwise,
@@ -71,8 +75,8 @@ module Docker
71
75
  end
72
76
 
73
77
  module_function :default_socket_url, :env_url, :url, :url=, :options,
74
- :options=, :connection, :reset_connection!, :version,
75
- :info, :authenticate!, :validate_version!
78
+ :options=, :creds, :creds=, :connection, :reset_connection!,
79
+ :version, :info, :authenticate!, :validate_version!
76
80
  end
77
81
 
78
82
  require 'docker/version'
@@ -81,3 +85,4 @@ require 'docker/util'
81
85
  require 'docker/connection'
82
86
  require 'docker/container'
83
87
  require 'docker/image'
88
+ require 'docker/event'
@@ -36,6 +36,8 @@ class Docker::Connection
36
36
  resource.request(compile_request_params(*args, &block)).body
37
37
  rescue Excon::Errors::BadRequest => ex
38
38
  raise ClientError, ex.message
39
+ rescue Excon::Errors::Unauthorized => ex
40
+ raise UnauthorizedError, ex.message
39
41
  rescue Excon::Errors::InternalServerError => ex
40
42
  raise ServerError, ex.message
41
43
  rescue Excon::Errors::Timeout => ex
@@ -50,14 +50,31 @@ class Docker::Container
50
50
 
51
51
  # Attach to a container's standard streams / logs.
52
52
  def attach(options = {}, &block)
53
- opts = { :stream => true, :stdout => true }.merge(options)
54
- connection.post(path_for(:attach), opts, :response_block => block)
53
+ opts = {
54
+ :stream => true, :stdout => true, :stderr => true
55
+ }.merge(options)
56
+ # Creates list to store stdout and stderr messages
57
+ msgs = [[],[]]
58
+ connection.post(
59
+ path_for(:attach),
60
+ opts,
61
+ :response_block => attach_for(block, msgs)
62
+ )
63
+ msgs
55
64
  end
56
65
 
57
66
  # Create an Image from a Container's change.s
58
67
  def commit(options = {})
59
68
  options.merge!('container' => self.id[0..7])
60
- hash = Docker::Util.parse_json(connection.post('/commit', options))
69
+ # [code](https://github.com/dotcloud/docker/blob/v0.6.3/commands.go#L1115)
70
+ # Based on the link, the config passed as run, needs to be passed as the
71
+ # body of the post so capture it, remove from the options, and pass it via
72
+ # the post body
73
+ config = options.delete('run')
74
+ hash = Docker::Util.parse_json(connection.post('/commit',
75
+ options,
76
+ :body => config.to_json)
77
+ )
61
78
  Docker::Image.send(:new, self.connection, hash['Id'])
62
79
  end
63
80
 
@@ -124,6 +141,24 @@ class Docker::Container
124
141
  "/containers/#{self.id}/#{resource}"
125
142
  end
126
143
 
127
- private :path_for
144
+ # Method that takes chunks and calls the attached block for each mux'd message
145
+ def attach_for(block, msg_stack)
146
+ lambda do |c,r,t|
147
+ stdout_msgs, stderr_msgs = Docker::Util.decipher_messages(c)
148
+ msg_stack[0] += stdout_msgs
149
+ msg_stack[1] += stderr_msgs
150
+
151
+ unless block.nil?
152
+ stdout_msgs.each do |msg|
153
+ block.call(:stdout, msg)
154
+ end
155
+ stderr_msgs.each do |msg|
156
+ block.call(:stderr, msg)
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ private :path_for, :attach_for
128
163
  private_class_method :new
129
164
  end
data/lib/docker/error.rb CHANGED
@@ -11,6 +11,9 @@ module Docker::Error
11
11
  # Raised when a request returns a 400.
12
12
  class ClientError < DockerError; end
13
13
 
14
+ # Raised when a request returns a 401.
15
+ class UnauthorizedError < DockerError; end
16
+
14
17
  # Raised when a request returns a 500.
15
18
  class ServerError < DockerError; end
16
19
 
@@ -22,4 +25,7 @@ module Docker::Error
22
25
 
23
26
  # Raised when a request times out.
24
27
  class TimeoutError < DockerError; end
28
+
29
+ # Raised when login fails.
30
+ class AuthenticationError < DockerError; end
25
31
  end
@@ -0,0 +1,40 @@
1
+ # This class represents a Docker Image.
2
+ class Docker::Event
3
+ include Docker::Error
4
+
5
+ attr_accessor :status, :id, :from, :time
6
+
7
+ def initialize(status, id, from, time)
8
+ @status, @id, @from, @time = status, id, from, time
9
+ end
10
+
11
+ def to_s
12
+ "Docker::Event { :status => #{self.status}, :id => #{self.id}, "\
13
+ ":from => #{self.from}, :time => #{self.time} }"
14
+ end
15
+
16
+ class << self
17
+ include Docker::Error
18
+
19
+ def stream(opts = {}, conn = Docker.connection, &block)
20
+ conn.get('/events', opts, :response_block => lambda { |b, r, t|
21
+ block.call(new_event(b, r, t))
22
+ })
23
+ end
24
+
25
+ def since(since, opts = {}, conn = Docker.connection, &block)
26
+ stream(opts.merge(:since => since), conn, &block)
27
+ end
28
+
29
+ def new_event(body, remaining, total)
30
+ return if body.nil? || body.empty?
31
+ json = Docker::Util.parse_json(body)
32
+ Docker::Event.new(
33
+ json['status'],
34
+ json['id'],
35
+ json['from'],
36
+ json['time']
37
+ )
38
+ end
39
+ end
40
+ end
data/lib/docker/image.rb CHANGED
@@ -15,16 +15,32 @@ class Docker::Image
15
15
 
16
16
  # Given a command and optional list of streams to attach to, run a command on
17
17
  # an Image. This will not modify the Image, but rather create a new Container
18
- # to run the Image.
19
- def run(cmd)
20
- cmd = cmd.split(/\s+/) if cmd.is_a?(String)
21
- Docker::Container.create({ 'Image' => self.id, 'Cmd' => cmd }, connection)
22
- .tap(&:start!)
18
+ # to run the Image. If the image has an embedded config, no command is
19
+ # necessary, but it will fail with 500 if no config is saved with the image
20
+ def run(cmd=nil)
21
+ opts = { 'Image' => self.id }
22
+ opts["Cmd"] = cmd.split(/\s+/) if cmd.is_a?(String)
23
+ begin
24
+ Docker::Container.create(opts, connection)
25
+ .tap(&:start!)
26
+ rescue ServerError
27
+ if cmd
28
+ raise ServerError, "Docker Server Error."
29
+ else
30
+ raise ServerError, "No command specified."
31
+ end
32
+ end
23
33
  end
24
34
 
25
35
  # Push the Image to the Docker registry.
26
- def push(options = {})
27
- connection.post(path_for(:push), options, :body => Docker.creds)
36
+ def push(creds = nil, options = {})
37
+ credentials = (creds.nil?) ? Docker.creds : creds.to_json
38
+ headers = Docker::Util.build_auth_header(credentials)
39
+ connection.post(
40
+ path_for(:push),
41
+ options,
42
+ :headers => headers
43
+ )
28
44
  self
29
45
  end
30
46
 
@@ -83,8 +99,14 @@ class Docker::Image
83
99
  include Docker::Error
84
100
 
85
101
  # Create a new Image.
86
- def create(opts = {}, conn = Docker.connection)
87
- instance = new(conn)
102
+ def create(opts = {}, creds = nil, conn = Docker.connection)
103
+ credentials = (creds.nil?) ? creds.to_json : Docker.creds
104
+ headers = if credentials.nil?
105
+ Docker::Util.build_auth_header(credentials)
106
+ else
107
+ {}
108
+ end
109
+ instance = new(conn, {}, :headers => headers)
88
110
  conn.post('/images/create', opts)
89
111
  id = opts['repo'] ? "#{opts['repo']}/#{opts['tag']}" : opts['fromImage']
90
112
  if (instance.id = id).nil?
@@ -122,19 +144,21 @@ class Docker::Image
122
144
  end
123
145
 
124
146
  # Given a Dockerfile as a string, builds an Image.
125
- def build(commands, connection = Docker.connection)
147
+ def build(commands, opts = {}, connection = Docker.connection)
126
148
  body = connection.post(
127
- '/build', {},
149
+ '/build', opts,
128
150
  :body => Docker::Util.create_tar('Dockerfile' => commands)
129
151
  )
130
152
  new(connection, Docker::Util.extract_id(body))
153
+ rescue Docker::Error::ServerError
154
+ raise Docker::Error::UnexpectedResponseError
131
155
  end
132
156
 
133
157
  # Given a directory that contains a Dockerfile, builds an Image.
134
- def build_from_dir(dir, connection = Docker.connection)
158
+ def build_from_dir(dir, opts = {}, connection = Docker.connection)
135
159
  tar = Docker::Util.create_dir_tar(dir)
136
160
  body = connection.post(
137
- '/build', {},
161
+ '/build', opts,
138
162
  :headers => { 'Content-Type' => 'application/tar',
139
163
  'Transfer-Encoding' => 'chunked' }
140
164
  ) { tar.read(Excon.defaults[:chunk_size]).to_s }
data/lib/docker/util.rb CHANGED
@@ -18,7 +18,7 @@ module Docker::Util
18
18
  tar.add_file(file_name, 0640) { |tar_file| tar_file.write(input) }
19
19
  end
20
20
  end
21
- output.tap(&:rewind)
21
+ output.tap(&:rewind).string
22
22
  end
23
23
 
24
24
  def create_dir_tar(directory)
@@ -57,4 +57,28 @@ module Docker::Util
57
57
 
58
58
  file_hash
59
59
  end
60
+
61
+ def build_auth_header(credentials)
62
+ credentials = credentials.to_json if credentials.is_a?(Hash)
63
+ { 'X-Registry-Auth' => Base64.encode64(credentials).gsub(/\n/, '') }
64
+ end
65
+
66
+ # Method to break apart application/vnd.docker.raw-stream headers
67
+ def decipher_messages(body)
68
+ raw_text = body.dup
69
+ stdout_messages = []
70
+ stderr_messages = []
71
+ while !raw_text.empty?
72
+ header = raw_text.slice!(0,8)
73
+ next if header.nil?
74
+ length = header[4..7].chars
75
+ .map { |c| c.getbyte(0) }
76
+ .inject(0) { |total, curr| (total << 8) + curr }
77
+ message = raw_text.slice!(0,length)
78
+ stdout_messages << message if header.getbyte(0) == 1
79
+ stderr_messages << message if header.getbyte(0) == 2
80
+ end
81
+
82
+ [stdout_messages, stderr_messages]
83
+ end
60
84
  end
@@ -1,7 +1,7 @@
1
1
  module Docker
2
2
  # The version of the docker-api gem.
3
- VERSION = '1.6.0'
3
+ VERSION = '1.7.0'
4
4
 
5
5
  # The version of the compatible Docker remote API.
6
- API_VERSION = '1.4'
6
+ API_VERSION = '1.6'
7
7
  end
@@ -58,16 +58,14 @@ describe Docker::Container do
58
58
  end
59
59
 
60
60
  describe '#top' do
61
- subject {
62
- described_class.create(
63
- 'Cmd' => %w[while true; do; done;],
64
- 'Image' => 'base'
65
- )
61
+ let(:dir) {
62
+ File.join(File.dirname(__FILE__), '..', 'fixtures', 'top')
66
63
  }
67
- let(:top) { subject.top }
64
+ let(:image) { Docker::Image.build_from_dir(dir) }
65
+ let(:top) { sleep 1; container.top }
66
+ let!(:container) { image.run('/while') }
68
67
 
69
- before { subject.start }
70
- after { subject.kill }
68
+ after { container.kill; image.remove }
71
69
 
72
70
  it 'returns the top commands as an Array', :vcr do
73
71
  top.should be_a Array
@@ -80,7 +78,7 @@ describe Docker::Container do
80
78
  subject {
81
79
  Docker::Image.create(
82
80
  'fromImage' => 'base'
83
- ).run('touch /test').tap { |c| c.start.wait }
81
+ ).run('touch /test').tap { |c| c.wait }
84
82
  }
85
83
 
86
84
  context 'when the file does not exist' do
@@ -120,8 +118,7 @@ describe Docker::Container do
120
118
  it 'yields each chunk', :vcr do
121
119
  first = nil
122
120
  subject.export do |chunk|
123
- first = chunk
124
- break
121
+ first ||= chunk
125
122
  end
126
123
  first[257..261].should == "ustar" # Make sure the export is a tar.
127
124
  end
@@ -133,10 +130,11 @@ describe Docker::Container do
133
130
  before { subject.start }
134
131
 
135
132
  it 'yields each chunk', :vcr do
136
- subject.attach { |chunk|
137
- chunk.should == "/\n"
138
- break
139
- }
133
+ chunk = nil
134
+ subject.attach do |stream, c|
135
+ chunk ||= c
136
+ end
137
+ expect(chunk).to eq("/\n")
140
138
  end
141
139
  end
142
140
 
@@ -277,6 +275,14 @@ describe Docker::Container do
277
275
  image.should be_a Docker::Image
278
276
  image.id.should_not be_nil
279
277
  end
278
+
279
+ context 'if run is passed, it saves the command in the image', :vcr do
280
+ let(:image) { subject.commit('run' => {"Cmd" => %w[pwd]}) }
281
+ it 'saves the command' do
282
+ expect(image.run.attach).to eql [["/\n"],[]]
283
+ end
284
+ end
285
+
280
286
  end
281
287
 
282
288
  describe '.create' do
@@ -284,8 +290,14 @@ describe Docker::Container do
284
290
 
285
291
  context 'when the Container does not yet exist' do
286
292
  context 'when the HTTP request does not return a 200' do
287
- before { Excon.stub({ :method => :post }, { :status => 400 }) }
288
- after { Excon.stubs.shift }
293
+ before do
294
+ Docker.options = { :mock => true }
295
+ Excon.stub({ :method => :post }, { :status => 400 })
296
+ end
297
+ after do
298
+ Excon.stubs.shift
299
+ Docker.options = {}
300
+ end
289
301
 
290
302
  it 'raises an error' do
291
303
  expect { subject.create }.to raise_error(Docker::Error::ClientError)
@@ -329,8 +341,14 @@ describe Docker::Container do
329
341
  subject { described_class }
330
342
 
331
343
  context 'when the HTTP response is not a 200' do
332
- before { Excon.stub({ :method => :get }, { :status => 500 }) }
333
- after { Excon.stubs.shift }
344
+ before do
345
+ Docker.options = { :mock => true }
346
+ Excon.stub({ :method => :get }, { :status => 500 })
347
+ end
348
+ after do
349
+ Excon.stubs.shift
350
+ Docker.options = {}
351
+ end
334
352
 
335
353
  it 'raises an error' do
336
354
  expect { subject.all }