dockerapi 0.14.0 → 0.19.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac123f7f5ed500758fd1bb2a9f214495e71c6848517662eae15b92dfa00387aa
4
- data.tar.gz: 270f7a7e14d43f73c402191f11ebf9233aa8b7e2c2e314ac3eeb2875487c5120
3
+ metadata.gz: 2edd0e23baece7608d646b30f453476e3badd792497234ef2ff91e639e234ac2
4
+ data.tar.gz: deba1315765257880eec881db91c4e71f286dc43f6e8f9e209b9f5ac551d864d
5
5
  SHA512:
6
- metadata.gz: 878a7c0a146bc6657909151ff0e866c1b9cc93f1dc57ed6c7d0e91b87063e41496af294d1f1e7318b11b0ba3eaf03823e5e081b664b4c3bdd326d4298aed6c65
7
- data.tar.gz: fee3d36fd9de8619fc27c588c1285c9acd6ca20a3a6ce1f9fd2ea67c807c74d90ae1a0b531ec233a227ccfd4655056e0c33e6605fa9a31040f6984ca2e3a6798
6
+ metadata.gz: aaaceb91eb304a1a9be2de7e5562a0744eab641b066fdc0e7aebe5a9b8b22f5e6d5710676897099190bbb705baa8ba269641d5aaddc53086f145c1f585b30681
7
+ data.tar.gz: 6e46d59caa6f4069dbd17cd5a784ac71fb119af9b0a846e282ce2ed140c00a564c339a26aa359667079472f41c785eb769ae8bbf1a3924420c6b247aad1ddfec
@@ -0,0 +1,67 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ master ]
13
+ pull_request:
14
+ branches: [ master ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ - name: Set up Ruby
24
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
25
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
26
+ # uses: ruby/setup-ruby@v1
27
+ uses: ruby/setup-ruby@21351ecc0a7c196081abca5dc55b08f085efe09a
28
+ with:
29
+ ruby-version: 2.6
30
+ - name: Install Docker
31
+ run: curl https://get.docker.com | sh
32
+ - name: Install dependencies
33
+ run: |
34
+ bin/setup
35
+ sudo bin/setup
36
+ - name: Test misc
37
+ run: rspec spec/misc/*.rb
38
+ - name: Test Image
39
+ run: rspec spec/endpoints/image_spec.rb:1
40
+ - name: Test Image authentication
41
+ run: rspec spec/endpoints/image_spec.rb:194
42
+ continue-on-error: true
43
+ - name: Test Container
44
+ run: rspec spec/endpoints/container_spec.rb
45
+ - name: Test Volume
46
+ run: rspec spec/endpoints/volume_spec.rb
47
+ - name: Test Network
48
+ run: rspec spec/endpoints/network_spec.rb
49
+ - name: Test System
50
+ run: rspec spec/endpoints/system_spec.rb
51
+ - name: Test Exec
52
+ run: rspec spec/endpoints/exec_spec.rb
53
+ - name: Test Swarm
54
+ run: rspec spec/endpoints/swarm_spec.rb
55
+ - name: Test Node
56
+ run: rspec spec/endpoints/node_spec.rb
57
+ - name: Test Service
58
+ run: rspec spec/endpoints/service_spec.rb
59
+ - name: Test Task
60
+ run: rspec spec/endpoints/task_spec.rb
61
+ - name: Test Secret
62
+ run: rspec spec/endpoints/secret_spec.rb
63
+ - name: Test Config
64
+ run: rspec spec/endpoints/config_spec.rb
65
+ - name: Test Plugin
66
+ run: rspec spec/endpoints/plugin_spec.rb
67
+
data/.gitignore CHANGED
@@ -9,3 +9,7 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ resources/registry_authentication/*.key
14
+ resources/registry_authentication/*.crt
15
+ resources/registry_authentication/htpasswd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ # 0.18.0
2
+
3
+ Method `Docker::API::Image#distribution` now accepts authentication parameters. Feature introduced in [PR#3](https://github.com/nu12/dockerapi/pull/3)
4
+
5
+ Contributors: @zarqman
6
+
7
+ # 0.17.0
8
+
9
+ New block execution introduced in [PR#1](https://github.com/nu12/dockerapi/pull/1).
10
+
11
+ Contributors: @zarqman
12
+
13
+ # 0.16.0
14
+
15
+ `Docker::API::Task#logs` method can now receive a block to replace standard output to stdout behavior.
16
+
17
+ Add `auth_encoder` to provide standard implementation for the authentication header where needed.
18
+
19
+ # 0.15.0
20
+
21
+ `Docker::API::System#events` and `Docker::API::Exec#start` methods can now receive a block to replace standard output to stdout behavior.
22
+
23
+ General refactoring and API documentation.
24
+
1
25
  # 0.14.0
2
26
 
3
27
  Method `Docker::API::Container#archive` is splitted in `#get_archive` and `#put_archive` as per Docker API documentation.
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dockerapi (0.14.0)
5
- excon (~> 0.76.0)
4
+ dockerapi (0.19.0)
5
+ excon (~> 0.79)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  diff-lcs (1.3)
11
- excon (0.76.0)
11
+ excon (0.79.0)
12
12
  rake (12.3.3)
13
13
  rspec (3.9.0)
14
14
  rspec-core (~> 3.9.0)
data/README.md CHANGED
@@ -21,6 +21,7 @@ Interact with Docker API directly from Ruby code. Comprehensive implementation (
21
21
  * [Requests](#requests)
22
22
  * [Response](#response)
23
23
  * [Error handling](#error-handling)
24
+ * [Blocks](#blocks)
24
25
  * [Development](#development)
25
26
  * [Contributing](#contributing)
26
27
  * [License](#license)
@@ -31,6 +32,8 @@ Add this line to your application's Gemfile:
31
32
 
32
33
  ```ruby
33
34
  gem 'dockerapi'
35
+ # or
36
+ gem 'dockerapi', github: 'nu12/dockerapi'
34
37
  ```
35
38
 
36
39
  And then execute:
@@ -75,6 +78,7 @@ image.details("image")
75
78
 
76
79
  # Return image digest and platform information by contacting the registry.
77
80
  image.distribution("image")
81
+ image.distribution("image", {username: "janedoe", password: "password"}) # private repository
78
82
 
79
83
  # History
80
84
  image.history("image")
@@ -91,7 +95,7 @@ image.tag("current:tag", repo: "new", tag: "tag")
91
95
  # Push image
92
96
  image.push("repo:tag") # to dockerhub
93
97
  image.push("localhost:5000/repo:tag") # to local registry
94
- image.push("private/repo", {tag: "tag"}, {username: "janedoe", password: "password"} # to private repository
98
+ image.push("private/repo", {tag: "tag"}, {username: "janedoe", password: "password"}) # to private repository
95
99
 
96
100
  # Remove image
97
101
  image.remove("image")
@@ -531,32 +535,46 @@ response.success?
531
535
 
532
536
  To completely skip the validation process, add `:skip_validation => true` in the hash to be validated.
533
537
 
538
+ ### Blocks
539
+
540
+ Some methods can receive a block to alter the default execution:
541
+ * Docker::API::Container#logs
542
+ * Docker::API::Container#attach
543
+ * Docker::API::Container#stats
544
+ * Docker::API::Container#export
545
+ * Docker::API::Container#get_archive
546
+ * Docker::API::Image#create
547
+ * Docker::API::Image#build
548
+ * Docker::API::Image#export
549
+ * Docker::API::System#event
550
+ * Docker::API::Exec#start
551
+ * Docker::API::Task#logs
552
+
553
+ Example:
554
+ ```ruby
555
+ => image = Docker::API::Image.new
556
+
557
+ => image.create(fromImage: "nginx:alpine") do | chunk, bytes_remaining, bytes_total |
558
+ p chunk.to_s
559
+ end
560
+ ```
561
+
562
+ The default blocks can be found in `Docker::API::Base`.
563
+
534
564
  ## Development
535
565
 
536
566
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
537
567
 
538
568
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
539
569
 
540
- ### Road to 1.0.0
541
-
542
- | Class | Tests | Implementation | Refactoring |
543
- |---|---|---|---|
544
- | Image | Ok | Ok | Ok |
545
- | Container | Ok | Ok | Ok |
546
- | Volume | Ok | Ok | 8/14 |
547
- | Network | Ok | Ok | 8/14 |
548
- | System | Ok | Ok | 8/14 |
549
- | Exec | Ok | Ok | 8/14 |
550
- | Swarm | Ok | Ok | 8/21 |
551
- | Node | Ok | Ok | 8/21 |
552
- | Service | Ok | Ok | 8/21 |
553
- | Task | Ok | Ok | 8/28 |
554
- | Secret | Ok | Ok | 8/28 |
555
- | Config | Ok | Ok | 8/28 |
556
- | Distribution | Ok | Ok | 8/28 |
557
- | Plugin | Ok | Ok | 8/28 |
558
-
559
- Add doc in these files: `base`, `connection`, `error`, `response`, `dockerapi`
570
+ ### Release new version
571
+
572
+ * Update CHANGELOG.
573
+ * Update README as needed.
574
+ * Update version.
575
+ * Run tests.
576
+ * Commit changes.
577
+ * Release / push version to Rubygems & Github.
560
578
 
561
579
  ## Contributing
562
580
 
data/bin/setup CHANGED
@@ -18,5 +18,13 @@ then
18
18
  else
19
19
  echo "Running bundle install"
20
20
  bundle install
21
+
22
+ echo "Creating self-signed certificate to use in tests"
23
+ openssl req -newkey rsa:2048 -nodes -keyout resources/registry_authentication/registry_auth.key -x509 -days 365 -out resources/registry_authentication/registry_auth.crt -subj "/C=CL/ST=Santiago/L=Santiago/O=dockerapi/OU=dockerapi/CN=localhost"
24
+
25
+ echo "Creating htpasswd file to use in tests"
26
+ docker run --rm --entrypoint htpasswd registry:2.7.0 -Bbn janedoe password > resources/registry_authentication/htpasswd
27
+ docker image rm registry:2.7.0
21
28
  echo "Run this script as root for further configurations"
22
- fi
29
+ fi
30
+
data/dockerapi.gemspec CHANGED
@@ -26,5 +26,5 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ["lib"]
28
28
 
29
- spec.add_dependency("excon", "~> 0.76.0")
29
+ spec.add_dependency("excon", "~> 0.79")
30
30
  end
@@ -1,24 +1,21 @@
1
+ ##
2
+ # Base class to provide general methods, helpers and implementations accross classes.
1
3
  class Docker::API::Base
2
4
 
3
-
5
+ ##
6
+ # Create new object and sets the validation to happen automatically when method parameters include "params" or "body".
7
+ #
8
+ # @param connection [Docker::API::Connection]: Connection to be used.
4
9
  def initialize connection = nil
5
10
  raise Docker::API::Error.new("Expected connection to be a Docker::API::Connection class") if connection != nil && !connection.is_a?(Docker::API::Connection)
6
11
  @connection = connection || Docker::API::Connection.new
7
-
8
- (self.methods - Object.methods).each do |method|
9
- params_index = method(method).parameters.map{|ar| ar[1]}.index(:params)
10
- body_index = method(method).parameters.map{|ar| ar[1]}.index(:body)
11
-
12
- define_singleton_method(method) do |*args, &block|
13
- validate Docker::API::InvalidParameter, Docker::API::VALID_PARAMS["#{self.class.name}"]["#{method}"], (args[params_index] || {}) if params_index
14
- validate Docker::API::InvalidRequestBody, Docker::API::VALID_BODY["#{self.class.name}"]["#{method}"], (args[body_index] || {}) if body_index
15
- super(*args,&block)
16
- end
17
- end
12
+ set_automated_validation
18
13
  end
19
14
 
20
15
  private
21
16
 
17
+ ##
18
+ # Output to stdout.
22
19
  def default_streamer
23
20
  streamer = lambda do |chunk, remaining_bytes, total_bytes|
24
21
  p chunk.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?') if Docker::API::PRINT_TO_STDOUT
@@ -26,6 +23,10 @@ class Docker::API::Base
26
23
  streamer
27
24
  end
28
25
 
26
+ ##
27
+ # Write file to disk.
28
+ #
29
+ # @param path [String]: Path to the file to be writen.
29
30
  def default_writer path
30
31
  streamer = lambda do |chunk, remaining_bytes, total_bytes|
31
32
  return if "#{chunk}".match(/(No such image)/)
@@ -36,31 +37,74 @@ class Docker::API::Base
36
37
  streamer
37
38
  end
38
39
 
40
+ ##
41
+ # Read file from disk.
42
+ #
43
+ # @param path [String]: Path to the file to be read.
44
+ # @param url [String]: Endpoint URL where the file is going to be sent.
45
+ # @param header [Hash]: Header of the request.
46
+ # @param &block: Replace the default output to stdout behavior.
39
47
  def default_reader path, url, header = {"Content-Type" => "application/x-tar"}, &block
40
48
  file = File.open(File.expand_path(path), "r")
41
- response = @connection.request(method: :post, path: url , headers: header, request_block: lambda { file.read(Excon.defaults[:chunk_size]).to_s}, response_block: block_given? ? block.call : default_streamer )
49
+ response = @connection.request(method: :post, path: url , headers: header, request_block: lambda { file.read(Excon.defaults[:chunk_size]).to_s}, response_block: block_given? ? block : default_streamer )
42
50
  file.close
43
51
  response
44
52
  end
45
53
 
54
+ ##
55
+ # Encode authentication parameters.
56
+ #
57
+ # @param authentication [Hash]: Parameters to be encoded.
58
+ def auth_encoder(authentication)
59
+ Base64.urlsafe_encode64(authentication.to_json.to_s).chomp
60
+ end
61
+
62
+ ##
63
+ # Validate a Hash object comparing its keys with a given Array of permitted values. Raise an error if the validation fail.
64
+ #
65
+ # @param error [Error]: Error to be raised of the validation fail.
66
+ # @param permitted [Array]: List of permitted keys.
67
+ # @param params [Hash]: Hash object to be validated.
46
68
  def validate error, permitted, params
47
69
  return if params[:skip_validation]
48
70
  unpermitted = params.keys.map(&:to_s) - permitted.map(&:to_s)
49
71
  raise error.new(permitted, unpermitted) if unpermitted.size > 0
50
72
  end
51
73
 
52
- ## Converts Ruby Hash into query parameters
53
- ## In general, the format is key=value
54
- ## If value is another Hash, it should keep a json syntax {key:value}
55
- def hash_to_params h
74
+ ##
75
+ # Convert Ruby Hash into URL query parameters.
76
+ #
77
+ # In general, query parameters' format is "key=value", but if "value" is another Hash, it should change to a json syntax {key:value}.
78
+ #
79
+ # @param hash [Hash]: Hash object to be converted in a query parameter-like string.
80
+ def hash_to_params hash
56
81
  p = []
57
- h.delete_if{ | k, v | k.to_s == "skip_validation" }.each { |k,v| p.push( v.is_a?(Hash) ? "#{k}=#{v.to_json}" : "#{k}=#{v}") }
82
+ hash.delete_if{ | k, v | k.to_s == "skip_validation" }.each { |k,v| p.push( v.is_a?(Hash) ? "#{k}=#{v.to_json}" : "#{k}=#{v}") }
58
83
  p.join("&").gsub(" ","")
59
84
  end
60
85
 
86
+ ##
87
+ # Build an URL string using the base path and a set of parameters.
88
+ #
89
+ # @param path [String]: Base URL string.
90
+ # @param hash [Hash]: Hash object to be appended to the URL as query parameters.
61
91
  def build_path path, params = {}
62
- p = path.is_a?(Array) ? ([base_path] << path).join("/") : path # TODO: this line to be removed?
63
- params.size > 0 ? [p, hash_to_params(params)].join("?") : p
92
+ params.size > 0 ? [path, hash_to_params(params)].join("?") : path
93
+ end
94
+
95
+ ##
96
+ # Set the validation to happen automatically when method parameters include "params" or "body".
97
+ def set_automated_validation
98
+ (self.methods - Object.methods).each do |method|
99
+ params_index = method(method).parameters.map{|ar| ar[1]}.index(:params)
100
+ body_index = method(method).parameters.map{|ar| ar[1]}.index(:body)
101
+
102
+ define_singleton_method(method) do |*args, &block|
103
+ validate Docker::API::InvalidParameter, Docker::API::VALID_PARAMS["#{self.class.name}"]["#{method}"], (args[params_index] || {}) if params_index
104
+ validate Docker::API::InvalidRequestBody, Docker::API::VALID_BODY["#{self.class.name}"]["#{method}"], (args[body_index] || {}) if body_index
105
+ super(*args,&block)
106
+ end
107
+ end
64
108
  end
65
109
 
66
110
  end
@@ -1,20 +1,28 @@
1
- module Docker
2
- module API
3
- class Connection
4
- [:get, :post, :head, :delete, :put].each do | method |
5
- define_method(method) { | path | self.request(method: method, path: path) }
6
- end
7
-
8
- def request params
9
- Docker::API::Response.new(@connection.request(params).data)
10
- end
11
-
12
- def initialize url = nil, params = nil
13
- url ||= 'unix:///'
14
- params ||= url == 'unix:///' ? {socket: '/var/run/docker.sock'} : {}
15
- @connection = Excon.new(url, params)
16
- end
1
+ ##
2
+ # Connection class.
3
+ class Docker::API::Connection
4
+ [:get, :post, :head, :delete, :put].each do | method |
5
+ define_method(method) { | path | self.request(method: method, path: path) }
6
+ end
17
7
 
18
- end
8
+ ##
9
+ # Call an Excon request and returns a Docker::API::Response object.
10
+ #
11
+ # @param params [Hash]: Request parameters.
12
+ def request params
13
+ response = Docker::API::Response.new(@connection.request(params).data)
14
+ p response if Docker::API::PRINT_RESPONSE_TO_STDOUT
15
+ response
19
16
  end
17
+
18
+ ##
19
+ # Create an Excon connection.
20
+ #
21
+ # @param url [String]: URL for the connection.
22
+ # @param params [String]: Additional parameters.
23
+ def initialize url = nil, params = nil
24
+ return @connection = Excon.new('unix:///', {socket: '/var/run/docker.sock'}) unless url
25
+ @connection = Excon.new(url, params || {})
26
+ end
27
+
20
28
  end
@@ -4,7 +4,7 @@
4
4
  class Docker::API::Container < Docker::API::Base
5
5
 
6
6
  ##
7
- # Returns a list of containers.
7
+ # Return a list of containers.
8
8
  #
9
9
  # Docker API: GET /containers/json
10
10
  # @see https://docs.docker.com/engine/api/v1.40/#operation/ContainerList
@@ -204,7 +204,7 @@ class Docker::API::Container < Docker::API::Base
204
204
  path = build_path("/containers/#{name}/logs", params)
205
205
 
206
206
  if [true, 1 ].include? params[:follow]
207
- @connection.request(method: :get, path: path , response_block: block_given? ? block.call : default_streamer)
207
+ @connection.request(method: :get, path: path , response_block: block_given? ? block : default_streamer)
208
208
  else
209
209
  @connection.get(path)
210
210
  end
@@ -220,7 +220,7 @@ class Docker::API::Container < Docker::API::Base
220
220
  # @param params [Hash]: Parameters that are appended to the URL.
221
221
  # @param &block: Replace the default output to stdout behavior.
222
222
  def attach name, params = {}, &block
223
- @connection.request(method: :post, path: build_path("/containers/#{name}/attach", params) , response_block: block_given? ? block.call : default_streamer)
223
+ @connection.request(method: :post, path: build_path("/containers/#{name}/attach", params) , response_block: block_given? ? block : default_streamer)
224
224
  end
225
225
 
226
226
  ##
@@ -247,7 +247,7 @@ class Docker::API::Container < Docker::API::Base
247
247
  def stats name, params = {}, &block
248
248
  path = build_path("/containers/#{name}/stats", params)
249
249
  if [true, 1 ].include? params[:stream]
250
- @connection.request(method: :get, path: path , response_block: block_given? ? block.call : default_streamer)
250
+ @connection.request(method: :get, path: path , response_block: block_given? ? block : default_streamer)
251
251
  else
252
252
  @connection.get(path)
253
253
  end
@@ -265,7 +265,7 @@ class Docker::API::Container < Docker::API::Base
265
265
  def export name, path, &block
266
266
  response = self.details(name)
267
267
  return response unless response.status == 200
268
- @connection.request(method: :get, path: "/containers/#{name}/export" , response_block: block_given? ? block.call : default_writer(path))
268
+ @connection.request(method: :get, path: "/containers/#{name}/export" , response_block: block_given? ? block : default_writer(path))
269
269
  end
270
270
 
271
271
  ##
@@ -285,7 +285,7 @@ class Docker::API::Container < Docker::API::Base
285
285
  return response unless response.status == 200
286
286
 
287
287
  file = File.open( File.expand_path( path ) , "wb")
288
- response = @connection.request(method: :get, path: build_path("/containers/#{name}/archive", params) , response_block: block_given? ? block.call : lambda { |chunk, remaining_bytes, total_bytes| file.write(chunk) })
288
+ response = @connection.request(method: :get, path: build_path("/containers/#{name}/archive", params) , response_block: block_given? ? block : lambda { |chunk, remaining_bytes, total_bytes| file.write(chunk) })
289
289
  file.close
290
290
  response
291
291
  end