dockerapi 0.14.0 → 0.19.0

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
  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