Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,12 +552,6 @@ response.success?
=> true
```

### Error handling

`Docker::API::InvalidParameter` and `Docker::API::InvalidRequestBody` may be raised when an invalid option is passed as argument (ie: an option not described in Docker API documentation for request query parameters nor request body (json) parameters). Even if no errors were raised, consider validating the status code and/or message of the response to check if the Docker daemon has fulfilled the operation properly.

To completely skip the validation process, add `:skip_validation => true` in the hash to be validated.

### Blocks

Some methods can receive a block to alter the default execution:
Expand Down
32 changes: 2 additions & 30 deletions lib/docker/api/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ class Docker::API::Base
#
# @param connection [Docker::API::Connection]: Connection to be used.
def initialize connection = nil
raise Docker::API::Error.new("Expected connection to be a Docker::API::Connection class") if connection != nil && !connection.is_a?(Docker::API::Connection)
raise StandardError.new("Expected connection to be a Docker::API::Connection class") if connection != nil && !connection.is_a?(Docker::API::Connection)
@connection = connection || Docker::API::Connection.new
set_automated_validation
end

private
Expand Down Expand Up @@ -59,18 +58,6 @@ def auth_encoder(authentication)
Base64.urlsafe_encode64(authentication.to_json.to_s).chomp
end

##
# Validate a Hash object comparing its keys with a given Array of permitted values. Raise an error if the validation fail.
#
# @param error [Error]: Error to be raised of the validation fail.
# @param permitted [Array]: List of permitted keys.
# @param params [Hash]: Hash object to be validated.
def validate error, permitted, params
return if params[:skip_validation]
unpermitted = params.keys.map(&:to_s) - permitted.map(&:to_s)
raise error.new(permitted, unpermitted) if unpermitted.size > 0
end

##
# Convert Ruby Hash into URL query parameters.
#
Expand All @@ -79,7 +66,7 @@ def validate error, permitted, params
# @param hash [Hash]: Hash object to be converted in a query parameter-like string.
def hash_to_params hash
p = []
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}") }
hash.each { |k,v| p.push( v.is_a?(Hash) ? "#{k}=#{v.to_json}" : "#{k}=#{v}") }
p.join("&").gsub(" ","")
end

Expand All @@ -93,19 +80,4 @@ def build_path path, params = {}
params.size > 0 ? [path, hash_to_params(params)].join("?") : path
end

##
# Set the validation to happen automatically when method parameters include "params" or "body".
def set_automated_validation
(self.methods - Object.methods).each do |method|
params_index = method(method).parameters.map{|ar| ar[1]}.index(:params)
body_index = method(method).parameters.map{|ar| ar[1]}.index(:body)

define_singleton_method(method) do |*args, &block|
validate Docker::API::InvalidParameter, Docker::API::VALID_PARAMS["#{self.class.name}"]["#{method}"], (args[params_index] || {}) if params_index
validate Docker::API::InvalidRequestBody, Docker::API::VALID_BODY["#{self.class.name}"]["#{method}"], (args[body_index] || {}) if body_index
super(*args,&block)
end
end
end

end
33 changes: 0 additions & 33 deletions lib/docker/api/error.rb

This file was deleted.

2 changes: 1 addition & 1 deletion lib/docker/api/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def import path, params = {}
# @param params [Hash]: Parameters that are appended to the URL.
# @param authentication [Hash]: Authentication parameters.
def push name, params = {}, authentication = {}
raise Docker::API::Error.new("Provide authentication parameters to push an image") unless authentication.any?
raise StandardError.new("Provide authentication parameters to push an image") unless authentication.any?
@connection.request(method: :post, path: build_path("/images/#{name}/push", params), headers: { "X-Registry-Auth" => auth_encoder(authentication) } )
end

Expand Down
139 changes: 0 additions & 139 deletions lib/dockerapi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
require "fileutils"

require "docker/api/version"
require "docker/api/error"
require "docker/api/connection"
require "docker/api/response"
require "docker/api/base"
Expand Down Expand Up @@ -44,144 +43,6 @@ def self.print_response_to_stdout=(bool)
@@print_response_to_stdout = bool
end
self.print_response_to_stdout = false

##
# Valid values for parameter validations.
VALID_PARAMS = {
"Docker::API::Image" => {
"build" => [:dockerfile, :t, :extrahosts, :remote, :q, :nocache, :cachefrom, :pull, :rm, :forcerm, :memory, :memswap, :cpushares, :cpusetcpus, :cpuperiod, :cpuquota, :buildargs, :shmsize, :squash, :labels, :networkmode, :platform, :target, :outputs],
"prune" => [:filters],
"list" => [:all, :filters, "shared-size", :digests],
"search" => [:term, :limit, :filters],
"tag" => [:repo, :tag],
"remove" => [:force, :noprune],
"import" => [:quiet],
"push" => [:tag],
"commit" => [:container, :repo, :tag, :comment, :author, :pause, :changes],
"create" => [:fromImage, :fromSrc, :repo, :tag, :message, :changes, :platform],
"delete_cache" => [:all, "keep-storage", :filters]
},
"Docker::API::Container" => {
"list" => [:all, :limit, :size, :filters],
"details" => [:size],
"top" => [:ps_args],
"start" => [:detachKeys],
"stop" => [:signal, :t],
"restart" => [:signal, :t],
"kill" => [:signal],
"wait" => [:condition],
"rename" => [:name],
"resize" => [:w, :h],
"prune" => [:filters],
"remove" => [:v, :force, :link],
"logs" => [:follow, :stdout, :stderr, :since, :until, :timestamps, :tail],
"attach" => [:detachKeys, :logs, :stream, :stdin, :stdout, :stderr],
"stats" => [:stream, "one-shot"],
"get_archive" => [:path],
"put_archive" => [:path, :noOverwriteDirNonDir, :copyUIDGID],
"create" => [:name, :platform]
},
"Docker::API::Volume" => {
"list" => [:filters],
"remove" => [:force],
"prune" => [:filters]
},
"Docker::API::Network" => {
"list" => [:filters],
"details" => [:verbose, :scope],
"prune" => [:filters]
},
"Docker::API::System" => {
"events" => [:since, :until, :filters],
"df" => [:type]
},
"Docker::API::Exec" => {
"resize" => [:w, :h]
},
"Docker::API::Swarm" => {
"leave" => [:force],
"update" => [:version, :rotateWorkerToken, :rotateManagerToken, :rotateManagerUnlockKey]
},
"Docker::API::Node" => {
"list" => [:filters],
"update" => [:version],
"delete" => [:force]
},
"Docker::API::Service" => {
"list" => [:filters, :status],
"update" => [:version, :registryAuthFrom, :rollback],
"details" => [:insertDefaults],
"logs" => [:details, :follow, :stdout, :stderr, :since, :timestamps, :tail]
},
"Docker::API::Secret" => {
"list" => [:filters],
"update" => [:version]
},
"Docker::API::Task" => {
"list" => [:filters],
"logs" => [:details, :follow, :stdout, :stderr, :since, :timestamps, :tail]
},
"Docker::API::Plugin" => {
"list" => [:filters],
"privileges" => [:remote],
"install" => [:remote, :name],
"remove" => [:force],
"enable" => [:timeout],
"upgrade" => [:remote]
},
"Docker::API::Config" => {
"list" => [:filters],
"update" => [:version]
}
}

##
# Valid values for request body validations.
VALID_BODY = {
"Docker::API::Image" => {
"commit" => [:Hostname, :Domainname, :User, :AttachStdin, :AttachStdout, :AttachStderr, :ExposedPorts, :Tty, :OpenStdin, :StdinOnce, :Env, :Cmd, :HealthCheck, :ArgsEscaped, :Image, :Volumes, :WorkingDir, :Entrypoint, :NetworkDisabled, :MacAddress, :OnBuild, :Labels, :StopSignal, :StopTimeout, :Shell]
},
"Docker::API::Container" => {
"create" => [:Hostname,:Domainname,:User,:AttachStdin,:AttachStdout,:AttachStderr,:ExposedPorts,:Tty,:OpenStdin,:StdinOnce,:Env,:Cmd,:HealthCheck,:ArgsEscaped,:Image,:Volumes,:WorkingDir,:Entrypoint,:NetworkDisabled,:MacAddress,:OnBuild,:Labels,:StopSignal,:StopTimeout,:Shell,:HostConfig,:NetworkingConfig],
"update" => [:CpuShares, :Memory, :CgroupParent, :BlkioWeight, :BlkioWeightDevice, :BlkioDeviceReadBps, :BlkioDeviceWriteBps, :BlkioDeviceReadIOps, :BlkioDeviceWriteIOps, :CpuPeriod, :CpuQuota, :CpuRealtimePeriod, :CpuRealtimeRuntime, :CpusetCpus, :CpusetMems, :Devices, :DeviceCgroupRules, :DeviceRequest, :Memory, :KernelMemoryTCP, :MemoryReservation, :MemorySwap, :MemorySwappiness, :NanoCPUs, :OomKillDisable, :Init, :PidsLimit, :ULimits, :CpuCount, :CpuPercent, :IOMaximumIOps, :IOMaximumBandwidth, :RestartPolicy]
},
"Docker::API::Volume" => {
"create" => [:Name, :Driver, :DriverOpts, :Labels, :ClusterVolumeSpec]
},
"Docker::API::Network" => {
"create" => [:Name, :CheckDuplicate, :Driver, :Internal, :Attachable, :Ingress, :IPAM, :EnableIPv6, :Options, :Labels],
"connect" => [:Container, :EndpointConfig],
"disconnect" => [:Container, :Force]
},
"Docker::API::System" => {
"auth" => [:username, :password, :email, :serveraddress, :identitytoken]
},
"Docker::API::Exec" => {
"create" => [:AttachStdin, :AttachStdout, :AttachStderr, :ConsoleSize, :DetachKeys, :Tty, :Env, :Cmd, :Privileged, :User, :WorkingDir],
"start" => [:Detach, :Tty, :ConsoleSize]
},
"Docker::API::Swarm" => {
"init" => [:ListenAddr, :AdvertiseAddr, :DataPathAddr, :DataPathPort, :DefaultAddrPool, :ForceNewCluster, :SubnetSize, :Spec],
"update" => [:Name, :Labels, :Orchestration, :Raft, :Dispatcher, :CAConfig, :EncryptionConfig, :TaskDefaults],
"unlock" => [:UnlockKey],
"join" => [:ListenAddr, :AdvertiseAddr, :DataPathAddr, :RemoteAddrs, :JoinToken]
},
"Docker::API::Node" => {
"update" => [:Name, :Labels, :Role, :Availability]
},
"Docker::API::Service" => {
"create" => [:Name, :Labels, :TaskTemplate, :Mode, :UpdateConfig, :RollbackConfig, :Networks, :EndpointSpec],
"update" => [:Name, :Labels, :TaskTemplate, :Mode, :UpdateConfig, :RollbackConfig, :Networks, :EndpointSpec]
},
"Docker::API::Secret" => {
"create" => [:Name, :Labels, :Data, :Driver, :Templating],
"update" => [:Name, :Labels, :Data, :Driver, :Templating]
},
"Docker::API::Config" => {
"create" => [:Name, :Labels, :Data, :Templating],
"update" => [:Name, :Labels, :Data, :Templating]
}
}

end
end
8 changes: 4 additions & 4 deletions spec/endpoints/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
it { expect(subject.list(filters: {id: { "config-id": true }}).request_params[:path]).to eq('/v1.43/configs?filters={"id":{"config-id":true}}') }
it { expect(subject.list(filters: {label: { "label=key": true }}).request_params[:path]).to eq('/v1.43/configs?filters={"label":{"label=key":true}}') }
it { expect(subject.list(filters: {name: { "config-name": true }}).request_params[:path]).to eq('/v1.43/configs?filters={"name":{"config-name":true}}') }
it { expect{subject.list(invalid: true)}.to raise_error(Docker::API::InvalidParameter) }
it { expect{subject.list(invalid: true)}.not_to raise_error }
end

describe ".create" do
it { expect(subject.create.request_params[:path]).to eq('/v1.43/configs/create') }
it { expect(subject.create.request_params[:method]).to eq(:post) }
it { expect(subject.create(Name: "rspec-config").request_params[:body]).to eq('{"Name":"rspec-config"}') }
it { expect(subject.create({Name: "rspec-config",Labels: {foo: "bar"}, Data: "VEhJUyBJUyBOT1QgQSBSRUFMIENFUlRJRklDQVRFCg=="}).request_params[:body]).to eq('{"Name":"rspec-config","Labels":{"foo":"bar"},"Data":"VEhJUyBJUyBOT1QgQSBSRUFMIENFUlRJRklDQVRFCg=="}') }
it { expect{subject.create(invalid: true)}.to raise_error(Docker::API::InvalidRequestBody) }
it { expect{subject.create(invalid: true)}.not_to raise_error }
end

describe ".details" do
Expand All @@ -46,8 +46,8 @@

it { expect(subject.update("rspec-config", {version: version}, spec).request_params[:path]).to eq('/v1.43/v1.43/configs/rspec-config/update?version=abc') }
it { expect(subject.update("rspec-config", {version: version}, spec).request_params[:method]).to eq(:post) }
it { expect{subject.update("rspec-config", invalid: true)}.to raise_error(Docker::API::InvalidParameter) }
it { expect{subject.update("rspec-config", {version: version}, {invalid: true})}.to raise_error(Docker::API::InvalidRequestBody) }
it { expect{subject.update("rspec-config", invalid: true)}.not_to raise_error }
it { expect{subject.update("rspec-config", {version: version}, {invalid: true})}.not_to raise_error }
end

describe ".delete" do
Expand Down
Loading