docker-api 1.8.0 → 1.8.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
2
  SHA1:
3
- metadata.gz: dc5ba28fab5aed18ec66531e1b33aa0cbec86e12
4
- data.tar.gz: b860c92de1e24af1f431399b07ee529f7c1a73dc
3
+ metadata.gz: e17294801992ba4c21ef2a8991aa45dac202d891
4
+ data.tar.gz: aa1b611592bec9e49568eb6f9c4e3bcf9cdeb8ae
5
5
  SHA512:
6
- metadata.gz: 3ab3594b2951e5789078ea05081a9f9dfdc595cd8b2de06cab2ca75c877e0f5936184076de080d8ce6d7c3aada2ce1a7244b0f76ae0042cff8997fdcce26836d
7
- data.tar.gz: a239960f224a37afc14432b7e450dd26b374e3dea52d25b83fa161f204491efc40375f7343b3701f52eaff6356120f3c5a3815e3d1ba119df5c29188ec38b4af
6
+ metadata.gz: 656fe22d8ec340dc7044d76659d72b6853657613a3f2f74a9cca40c3468b7d7cb95e76c6e3103288efe98b9de90756246a2716fac00ceeb7b837d007a05fdc37
7
+ data.tar.gz: 501c1dd9fa9bcdf678ae605132d3db8ef2ae2e328a4f15309089bc51fe27d4ba72ea26802c3d6a7aba548c607024788e62a69784b00fa5897078da95052e9c32
data/README.md CHANGED
@@ -2,7 +2,7 @@ docker-api
2
2
  ==========
3
3
  [![Gem Version](https://badge.fury.io/rb/docker-api.png)](http://badge.fury.io/rb/docker-api) [![travis-ci](https://travis-ci.org/swipely/docker-api.png?branch=master)](https://travis-ci.org/swipely/docker-api) [![Code Climate](https://codeclimate.com/github/swipely/docker-api.png)](https://codeclimate.com/github/swipely/docker-api) [![Dependency Status](https://gemnasium.com/swipely/docker-api.png)](https://gemnasium.com/swipely/docker-api)
4
4
 
5
- This gem provides an object-oriented interface to the [Docker Remote API](http://docs.docker.io/en/latest/api/docker_remote_api_v1.4/). Every method listed there is implemented, with the exception of attaching to the STDIN of a Container. At the time of this writing, docker-api is meant to interface with Docker version 0.6.*.
5
+ This gem provides an object-oriented interface to the [Docker Remote API](http://docs.docker.io/en/latest/api/docker_remote_api_v1.4/). Every method listed there is implemented, with the exception of attaching to the STDIN of a Container. At the time of this writing, docker-api is meant to interface with Docker version 0.8.*.
6
6
 
7
7
  Installation
8
8
  ------------
@@ -20,6 +20,7 @@ module Docker
20
20
  autoload :Image, 'docker/image'
21
21
  autoload :Messages, 'docker/messages'
22
22
  autoload :Util, 'docker/util'
23
+ autoload :Base, 'docker/base'
23
24
 
24
25
  def default_socket_url
25
26
  'unix:///var/run/docker.sock'
@@ -30,7 +31,12 @@ module Docker
30
31
  end
31
32
 
32
33
  def url
33
- @url ||= ENV['DOCKER_URL'] || default_socket_url
34
+ @url ||= ENV['DOCKER_URL'] || ENV['DOCKER_HOST'] || default_socket_url
35
+ # docker uses a default notation tcp:// which means tcp://localhost:4243
36
+ if @url == 'tcp://'
37
+ @url = 'tcp://localhost:4243'
38
+ end
39
+ @url
34
40
  end
35
41
 
36
42
  def options
@@ -0,0 +1,24 @@
1
+ # This class is a base class for Docker Container and Image.
2
+ # It is implementing accessor methods for the models attributes.
3
+ class Docker::Base
4
+ include Docker::Error
5
+
6
+ attr_accessor :connection, :info
7
+ attr_reader :id
8
+
9
+ # The private new method accepts a connection and optional id.
10
+ def initialize(connection, hash={})
11
+ unless connection.is_a?(Docker::Connection)
12
+ raise ArgumentError, "Expected a Docker::Connection, got: #{connection}."
13
+ end
14
+ normalize_hash(hash)
15
+ @connection, @info, @id = connection, hash, hash['id']
16
+ raise ArgumentError, "Must have id, got: #{hash}" unless @id
17
+ end
18
+
19
+ # The docker-api will some time return "ID" other times it will return "Id"
20
+ # and other times it will return "id". This method normalize it to "id"
21
+ def normalize_hash(hash)
22
+ hash["id"] ||= hash.delete("ID") || hash.delete("Id")
23
+ end
24
+ end
@@ -1,18 +1,6 @@
1
1
  # This class represents a Docker Container. It's important to note that nothing
2
2
  # is cached so that the information is always up to date.
3
- class Docker::Container
4
- include Docker::Error
5
-
6
- attr_accessor :id, :connection
7
-
8
- # The private new method accepts a connection and optional id.
9
- def initialize(connection, id = nil)
10
- if connection.is_a?(Docker::Connection)
11
- @connection, @id = connection, id
12
- else
13
- raise ArgumentError, "Expected a Docker::Connection, got: #{connection}."
14
- end
15
- end
3
+ class Docker::Container < Docker::Base
16
4
 
17
5
  # Return a List of Hashes that represents the top running processes.
18
6
  def top(opts = {})
@@ -74,10 +62,10 @@ class Docker::Container
74
62
  hash = Docker::Util.parse_json(connection.post('/commit',
75
63
  options,
76
64
  :body => config.to_json))
77
- Docker::Image.send(:new, self.connection, hash['Id'])
65
+ Docker::Image.send(:new, self.connection, hash)
78
66
  end
79
67
 
80
- # Return a String represntation of the Container.
68
+ # Return a String representation of the Container.
81
69
  def to_s
82
70
  "Docker::Container { :id => #{self.id}, :connection => #{self.connection} }"
83
71
  end
@@ -104,11 +92,12 @@ class Docker::Container
104
92
  end
105
93
  end
106
94
 
107
- # delete container
108
- def delete(options = {})
95
+ # remove container
96
+ def remove(options = {})
109
97
  connection.delete("/containers/#{self.id}", options)
110
98
  nil
111
99
  end
100
+ alias_method :delete, :remove
112
101
 
113
102
  def copy(path, &block)
114
103
  connection.post(path_for(:copy), {},
@@ -120,29 +109,25 @@ class Docker::Container
120
109
 
121
110
  # Create a new Container.
122
111
  def self.create(opts = {}, conn = Docker.connection)
123
- instance = new(conn)
124
112
  name = opts.delete('name')
125
113
  query = {}
126
114
  query['name'] = name if name
127
115
  resp = conn.post('/containers/create', query, :body => opts.to_json)
128
- if (instance.id = Docker::Util.parse_json(resp)['Id']).nil?
129
- raise UnexpectedResponseError, 'Create response did not contain an Id'
130
- else
131
- instance
132
- end
116
+ hash = Docker::Util.parse_json(resp) || {}
117
+ new(conn, hash)
133
118
  end
134
119
 
135
120
  # Return the container with specified ID
136
121
  def self.get(id, opts = {}, conn = Docker.connection)
137
122
  container_json = conn.get("/containers/#{URI.encode(id)}/json", opts)
138
123
  hash = Docker::Util.parse_json(container_json) || {}
139
- new(conn, hash['ID'])
124
+ new(conn, hash)
140
125
  end
141
126
 
142
127
  # Return all of the Containers.
143
128
  def self.all(opts = {}, conn = Docker.connection)
144
129
  hashes = Docker::Util.parse_json(conn.get('/containers/json', opts)) || []
145
- hashes.map { |hash| new(conn, hash['Id']) }
130
+ hashes.map { |hash| new(conn, hash) }
146
131
  end
147
132
 
148
133
  # Convenience method to return the path for a particular resource.
@@ -1,17 +1,5 @@
1
1
  # This class represents a Docker Image.
2
- class Docker::Image
3
- include Docker::Error
4
-
5
- attr_accessor :id, :connection, :info
6
-
7
- # The private new method accepts a connection and optional id.
8
- def initialize(connection, id = nil, info = {})
9
- if connection.is_a?(Docker::Connection)
10
- @connection, @id, @info = connection, id, info
11
- else
12
- raise ArgumentError, "Expected a Docker::Connection, got: #{connection}."
13
- end
14
- end
2
+ class Docker::Image < Docker::Base
15
3
 
16
4
  # Given a command and optional list of streams to attach to, run a command on
17
5
  # an Image. This will not modify the Image, but rather create a new Container
@@ -36,10 +24,7 @@ class Docker::Image
36
24
  def push(creds = nil, options = {})
37
25
  repository = self.info['RepoTags'].first.split(/:/)[0] rescue nil
38
26
 
39
- unless repository
40
- raise ArgumentError
41
- "Image does not have a name to push, got: #{repository}."
42
- end
27
+ raise ArgumentError, "Image does not have a name to push." unless repository
43
28
 
44
29
  credentials = creds || Docker.creds
45
30
  headers = Docker::Util.build_auth_header(credentials)
@@ -53,7 +38,10 @@ class Docker::Image
53
38
 
54
39
  # Tag the Image.
55
40
  def tag(opts = {})
56
- Docker::Util.parse_json(connection.post(path_for(:tag), opts))
41
+ self.info['RepoTags'] ||= []
42
+ connection.post(path_for(:tag), opts)
43
+ repo = opts['repo'] || opts[:repo]
44
+ self.info['RepoTags'] << (repo.include?(?:) ? repo : "#{repo}:latest")
57
45
  end
58
46
 
59
47
  # Insert a file into the Image, returns a new Image that has that file.
@@ -62,7 +50,7 @@ class Docker::Image
62
50
  if (id = body.match(/{"status":"([a-f0-9]+)"}\z/)).nil? || id[1].empty?
63
51
  raise UnexpectedResponseError, "Could not find Id in '#{body}'"
64
52
  else
65
- self.class.send(:new, connection, id[1])
53
+ self.class.send(:new, connection, 'id' => id[1])
66
54
  end
67
55
  end
68
56
 
@@ -80,13 +68,14 @@ class Docker::Image
80
68
 
81
69
  tar = Docker::Util.create_tar(file_hash)
82
70
  body = connection.post('/build', opts, :body => tar)
83
- self.class.send(:new, connection, Docker::Util.extract_id(body))
71
+ self.class.send(:new, connection, 'id' => Docker::Util.extract_id(body))
84
72
  end
85
73
 
86
74
  # Remove the Image from the server.
87
75
  def remove
88
76
  connection.delete("/images/#{self.id}")
89
77
  end
78
+ alias_method :delete, :remove
90
79
 
91
80
  # Return a String representation of the Image.
92
81
  def to_s
@@ -103,7 +92,6 @@ class Docker::Image
103
92
  end
104
93
 
105
94
  class << self
106
- include Docker::Error
107
95
 
108
96
  # Create a new Image.
109
97
  def create(opts = {}, creds = nil, conn = Docker.connection)
@@ -113,27 +101,22 @@ class Docker::Image
113
101
  else
114
102
  {}
115
103
  end
116
- instance = new(conn, {}, :headers => headers)
117
104
  conn.post('/images/create', opts)
118
105
  id = opts['repo'] ? "#{opts['repo']}/#{opts['tag']}" : opts['fromImage']
119
- if (instance.id = id).nil?
120
- raise UnexpectedResponseError, 'Create response did not contain an Id'
121
- else
122
- instance
123
- end
106
+ new(conn, 'id' => id, :headers => headers)
124
107
  end
125
108
 
126
109
  # Return a specific image.
127
110
  def get(id, opts = {}, conn = Docker.connection)
128
111
  image_json = conn.get("/images/#{URI.encode(id)}/json", opts)
129
112
  hash = Docker::Util.parse_json(image_json) || {}
130
- new(conn, hash['id'])
113
+ new(conn, hash)
131
114
  end
132
115
 
133
116
  # Return every Image.
134
117
  def all(opts = {}, conn = Docker.connection)
135
118
  hashes = Docker::Util.parse_json(conn.get('/images/json', opts)) || []
136
- hashes.map { |hash| new(conn, hash['Id'], hash.tap{|h| h.delete('Id')}) }
119
+ hashes.map { |hash| new(conn, hash) }
137
120
  end
138
121
 
139
122
  # Given a query like `{ :term => 'sshd' }`, queries the Docker Registry for
@@ -141,7 +124,7 @@ class Docker::Image
141
124
  def search(query = {}, connection = Docker.connection)
142
125
  body = connection.get('/images/search', query)
143
126
  hashes = Docker::Util.parse_json(body) || []
144
- hashes.map { |hash| new(connection, hash['name']) }
127
+ hashes.map { |hash| new(connection, 'id' => hash['name']) }
145
128
  end
146
129
 
147
130
  # Import an Image from the output of Docker::Container#export.
@@ -153,7 +136,7 @@ class Docker::Image
153
136
  :headers => { 'Content-Type' => 'application/tar',
154
137
  'Transfer-Encoding' => 'chunked' }
155
138
  ) { io.read(Excon.defaults[:chunk_size]).to_s }
156
- new(connection, Docker::Util.parse_json(body)['status'])
139
+ new(connection, 'id'=> Docker::Util.parse_json(body)['status'])
157
140
  end
158
141
  end
159
142
 
@@ -165,7 +148,7 @@ class Docker::Image
165
148
  :body => Docker::Util.create_tar('Dockerfile' => commands),
166
149
  :response_block => response_block_for_build(body, &block)
167
150
  )
168
- new(connection, Docker::Util.extract_id(body))
151
+ new(connection, 'id' => Docker::Util.extract_id(body))
169
152
  rescue Docker::Error::ServerError
170
153
  raise Docker::Error::UnexpectedResponseError
171
154
  end
@@ -185,7 +168,7 @@ class Docker::Image
185
168
  'Transfer-Encoding' => 'chunked' },
186
169
  :response_block => response_block_for_build(body, &block)
187
170
  ) { tar.read(Excon.defaults[:chunk_size]).to_s }
188
- new(connection, Docker::Util.extract_id(body))
171
+ new(connection, 'id' => Docker::Util.extract_id(body))
189
172
  ensure
190
173
  tar.close unless tar.nil?
191
174
  end
@@ -1,6 +1,6 @@
1
1
  module Docker
2
2
  # The version of the docker-api gem.
3
- VERSION = '1.8.0'
3
+ VERSION = '1.8.1'
4
4
 
5
5
  # The version of the compatible Docker remote API.
6
6
  API_VERSION = '1.8'
@@ -4,7 +4,9 @@ require 'spec_helper'
4
4
  # Docker daemon and have the base Image pulled.
5
5
  describe Docker::Container do
6
6
  describe '#to_s' do
7
- subject { described_class.send(:new, Docker.connection, rand(10000).to_s) }
7
+ subject {
8
+ described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
9
+ }
8
10
 
9
11
  let(:id) { 'bf119e2' }
10
12
  let(:connection) { Docker.connection }
@@ -2,13 +2,13 @@ require 'spec_helper'
2
2
 
3
3
  describe Docker::Image do
4
4
  describe '#to_s' do
5
- subject { described_class.new(Docker.connection, id, info) }
5
+ subject { described_class.new(Docker.connection, info) }
6
6
 
7
7
  let(:id) { 'bf119e2' }
8
8
  let(:connection) { Docker.connection }
9
9
 
10
10
  let(:info) do
11
- {"Repository" => "base", "Tag" => "latest",
11
+ {"id" => "bf119e2", "Repository" => "base", "Tag" => "latest",
12
12
  "Created" => 1364102658, "Size" => 24653, "VirtualSize" => 180116135}
13
13
  end
14
14
 
@@ -133,8 +133,8 @@ describe Docker::Image do
133
133
  subject { described_class.create('fromImage' => 'base') }
134
134
 
135
135
  it 'tags the image with the repo name', :vcr do
136
- expect { subject.tag(:repo => 'base2', :force => true) }
137
- .to_not raise_error
136
+ subject.tag(:repo => 'base2', :force => true)
137
+ subject.info['RepoTags'].should include('base2:latest')
138
138
  end
139
139
  end
140
140
 
@@ -5,6 +5,7 @@ describe Docker do
5
5
 
6
6
  before do
7
7
  ENV['DOCKER_URL'] = nil
8
+ ENV['DOCKER_HOST'] = nil
8
9
  end
9
10
 
10
11
  it { should be_a Module }
@@ -30,6 +31,38 @@ describe Docker do
30
31
  its(:url) { should == 'unixs:///var/run/not-docker.sock' }
31
32
  its(:connection) { should be_a Docker::Connection }
32
33
  end
34
+
35
+ context "when the DOCKER_HOST is set and uses default tcp://" do
36
+ before do
37
+ ENV['DOCKER_HOST'] = 'tcp://'
38
+ end
39
+
40
+ its(:options) { {} }
41
+ its(:url) { should == 'tcp://localhost:4243' }
42
+ its(:connection) { should be_a Docker::Connection }
43
+ end
44
+
45
+ context "when the DOCKER_HOST ENV variables is set" do
46
+ before do
47
+ ENV['DOCKER_HOST'] = 'tcp://someserver:8103'
48
+ end
49
+
50
+ its(:options) { {} }
51
+ its(:url) { should == 'tcp://someserver:8103' }
52
+ its(:connection) { should be_a Docker::Connection }
53
+ end
54
+
55
+ context "DOCKER_URL should take precedence over DOCKER_HOST" do
56
+ before do
57
+ ENV['DOCKER_HOST'] = 'tcp://someserver:8103'
58
+ ENV['DOCKER_URL'] = 'tcp://someotherserver:8103'
59
+
60
+ end
61
+
62
+ its(:options) { {} }
63
+ its(:url) { should == 'tcp://someotherserver:8103' }
64
+ its(:connection) { should be_a Docker::Connection }
65
+ end
33
66
  end
34
67
 
35
68
  describe '#reset_connection!' do
@@ -8,7 +8,7 @@ http_interactions:
8
8
  string: ''
9
9
  headers:
10
10
  User-Agent:
11
- - Swipely/Docker-API 1.7.6
11
+ - Swipely/Docker-API 1.8.0
12
12
  Content-Type:
13
13
  - text/plain
14
14
  response:
@@ -19,7 +19,7 @@ http_interactions:
19
19
  Content-Type:
20
20
  - application/json
21
21
  Date:
22
- - Wed, 12 Feb 2014 17:06:20 GMT
22
+ - Mon, 17 Feb 2014 19:21:58 GMT
23
23
  Connection:
24
24
  - close
25
25
  Transfer-Encoding:
@@ -34,7 +34,7 @@ http_interactions:
34
34
  complete\",\"progressDetail\":{},\"id\":\"b750fe79269d\"}{\"status\":\"Download
35
35
  complete\",\"progressDetail\":{},\"id\":\"b750fe79269d\"}"
36
36
  http_version:
37
- recorded_at: Wed, 12 Feb 2014 17:06:21 GMT
37
+ recorded_at: Mon, 17 Feb 2014 19:22:00 GMT
38
38
  - request:
39
39
  method: post
40
40
  uri: unix:///var/run/docker.sock/v1.8/images/base/tag?force=true&repo=base2
@@ -43,7 +43,7 @@ http_interactions:
43
43
  string: ''
44
44
  headers:
45
45
  User-Agent:
46
- - Swipely/Docker-API 1.7.6
46
+ - Swipely/Docker-API 1.8.0
47
47
  Content-Type:
48
48
  - text/plain
49
49
  response:
@@ -52,7 +52,7 @@ http_interactions:
52
52
  message:
53
53
  headers:
54
54
  Date:
55
- - Wed, 12 Feb 2014 17:06:21 GMT
55
+ - Mon, 17 Feb 2014 19:22:00 GMT
56
56
  Content-Length:
57
57
  - '0'
58
58
  Content-Type:
@@ -63,5 +63,5 @@ http_interactions:
63
63
  encoding: UTF-8
64
64
  string: ''
65
65
  http_version:
66
- recorded_at: Wed, 12 Feb 2014 17:06:21 GMT
66
+ recorded_at: Mon, 17 Feb 2014 19:22:00 GMT
67
67
  recorded_with: VCR 2.8.0
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Swipely, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-12 00:00:00.000000000 Z
11
+ date: 2014-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: excon
@@ -154,6 +154,7 @@ files:
154
154
  - Rakefile
155
155
  - docker-api.gemspec
156
156
  - lib/docker.rb
157
+ - lib/docker/base.rb
157
158
  - lib/docker/connection.rb
158
159
  - lib/docker/container.rb
159
160
  - lib/docker/error.rb