docker-swarm 0.1.0 → 0.2.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 +4 -4
- data/lib/docker-swarm.rb +3 -0
- data/lib/docker_swarm/base.rb +12 -1
- data/lib/docker_swarm/configuration.rb +15 -0
- data/lib/docker_swarm/connection.rb +98 -17
- data/lib/docker_swarm/errors.rb +28 -1
- data/lib/docker_swarm/middleware/error_handler.rb +45 -18
- data/lib/docker_swarm/models/volume.rb +2 -6
- data/lib/docker_swarm/version.rb +1 -1
- data/lib/docker_swarm.rb +28 -29
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b43832405fbf723559703102c4d84a42c27c677d601625de43c81ceb2db804d0
|
|
4
|
+
data.tar.gz: 57d9349d4ce67bc9e157c6d235e5cf4925b0af05df53ce0f29fffd2bd888fbb7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72c9fa985935caac2386f9b782ac3728f4c5ffbd121db6f5b36a6e1291eafed9bc5500bd0841385caad69ad5430152b5d11d10261c4ad73fbda86bd9cc7053b3
|
|
7
|
+
data.tar.gz: e841eaa3cad32138f809a40556a2c798fb97e7c92bf40975d2076adbd6650a699eb5635880f6c50d598de2c1017045d61771ff88f7a794f8482a71bdb32b7fe3
|
data/lib/docker-swarm.rb
ADDED
data/lib/docker_swarm/base.rb
CHANGED
|
@@ -13,8 +13,19 @@ module DockerSwarm
|
|
|
13
13
|
Api::ENDPOINTS[resource_name.to_sym]
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# Key in the JSON response that contains the array of items.
|
|
17
|
+
# Override in subclasses if the API returns a wrapped object (e.g., Volumes).
|
|
18
|
+
# @return [String, nil]
|
|
19
|
+
def root_key
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
|
|
16
23
|
def all(filters = {})
|
|
17
|
-
_fetch_all(filters)
|
|
24
|
+
response = _fetch_all(filters)
|
|
25
|
+
return [] if response.blank?
|
|
26
|
+
|
|
27
|
+
data = root_key && response.is_a?(Hash) ? response[root_key] : response
|
|
28
|
+
Array(data).map { |item| new(item) }
|
|
18
29
|
end
|
|
19
30
|
|
|
20
31
|
def find(id)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
5
|
+
module DockerSwarm
|
|
6
|
+
class Configuration
|
|
7
|
+
attr_accessor :socket_path, :logger, :log_level
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@socket_path = "unix:///var/run/docker.sock"
|
|
11
|
+
@logger = Logger.new($stdout)
|
|
12
|
+
@log_level = Logger::INFO
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -10,29 +10,110 @@ module DockerSwarm
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def request(options = {})
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
14
|
+
|
|
15
|
+
log_event("request_started",
|
|
16
|
+
level: :debug,
|
|
17
|
+
data: { method: options[:method], path: options[:path] })
|
|
18
|
+
|
|
19
|
+
response = client.request(options)
|
|
20
|
+
|
|
21
|
+
log_event("request_success",
|
|
22
|
+
data: {
|
|
23
|
+
method: options[:method],
|
|
24
|
+
path: options[:path],
|
|
25
|
+
status: response.status,
|
|
26
|
+
duration_ms: calculate_duration(start_time)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
response.body
|
|
15
30
|
rescue => e
|
|
16
|
-
|
|
17
|
-
|
|
31
|
+
# Excon suele envolver excepciones de middleware en Excon::Error::Socket.
|
|
32
|
+
# Intentamos recuperar la causa original si es una de nuestras excepciones.
|
|
33
|
+
actual_error = (e.respond_to?(:cause) && e.cause&.class&.name&.include?("DockerSwarm::Error")) ? e.cause : e
|
|
34
|
+
|
|
35
|
+
log_event("request_failure",
|
|
36
|
+
level: :error,
|
|
37
|
+
data: {
|
|
38
|
+
method: options[:method],
|
|
39
|
+
path: options[:path],
|
|
40
|
+
error: actual_error.class.name,
|
|
41
|
+
message: actual_error.message,
|
|
42
|
+
duration_ms: calculate_duration(start_time)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
if actual_error.class.name.include?("DockerSwarm::Error")
|
|
46
|
+
raise actual_error
|
|
47
|
+
elsif actual_error.is_a?(Excon::Error::Socket)
|
|
48
|
+
raise ::DockerSwarm::Error::Communication, "Docker socket error: #{actual_error.message}"
|
|
18
49
|
else
|
|
19
|
-
raise
|
|
50
|
+
raise actual_error
|
|
20
51
|
end
|
|
21
52
|
end
|
|
53
|
+
|
|
22
54
|
private
|
|
23
55
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
56
|
+
def log_event(event, level: :info, data: {})
|
|
57
|
+
return unless logger
|
|
58
|
+
# Respetar el nivel de log antes de procesar nada
|
|
59
|
+
return if level == :debug && logger.level > Logger::DEBUG
|
|
60
|
+
|
|
61
|
+
log_block = proc do
|
|
62
|
+
begin
|
|
63
|
+
payload = {
|
|
64
|
+
component: "docker_swarm.connection",
|
|
65
|
+
event: event,
|
|
66
|
+
source: "http"
|
|
67
|
+
}.merge(data)
|
|
68
|
+
|
|
69
|
+
payload.map do |k, v|
|
|
70
|
+
val = k.to_s =~ /password|token|api_key|auth|secret/i ? "[FILTERED]" : v
|
|
71
|
+
"#{k}=#{val}"
|
|
72
|
+
end.join(" ")
|
|
73
|
+
rescue
|
|
74
|
+
"component=docker_swarm.connection event=logging_error"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if level == :debug
|
|
79
|
+
logger.debug(&log_block)
|
|
80
|
+
else
|
|
81
|
+
logger.send(level, log_block.call)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def calculate_duration(start_time)
|
|
86
|
+
((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) * 1000).round(2)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def common_middlewares
|
|
90
|
+
# Usamos los middlewares por defecto de Excon para garantizar que todas las llaves internas
|
|
91
|
+
# (como :retries_remaining o :instrumentor_name) se inicialicen correctamente.
|
|
92
|
+
Excon.defaults[:middlewares] + [
|
|
93
|
+
Excon::Middleware::RedirectFollower,
|
|
94
|
+
Middleware::RequestEncoder,
|
|
95
|
+
Middleware::ResponseJSONParser,
|
|
96
|
+
Middleware::ErrorHandler
|
|
97
|
+
]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def client
|
|
101
|
+
debug_enabled = logger&.level == Logger::DEBUG
|
|
102
|
+
|
|
103
|
+
options = {
|
|
104
|
+
middlewares: common_middlewares,
|
|
105
|
+
logger: logger,
|
|
106
|
+
debug_request: debug_enabled,
|
|
107
|
+
debug_response: debug_enabled,
|
|
108
|
+
# Si debug_enabled es true, Excon usará su lógica interna de debug con el logger proporcionado
|
|
109
|
+
retry_limit: 0
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@client ||= if socket_path.start_with?("unix://")
|
|
113
|
+
Excon.new("unix:///", options.merge(socket: socket_path.sub(/^unix:\/\//, "")))
|
|
114
|
+
else
|
|
115
|
+
Excon.new(socket_path, options)
|
|
116
|
+
end
|
|
36
117
|
end
|
|
37
118
|
end
|
|
38
119
|
end
|
data/lib/docker_swarm/errors.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module DockerSwarm
|
|
4
4
|
class Error < StandardError; end
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
class Error
|
|
7
7
|
class BadRequest < Error; end
|
|
8
8
|
class Unauthorized < Error; end
|
|
9
9
|
class Forbidden < Error; end
|
|
@@ -19,4 +19,31 @@ module DockerSwarm
|
|
|
19
19
|
class TooManyRequests < Error; end
|
|
20
20
|
class Communication < Error; end
|
|
21
21
|
end
|
|
22
|
+
|
|
23
|
+
# Aliases para permitir acceso directo DockerSwarm::Conflict
|
|
24
|
+
BadRequest = Error::BadRequest
|
|
25
|
+
Unauthorized = Error::Unauthorized
|
|
26
|
+
Forbidden = Error::Forbidden
|
|
27
|
+
NotFound = Error::NotFound
|
|
28
|
+
NotAcceptable = Error::NotAcceptable
|
|
29
|
+
RequestTimeout = Error::RequestTimeout
|
|
30
|
+
Conflict = Error::Conflict
|
|
31
|
+
UnprocessableEntity = Error::UnprocessableEntity
|
|
32
|
+
InternalServerError = Error::InternalServerError
|
|
33
|
+
BadGateway = Error::BadGateway
|
|
34
|
+
ServiceUnavailable = Error::ServiceUnavailable
|
|
35
|
+
GatewayTimeout = Error::GatewayTimeout
|
|
36
|
+
TooManyRequests = Error::TooManyRequests
|
|
37
|
+
Communication = Error::Communication
|
|
38
|
+
|
|
39
|
+
# Módulo Errors para compatibilidad adicional
|
|
40
|
+
module Errors
|
|
41
|
+
def self.const_missing(name)
|
|
42
|
+
if ::DockerSwarm::Error.const_defined?(name)
|
|
43
|
+
::DockerSwarm::Error.const_get(name)
|
|
44
|
+
else
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
22
49
|
end
|
|
@@ -9,31 +9,58 @@ module DockerSwarm
|
|
|
9
9
|
status = env[:response][:status]
|
|
10
10
|
body = env[:response][:body]
|
|
11
11
|
|
|
12
|
+
return @stack.response_call(env) if (200..299).include?(status)
|
|
13
|
+
|
|
14
|
+
error_msg = error_message(body)
|
|
15
|
+
log_business_error(env, status, error_msg)
|
|
16
|
+
|
|
12
17
|
case status
|
|
13
|
-
when
|
|
14
|
-
|
|
15
|
-
when
|
|
16
|
-
when
|
|
17
|
-
when
|
|
18
|
-
when
|
|
19
|
-
when
|
|
20
|
-
when
|
|
21
|
-
when
|
|
22
|
-
when
|
|
23
|
-
when
|
|
24
|
-
when
|
|
25
|
-
when
|
|
26
|
-
when 503 then raise Errors::ServiceUnavailable, error_message(body)
|
|
27
|
-
when 504 then raise Errors::GatewayTimeout, error_message(body)
|
|
18
|
+
when 400 then raise ::DockerSwarm::BadRequest, error_msg
|
|
19
|
+
when 401 then raise ::DockerSwarm::Unauthorized, error_msg
|
|
20
|
+
when 403 then raise ::DockerSwarm::Forbidden, error_msg
|
|
21
|
+
when 404 then raise ::DockerSwarm::NotFound, error_msg
|
|
22
|
+
when 406 then raise ::DockerSwarm::NotAcceptable, error_msg
|
|
23
|
+
when 408 then raise ::DockerSwarm::RequestTimeout, error_msg
|
|
24
|
+
when 409 then raise ::DockerSwarm::Conflict, error_msg
|
|
25
|
+
when 422 then raise ::DockerSwarm::UnprocessableEntity, body
|
|
26
|
+
when 429 then raise ::DockerSwarm::TooManyRequests, error_msg
|
|
27
|
+
when 500 then raise ::DockerSwarm::InternalServerError, error_msg
|
|
28
|
+
when 502 then raise ::DockerSwarm::BadGateway, error_msg
|
|
29
|
+
when 503 then raise ::DockerSwarm::ServiceUnavailable, error_msg
|
|
30
|
+
when 504 then raise ::DockerSwarm::GatewayTimeout, error_msg
|
|
28
31
|
else
|
|
29
|
-
raise
|
|
32
|
+
raise ::DockerSwarm::Error, "HTTP #{status}: #{error_msg}"
|
|
30
33
|
end
|
|
31
|
-
|
|
32
|
-
@stack.response_call(env)
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
private
|
|
36
37
|
|
|
38
|
+
def log_business_error(env, status, message)
|
|
39
|
+
logger = env[:logger]
|
|
40
|
+
return unless logger
|
|
41
|
+
|
|
42
|
+
begin
|
|
43
|
+
payload = {
|
|
44
|
+
component: "docker_swarm.middleware.error_handler",
|
|
45
|
+
event: "business_error",
|
|
46
|
+
source: "http",
|
|
47
|
+
status: status,
|
|
48
|
+
message: message,
|
|
49
|
+
method: env[:method],
|
|
50
|
+
path: env[:path]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
kv_string = payload.map do |k, v|
|
|
54
|
+
val = k.to_s =~ /password|token|api_key|auth|secret/i ? "[FILTERED]" : v
|
|
55
|
+
"#{k}=#{val}"
|
|
56
|
+
end.join(" ")
|
|
57
|
+
|
|
58
|
+
logger.error(kv_string)
|
|
59
|
+
rescue
|
|
60
|
+
# Resilience: logging should not crash the app
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
37
64
|
def error_message(body)
|
|
38
65
|
if body.is_a?(Hash)
|
|
39
66
|
body["message"] || body["error"] || body.to_json
|
|
@@ -5,12 +5,8 @@ module DockerSwarm
|
|
|
5
5
|
include Concerns::Creatable
|
|
6
6
|
include Concerns::Deletable
|
|
7
7
|
|
|
8
|
-
def self.
|
|
9
|
-
|
|
10
|
-
return [] if response.blank?
|
|
11
|
-
|
|
12
|
-
data = response.is_a?(Hash) ? response["Volumes"] : response
|
|
13
|
-
Array(data).map { |item| new(item) }
|
|
8
|
+
def self.root_key
|
|
9
|
+
"Volumes"
|
|
14
10
|
end
|
|
15
11
|
end
|
|
16
12
|
end
|
data/lib/docker_swarm/version.rb
CHANGED
data/lib/docker_swarm.rb
CHANGED
|
@@ -7,6 +7,34 @@ require "excon"
|
|
|
7
7
|
require "json"
|
|
8
8
|
require "logger"
|
|
9
9
|
|
|
10
|
+
module DockerSwarm
|
|
11
|
+
class << self
|
|
12
|
+
attr_accessor :configuration
|
|
13
|
+
|
|
14
|
+
def configure
|
|
15
|
+
@configuration ||= Configuration.new
|
|
16
|
+
yield(@configuration) if block_given?
|
|
17
|
+
|
|
18
|
+
if @configuration.logger.respond_to?(:level=)
|
|
19
|
+
@configuration.logger.level = @configuration.log_level
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
@connection = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def connection
|
|
26
|
+
configure unless @configuration
|
|
27
|
+
@connection ||= Connection.new(@configuration.socket_path, @configuration.logger)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def request(options = {})
|
|
31
|
+
connection.request(options)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Primero cargamos la configuración porque la clase DockerSwarm la usa arriba
|
|
37
|
+
require_relative "docker_swarm/configuration"
|
|
10
38
|
require_relative "docker_swarm/version"
|
|
11
39
|
require_relative "docker_swarm/errors"
|
|
12
40
|
require_relative "docker_swarm/middleware/request_encoder"
|
|
@@ -31,32 +59,3 @@ require_relative "docker_swarm/models/network"
|
|
|
31
59
|
require_relative "docker_swarm/models/config"
|
|
32
60
|
require_relative "docker_swarm/models/secret"
|
|
33
61
|
require_relative "docker_swarm/models/volume"
|
|
34
|
-
|
|
35
|
-
module DockerSwarm
|
|
36
|
-
class << self
|
|
37
|
-
attr_accessor :configuration
|
|
38
|
-
|
|
39
|
-
def configure
|
|
40
|
-
self.configuration ||= Configuration.new
|
|
41
|
-
yield(configuration) if block_given?
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def connection
|
|
45
|
-
configure unless configuration
|
|
46
|
-
@connection ||= Connection.new(configuration.socket_path, configuration.logger)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def request(options = {})
|
|
50
|
-
connection.request(options)
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
class Configuration
|
|
55
|
-
attr_accessor :socket_path, :logger
|
|
56
|
-
|
|
57
|
-
def initialize
|
|
58
|
-
@socket_path = "unix:///var/run/docker.sock"
|
|
59
|
-
@logger = defined?(Rails) ? Rails.logger : Logger.new($stdout)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: docker-swarm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gabriel
|
|
@@ -89,12 +89,14 @@ extensions: []
|
|
|
89
89
|
extra_rdoc_files: []
|
|
90
90
|
files:
|
|
91
91
|
- README.md
|
|
92
|
+
- lib/docker-swarm.rb
|
|
92
93
|
- lib/docker_swarm.rb
|
|
93
94
|
- lib/docker_swarm/api.rb
|
|
94
95
|
- lib/docker_swarm/base.rb
|
|
95
96
|
- lib/docker_swarm/concerns/creatable.rb
|
|
96
97
|
- lib/docker_swarm/concerns/deletable.rb
|
|
97
98
|
- lib/docker_swarm/concerns/updatable.rb
|
|
99
|
+
- lib/docker_swarm/configuration.rb
|
|
98
100
|
- lib/docker_swarm/connection.rb
|
|
99
101
|
- lib/docker_swarm/errors.rb
|
|
100
102
|
- lib/docker_swarm/middleware/error_handler.rb
|