dockerapi 0.11.0 → 0.16.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: '09aa5bf2a46df8ad42f1c4833fe7577610af14dde350730787b703e1080fa4c7'
4
- data.tar.gz: 0be7a47781bbc7f75824f65b8fea5d7bcbd11deb98451f2b030856391a68d5c1
3
+ metadata.gz: 8207aa413525c868d4e1c0f57cacf38c19348dee819da2aeb63f390d5ac41f28
4
+ data.tar.gz: 53406674405580c0dcb91c4c32a914ef0de92ce9a9c1132eb7bf046902e5adc8
5
5
  SHA512:
6
- metadata.gz: f0573e091c6cbbc6c2fa3411ca6336a328e4677a656f22bd7d4a036064f8c813523c6a686c2e3ec03df2ec194f65c1b69c6d5be5782c1a1fca80460f3c383db9
7
- data.tar.gz: 5fa96ad226aad3faa2e3a2836948687adf29079b0495e88ceb42424bbe14d2664cab4a8f59a2a795e2f73c9fe59318504a9c454b4964d1b16a04165023c7e8f8
6
+ metadata.gz: be5d82c94e72b29d4341330b3c12f4a2007c6e46813cca6eb6cc8ba3f3a0adae2cd8ef00d0020ed1d59bf5bfc12bf6b22f6b3dd96eb5287ee03f02e14f1bb0ce
7
+ data.tar.gz: f4155422936cd0a4e754d4f32a118662c1d6ace28d788aae51e4d09f09b817519ed7ec0bca9e1955bcb2edc66c5ea111181493e43d398de20e4662d665ac8d2b
@@ -1,3 +1,54 @@
1
+ # 0.16.0
2
+
3
+ `Docker::API::Task#logs` method can now receive a block to replace standard output to stdout behavior.
4
+
5
+ Add `auth_encoder` to provide standard implementation for the authentication header where needed.
6
+
7
+ # 0.15.0
8
+
9
+ `Docker::API::System#events` and `Docker::API::Exec#start` methods can now receive a block to replace standard output to stdout behavior.
10
+
11
+ General refactoring and API documentation.
12
+
13
+ # 0.14.0
14
+
15
+ Method `Docker::API::Container#archive` is splitted in `#get_archive` and `#put_archive` as per Docker API documentation.
16
+
17
+ The following `Docker::API::Container` methods that can now receive a block:
18
+ * logs (output to stdout)
19
+ * attach (output to stdout)
20
+ * stats (output to stdout)
21
+ * export (write file)
22
+ * get_archive (write file)
23
+
24
+ # 0.13.0
25
+
26
+ Add default behavior for file read, write and output to stdout. Whenever a method can receive a block, this default behavior can be replaced.
27
+
28
+ The following `Docker::API::Image` methods that can now receive a block:
29
+ * export (write file)
30
+ * create (output to stdout)
31
+ * build (output to stdout)
32
+
33
+ Default output to stdout can be supressed by setting `Docker::API::PRINT_TO_STDOUT` to `false`
34
+
35
+ Method parameters `params` and `body` will be automatically evaluated whenever they are present in the method's signature.
36
+
37
+ # 0.12.0
38
+
39
+ Add `Docker::API::Plugin` methods:
40
+ * list
41
+ * privileges
42
+ * install
43
+ * details
44
+ * remove
45
+ * enable
46
+ * disable
47
+ * upgrade
48
+ * create
49
+ * push
50
+ * configure
51
+
1
52
  # 0.11.0
2
53
 
3
54
  Add `Docker::API::Task` methods:
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dockerapi (0.11.0)
5
- excon (~> 0.74.0)
4
+ dockerapi (0.16.0)
5
+ excon (~> 0.76.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  diff-lcs (1.3)
11
- excon (0.74.0)
11
+ excon (0.76.0)
12
12
  rake (12.3.3)
13
13
  rspec (3.9.0)
14
14
  rspec-core (~> 3.9.0)
data/README.md CHANGED
@@ -1,6 +1,29 @@
1
1
  # dockerapi
2
2
 
3
- Interact directly with Docker API from Ruby code.
3
+ Interact with Docker API directly from Ruby code. Comprehensive implementation (all available endpoints), no local Docker installation required, easily manipulated http responses.
4
+
5
+ * [Installation](#installation)
6
+ * [Usage](#usage)
7
+ * [Images](#images)
8
+ * [Containers](#containers)
9
+ * [Volumes](#volumes)
10
+ * [Network](#network)
11
+ * [System](#system)
12
+ * [Exec](#exec)
13
+ * [Swarm](#swarm)
14
+ * [Node](#node)
15
+ * [Service](#service)
16
+ * [Task](#task)
17
+ * [Secret](#secret)
18
+ * [Config](#config)
19
+ * [Plugin](#plugin)
20
+ * [Connection](#connection)
21
+ * [Requests](#requests)
22
+ * [Response](#response)
23
+ * [Error handling](#error-handling)
24
+ * [Development](#development)
25
+ * [Contributing](#contributing)
26
+ * [License](#license)
4
27
 
5
28
  ## Installation
6
29
 
@@ -8,6 +31,8 @@ Add this line to your application's Gemfile:
8
31
 
9
32
  ```ruby
10
33
  gem 'dockerapi'
34
+ # or
35
+ gem 'dockerapi', github: 'nu12/dockerapi'
11
36
  ```
12
37
 
13
38
  And then execute:
@@ -20,6 +45,12 @@ Or install it yourself as:
20
45
 
21
46
  ## Usage
22
47
 
48
+ The following section will bring you up to speed in order to use most this gem resources with pratical examples.
49
+
50
+ If you need more information about the different Docker API endpoints, please see the [Docker API documentation](https://docs.docker.com/engine/api/v1.40/).
51
+
52
+ For a more detailed and comprehensive documentation about this gem's API, please see the [documentation page](https://rubydoc.info/gems/dockerapi).
53
+
23
54
  ### Images
24
55
 
25
56
  ```ruby
@@ -75,13 +106,16 @@ image.prune(filters: {dangling: {"false": true}})
75
106
  image.commit(container: container, repo: "my/image", tag: "latest", comment: "Comment from commit", author: "dockerapi", pause: false )
76
107
 
77
108
  # Build image from a local tar file
78
- image.build("/path/to/file.tar")
109
+ image.build("/path/to/file.tar", {t: "tag"})
110
+
111
+ # Build image using private repository
112
+ image.build("/path/to/file.tar", {t: "tag"}, {"https://index.docker.io/v1/" => {username: "janedoe", password: "janedoe"}})
79
113
 
80
114
  # Build image from a remote tar file
81
- image.build(nil, remote: "https://url.to/file.tar")
115
+ image.build(nil, {remote: "https://url.to/file.tar", t: "tag"})
82
116
 
83
117
  # Build image from a remote Dockerfile
84
- image.build(nil, remote: "https://url.to/Dockerfile")
118
+ image.build(nil, {remote: "https://url.to/Dockerfile", t: "tag"})
85
119
 
86
120
  # Delete builder cache
87
121
  image.delete_cache
@@ -148,7 +182,10 @@ container.stats("nginx", stream: true)
148
182
  container.export("nginx", "~/exported_container")
149
183
 
150
184
  # Get files from container
151
- container.archive("nginx", "~/html.tar", path: "/usr/share/nginx/html/")
185
+ container.get_archive("nginx", "~/html.tar", path: "/usr/share/nginx/html/")
186
+
187
+ # Send files to container
188
+ container.put_archive("nginx", "~/html.tar", path: "/usr/share/nginx/html/")
152
189
 
153
190
  # Stop container
154
191
  container.stop("nginx")
@@ -391,9 +428,50 @@ config.update("config-name", {version: version}, spec.merge!({ Data: "VEhJUyBJUy
391
428
  config.delete("config-name")
392
429
  ```
393
430
 
431
+ ### Plugin
432
+ ```ruby
433
+ # Connect to local plugin endpoints
434
+ plugin = Docker::API::Plugin.new
435
+
436
+ # List plugins
437
+ plugin.list
438
+
439
+ # List plugin's privileges
440
+ plugin.privileges(remote: "plugin-name")
441
+
442
+ # Install plugin (using defined privileges)
443
+ privileges = plugin.privileges(remote: "plugin-name")
444
+ plugin.install({remote: "plugin-name"}, privileges)
445
+
446
+ # Upgrade plugin (using defined privileges)
447
+ privileges = plugin.privileges(remote: "plugin-name2")
448
+ plugin.upgrade("plugin-name", {remote: "plugin-name2"}, privileges)
449
+
450
+ # Enable plugin
451
+ plugin.enable("plugin-name", timeout: 0)
452
+
453
+ # Disable plugin
454
+ plugin.disable("plugin-name")
455
+
456
+ # Configure plugin
457
+ plugin.configure("plugin-name", ["DEBUG=1"])
458
+
459
+ # Inspect plugin
460
+ plugin.details("plugin-name")
461
+
462
+ # Remove plugin
463
+ plugin.remove("plugin-name")
464
+
465
+ # Create plugin (tar file must contain rootfs folder and config.json file)
466
+ plugin.create("name", "/path/to/file.tar")
467
+
468
+ # Push plugin
469
+ plugin.push("name")
470
+ ```
471
+
394
472
  ### Connection
395
473
 
396
- By default Docker::API::Connection will connect to local Docker socket at `/var/run/docker.sock`. See examples below to use a different path or connect to a remote address.
474
+ By default `Docker::API::Connection` will connect to local Docker socket at `/var/run/docker.sock`. See examples below to use a different path or connect to a remote address.
397
475
 
398
476
  ```ruby
399
477
  # Setting different connections
@@ -465,20 +543,19 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
465
543
 
466
544
  | Class | Tests | Implementation | Refactoring |
467
545
  |---|---|---|---|
468
- | Image | Ok | Ok | 8/7 |
469
- | Container | Ok | Ok | 8/14 |
470
- | Volume | Ok | Ok | 8/21 |
471
- | Network | Ok | Ok | 8/21 |
472
- | System | Ok | Ok | 8/21 |
473
- | Exec | Ok | Ok | 8/21 |
474
- | Swarm | Ok | Ok | 8/28 |
475
- | Node | Ok | Ok | 8/28 |
476
- | Service | Ok | Ok | 8/28 |
477
- | Task | Ok | Ok | 9/4 |
478
- | Secret | Ok | Ok | 9/4 |
479
- | Config | Ok | Ok | 9/4 |
480
- | Distribution | Ok | Ok | 9/4 |
481
- | Plugin | 7/24 | 7/24 | 9/4 |
546
+ | Image | Ok | Ok | Ok |
547
+ | Container | Ok | Ok | Ok |
548
+ | Volume | Ok | Ok | Ok |
549
+ | Network | Ok | Ok | Ok |
550
+ | System | Ok | Ok | Ok |
551
+ | Exec | Ok | Ok | Ok |
552
+ | Swarm | Ok | Ok | Ok |
553
+ | Node | Ok | Ok | Ok |
554
+ | Service | Ok | Ok | Ok |
555
+ | Task | Ok | Ok | Ok |
556
+ | Secret | Ok | Ok | Ok |
557
+ | Config | Ok | Ok | 8/14 |
558
+ | Plugin | Ok | Ok | 8/14 |
482
559
 
483
560
  ## Contributing
484
561
 
@@ -6,8 +6,8 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ["Alysson A. Costa"]
7
7
  spec.email = ["alysson.avila.costa@gmail.com"]
8
8
 
9
- spec.summary = "Interact directly with Docker API from Ruby code."
10
- spec.description = "Interact directly with Docker API from Ruby code."
9
+ spec.summary = "Interact with Docker API from Ruby code."
10
+ spec.description = "Interact with Docker API directly from Ruby code. Comprehensive implementation (all available endpoints), no local Docker installation required, easily manipulated http responses."
11
11
  spec.homepage = "https://github.com/nu12/dockerapi"
12
12
  spec.license = "MIT"
13
13
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
@@ -15,6 +15,7 @@ Gem::Specification.new do |spec|
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
16
  spec.metadata["source_code_uri"] = "https://github.com/nu12/dockerapi.git"
17
17
  spec.metadata["changelog_uri"] = "https://github.com/nu12/dockerapi/blob/master/CHANGELOG.md"
18
+ spec.metadata["documentation_uri"] = "https://www.rubydoc.info/gems/dockerapi"
18
19
 
19
20
  # Specify which files should be added to the gem when it is released.
20
21
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -25,5 +26,5 @@ Gem::Specification.new do |spec|
25
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
27
  spec.require_paths = ["lib"]
27
28
 
28
- spec.add_dependency("excon", "~> 0.74.0")
29
+ spec.add_dependency("excon", "~> 0.76.0")
29
30
  end
@@ -1,38 +1,110 @@
1
- module Docker
2
- module API
3
- class Base
1
+ ##
2
+ # Base class to provide general methods, helpers and implementations accross classes.
3
+ class Docker::API::Base
4
+
5
+ ##
6
+ # Creates 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.
9
+ def initialize connection = nil
10
+ raise Docker::API::Error.new("Expected connection to be a Docker::API::Connection class") if connection != nil && !connection.is_a?(Docker::API::Connection)
11
+ @connection = connection || Docker::API::Connection.new
12
+ set_automated_validation
13
+ end
14
+
15
+ private
4
16
 
5
- def initialize connection = nil
6
- raise Docker::API::Error.new("Expect connection to be a Docker::API::Connection class") if connection != nil && !connection.is_a?(Docker::API::Connection)
7
- @connection = connection || Docker::API::Connection.new
8
- end
9
-
10
- private
17
+ ##
18
+ # Outputs to stdout.
19
+ def default_streamer
20
+ streamer = lambda do |chunk, remaining_bytes, total_bytes|
21
+ p chunk.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?') if Docker::API::PRINT_TO_STDOUT
22
+ end
23
+ streamer
24
+ end
11
25
 
12
- def base_path # TODO: this method to be removed?
13
- "/"
14
- end
26
+ ##
27
+ # Writes file.
28
+ #
29
+ # @param path [String]: Path to the file to be writen.
30
+ def default_writer path
31
+ streamer = lambda do |chunk, remaining_bytes, total_bytes|
32
+ return if "#{chunk}".match(/(No such image)/)
33
+ file = File.open(File.expand_path(path), "wb+")
34
+ file.write(chunk)
35
+ file.close
36
+ end
37
+ streamer
38
+ end
15
39
 
16
- def validate error, permitted, params
17
- return if params[:skip_validation]
18
- unpermitted = params.keys.map(&:to_s) - permitted.map(&:to_s)
19
- raise error.new(permitted, unpermitted) if unpermitted.size > 0
20
- end
40
+ ##
41
+ # Reads file.
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.
47
+ def default_reader path, url, header = {"Content-Type" => "application/x-tar"}, &block
48
+ file = File.open(File.expand_path(path), "r")
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.call : default_streamer )
50
+ file.close
51
+ response
52
+ end
21
53
 
22
- ## Converts Ruby Hash into query parameters
23
- ## In general, the format is key=value
24
- ## If value is another Hash, it should keep a json syntax {key:value}
25
- def hash_to_params h
26
- p = []
27
- 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}") }
28
- p.join("&").gsub(" ","")
29
- end
54
+ ##
55
+ # Encodes the 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
30
61
 
31
- def build_path path, params = {}
32
- p = path.is_a?(Array) ? ([base_path] << path).join("/") : path # TODO: this line to be removed?
33
- params.size > 0 ? [p, hash_to_params(params)].join("?") : p
34
- end
62
+ ##
63
+ # Validates 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.
68
+ def validate error, permitted, params
69
+ return if params[:skip_validation]
70
+ unpermitted = params.keys.map(&:to_s) - permitted.map(&:to_s)
71
+ raise error.new(permitted, unpermitted) if unpermitted.size > 0
72
+ end
73
+
74
+ ##
75
+ # Converts 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
81
+ p = []
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}") }
83
+ p.join("&").gsub(" ","")
84
+ end
35
85
 
86
+ ##
87
+ # Builds 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.
91
+ def build_path path, params = {}
92
+ params.size > 0 ? [path, hash_to_params(params)].join("?") : path
93
+ end
94
+
95
+ ##
96
+ # Sets 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
36
107
  end
37
108
  end
109
+
38
110
  end
@@ -13,7 +13,6 @@ class Docker::API::Config < Docker::API::Base
13
13
  #
14
14
  # @param params [Hash]: Parameters that are appended to the URL.
15
15
  def list params = {}
16
- validate Docker::API::InvalidParameter, [:filters], params
17
16
  @connection.get(build_path("/configs",params))
18
17
  end
19
18
 
@@ -25,7 +24,6 @@ class Docker::API::Config < Docker::API::Base
25
24
  #
26
25
  # @param body [Hash]: Request body to be sent as json.
27
26
  def create body = {}
28
- validate Docker::API::InvalidRequestBody, [:Name, :Labels, :Data, :Templating], body
29
27
  @connection.request(method: :post, path: "/configs/create", headers: {"Content-Type": "application/json"}, body: body.to_json)
30
28
  end
31
29
 
@@ -52,8 +50,6 @@ class Docker::API::Config < Docker::API::Base
52
50
  #
53
51
  # @param body [Hash]: Request body to be sent as json.
54
52
  def update name, params = {}, body = {}
55
- validate Docker::API::InvalidParameter, [:version], params
56
- validate Docker::API::InvalidRequestBody, [:Name, :Labels, :Data, :Driver, :Templating], body
57
53
  @connection.request(method: :post, path: build_path("/configs/#{name}/update",params), headers: {"Content-Type": "application/json"}, body: body.to_json)
58
54
  end
59
55
 
@@ -1,20 +1,26 @@
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
+ # Calls an Excon request and returns a Docker::API::Response object.
10
+ #
11
+ # @param params [Hash]: Request parameters.
12
+ def request params
13
+ Docker::API::Response.new(@connection.request(params).data)
19
14
  end
15
+
16
+ ##
17
+ # Creates an Excon connection.
18
+ #
19
+ # @param url [String]: URL for the connection.
20
+ # @param params [String]: Additional parameters.
21
+ def initialize url = nil, params = nil
22
+ return @connection = Excon.new('unix:///', {socket: '/var/run/docker.sock'}) unless url
23
+ @connection = Excon.new(url, params || {})
24
+ end
25
+
20
26
  end