docker-swarm 0.2.0 → 0.4.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/README.md +12 -17
- data/lib/docker_swarm/base.rb +10 -1
- data/lib/docker_swarm/concerns/inspectable.rb +28 -0
- data/lib/docker_swarm/concerns/loggable.rb +16 -0
- data/lib/docker_swarm/configuration.rb +21 -0
- data/lib/docker_swarm/connection.rb +38 -41
- data/lib/docker_swarm/log_helper.rb +20 -0
- data/lib/docker_swarm/middleware/error_handler.rb +2 -7
- data/lib/docker_swarm/middleware/request_encoder.rb +19 -3
- data/lib/docker_swarm/middleware/response_json_parser.rb +19 -7
- data/lib/docker_swarm/models/config.rb +2 -0
- data/lib/docker_swarm/models/container.rb +9 -4
- data/lib/docker_swarm/models/image.rb +2 -0
- data/lib/docker_swarm/models/network.rb +0 -9
- data/lib/docker_swarm/models/node.rb +2 -0
- data/lib/docker_swarm/models/secret.rb +2 -0
- data/lib/docker_swarm/models/service.rb +1 -16
- data/lib/docker_swarm/models/swarm.rb +6 -0
- data/lib/docker_swarm/models/system.rb +12 -0
- data/lib/docker_swarm/models/task.rb +3 -3
- data/lib/docker_swarm/version.rb +1 -1
- data/lib/docker_swarm.rb +10 -3
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 78ad878518bedd7c1ac7355efbb6372b49f2721fd7db5a3b0536b0872ed9f3ea
|
|
4
|
+
data.tar.gz: 6a5b9b06a1c43e8735d111cda5e9eb65820101fe515832fdf64647834310ad12
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 762b554eb9e1321d1cb2cb82867809b816ba7e7a84ee55e1e34b571b0942aba9e13020d8b7019dc40c70d4457b3307f9d72ca5cc98cd5de26207c9bf9ce70c1b
|
|
7
|
+
data.tar.gz: e092c1f28b3de38986f3f5e207dd1aafeac8449448e861675aa0be88ee4763f71aa663fc9ee8c1b3bafcfe1997b3917a0924ca9dea777b484b5163bd4b197d45
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://badge.fury.io/rb/docker-swarm)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
`docker-swarm` es un ORM ligero y cliente API robusto para interactuar con Docker Swarm desde Ruby. Diseñado para sentirse familiar a los desarrolladores de Rails, utiliza `ActiveModel` para ofrecer una interfaz limpia y potente.
|
|
6
|
+
`docker-swarm` es un ORM ligero y cliente API robusto para interactuar con Docker Swarm desde Ruby. Diseñado para sentirse familiar a los desarrolladores de Rails, utiliza `ActiveModel` para ofrecer una interfaz limpia y potente con estándares de observabilidad de Wispro.
|
|
7
7
|
|
|
8
8
|
## 🚀 Inicio Rápido
|
|
9
9
|
|
|
@@ -13,42 +13,37 @@ require 'docker_swarm'
|
|
|
13
13
|
# Configurar (opcional, usa defaults)
|
|
14
14
|
DockerSwarm.configure do |config|
|
|
15
15
|
config.socket_path = "unix:///var/run/docker.sock"
|
|
16
|
+
config.log_level = Logger::INFO
|
|
17
|
+
config.read_timeout = 30
|
|
18
|
+
config.max_retries = 3
|
|
16
19
|
end
|
|
17
20
|
|
|
18
|
-
# Listar servicios
|
|
21
|
+
# Listar servicios (con soporte para Indifferent Access en arrays)
|
|
19
22
|
services = DockerSwarm::Service.all
|
|
20
|
-
services.each { |s| puts "#{s.ID}: #{s.Spec[
|
|
23
|
+
services.each { |s| puts "#{s.ID}: #{s.Spec[:Name]}" }
|
|
21
24
|
|
|
22
25
|
# Crear un nuevo servicio
|
|
23
26
|
service = DockerSwarm::Service.create(
|
|
27
|
+
Name: "my-webapp",
|
|
24
28
|
Spec: {
|
|
25
|
-
Name: "my-webapp",
|
|
26
29
|
TaskTemplate: {
|
|
27
30
|
ContainerSpec: { Image: "nginx:latest" }
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
)
|
|
31
34
|
|
|
32
|
-
# Obtener logs
|
|
35
|
+
# Obtener logs (stdout y stderr habilitados por defecto)
|
|
33
36
|
puts service.logs
|
|
34
37
|
```
|
|
35
38
|
|
|
36
|
-
## 📖 Documentación Completa
|
|
37
|
-
|
|
38
|
-
Para profundizar en el uso de la gema, consulta las siguientes guías:
|
|
39
|
-
|
|
40
|
-
1. **[Guía de Configuración](docs/configuration.md)**: Cómo configurar el socket, logger y opciones globales.
|
|
41
|
-
2. **[Uso del ORM (Modelos)](docs/models.md)**: Todo sobre el ciclo de vida de los recursos (`Service`, `Node`, `Task`, etc.).
|
|
42
|
-
3. **[Cliente de API (Bajo Nivel)](docs/api.md)**: Cómo realizar peticiones personalizadas directamente a la API de Docker.
|
|
43
|
-
4. **[Manejo de Errores](docs/errors.md)**: Jerarquía de excepciones y mapeo de errores de Docker.
|
|
44
|
-
5. **[Pruebas y Mocking](docs/testing.md)**: Guía para testear tu aplicación sin depender de un socket de Docker real.
|
|
45
|
-
|
|
46
39
|
## 🛠 Características Clave
|
|
47
40
|
|
|
41
|
+
- **Observabilidad Wispro**: Logging estructurado (KV) con `component`, `event`, `source` y `duration_ms` usando reloj monotónico.
|
|
42
|
+
- **Seguridad**: Enmascaramiento automático de secretos (`password`, `token`, etc.) en los logs.
|
|
43
|
+
- **Deep Indifferent Access**: Acceso a atributos mediante símbolos o strings, incluso en resultados de listados (`.all`).
|
|
44
|
+
- **Resiliencia**: Gestión inteligente de timeouts (`read`, `write`, `connect`) y reintentos automáticos para errores de red.
|
|
48
45
|
- **Mapeo PascalCase**: Mantiene la fidelidad con los atributos de Docker (e.g., `s.ID`, `s.Spec`) evitando transformaciones costosas.
|
|
49
46
|
- **ActiveModel Ready**: Soporta validaciones, serialización JSON y comportamientos estándar de modelos Ruby.
|
|
50
|
-
- **Surgical Updates**: Actualizaciones precisas enviando solo el índice de versión y el payload necesario.
|
|
51
|
-
- **Excon Stack**: Basado en `Excon` con middlewares para encoding de peticiones, parseo de respuestas y gestión de errores.
|
|
52
47
|
|
|
53
48
|
## 🤝 Contribuir
|
|
54
49
|
|
data/lib/docker_swarm/base.rb
CHANGED
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
module DockerSwarm
|
|
4
4
|
class Base
|
|
5
5
|
include ActiveModel::Model
|
|
6
|
+
include Concerns::Inspectable
|
|
6
7
|
|
|
7
8
|
class << self
|
|
8
9
|
def resource_name
|
|
9
10
|
name.demodulize.downcase.pluralize
|
|
10
11
|
end
|
|
11
12
|
|
|
13
|
+
# Cache of attributes already defined for this class
|
|
14
|
+
# @return [Set]
|
|
15
|
+
def defined_attributes
|
|
16
|
+
@defined_attributes ||= Set.new([ :validation_context, :errors, :context_for_validation ])
|
|
17
|
+
end
|
|
18
|
+
|
|
12
19
|
def routes
|
|
13
20
|
Api::ENDPOINTS[resource_name.to_sym]
|
|
14
21
|
end
|
|
@@ -156,8 +163,10 @@ module DockerSwarm
|
|
|
156
163
|
private
|
|
157
164
|
|
|
158
165
|
def _define_dynamic_accessor(key)
|
|
159
|
-
return if self.class.
|
|
166
|
+
return if self.class.defined_attributes.include?(key.to_sym)
|
|
167
|
+
|
|
160
168
|
self.class.send(:attr_accessor, key)
|
|
169
|
+
self.class.defined_attributes.add(key.to_sym)
|
|
161
170
|
end
|
|
162
171
|
|
|
163
172
|
def _valid_attribute_name?(name)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DockerSwarm
|
|
4
|
+
module Concerns
|
|
5
|
+
module Inspectable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
def inspect
|
|
9
|
+
inspection = if respond_to?(:ID) && ID.present?
|
|
10
|
+
"ID: #{ID}"
|
|
11
|
+
else
|
|
12
|
+
"not persisted"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Intentar añadir el nombre si existe
|
|
16
|
+
name_attr = attributes["Name"] || (respond_to?(:Name) ? Name : nil)
|
|
17
|
+
inspection += ", Name: #{name_attr}" if name_attr.present?
|
|
18
|
+
|
|
19
|
+
# Intentar añadir la imagen para servicios/contenedores
|
|
20
|
+
spec = attributes["Spec"] || (respond_to?(:Spec) ? Spec : nil)
|
|
21
|
+
image = spec&.dig("TaskTemplate", "ContainerSpec", "Image") || attributes["Image"] || (respond_to?(:Image) ? Image : nil)
|
|
22
|
+
inspection += ", Image: #{image}" if image.present?
|
|
23
|
+
|
|
24
|
+
"#<#{self.class.name} #{inspection}>"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DockerSwarm
|
|
4
|
+
module Concerns
|
|
5
|
+
module Loggable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
# Fetches logs for the resource
|
|
9
|
+
# @param query_params [Hash] Query parameters for the logs endpoint (stdout, stderr, follow, etc.)
|
|
10
|
+
# @return [String] The raw log stream
|
|
11
|
+
def logs(query_params = { stdout: 1, stderr: 1 })
|
|
12
|
+
Api.request(action: self.class.routes[:logs], arguments: { id: self.ID }, query_params: query_params)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -5,11 +5,32 @@ require "logger"
|
|
|
5
5
|
module DockerSwarm
|
|
6
6
|
class Configuration
|
|
7
7
|
attr_accessor :socket_path, :logger, :log_level
|
|
8
|
+
attr_reader :read_timeout, :write_timeout, :connect_timeout, :max_retries
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
@socket_path = "unix:///var/run/docker.sock"
|
|
11
12
|
@logger = Logger.new($stdout)
|
|
12
13
|
@log_level = Logger::INFO
|
|
14
|
+
@read_timeout = 60.0
|
|
15
|
+
@write_timeout = 60.0
|
|
16
|
+
@connect_timeout = 10.0
|
|
17
|
+
@max_retries = 3
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def read_timeout=(val)
|
|
21
|
+
@read_timeout = val&.to_f
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def write_timeout=(val)
|
|
25
|
+
@write_timeout = val&.to_f
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def connect_timeout=(val)
|
|
29
|
+
@connect_timeout = val&.to_f
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def max_retries=(val)
|
|
33
|
+
@max_retries = val&.to_i
|
|
13
34
|
end
|
|
14
35
|
end
|
|
15
36
|
end
|
|
@@ -11,37 +11,43 @@ module DockerSwarm
|
|
|
11
11
|
|
|
12
12
|
def request(options = {})
|
|
13
13
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
14
|
-
|
|
15
|
-
log_event("request_started",
|
|
14
|
+
|
|
15
|
+
log_event("request_started",
|
|
16
16
|
level: :debug,
|
|
17
|
-
data:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
data: options.merge(path: options[:path]))
|
|
18
|
+
|
|
19
|
+
# Combinar opciones por defecto de la gema con las de la petición
|
|
20
|
+
request_options = {
|
|
21
|
+
idempotent: true,
|
|
22
|
+
retry_errors: [ Excon::Error::Socket, Excon::Error::Timeout ],
|
|
23
|
+
read_timeout: DockerSwarm.configuration.read_timeout.to_f,
|
|
24
|
+
write_timeout: DockerSwarm.configuration.write_timeout.to_f,
|
|
25
|
+
connect_timeout: DockerSwarm.configuration.connect_timeout.to_f,
|
|
26
|
+
retries: DockerSwarm.configuration.max_retries.to_i
|
|
27
|
+
}.merge(options)
|
|
28
|
+
|
|
29
|
+
response = client.request(request_options)
|
|
30
|
+
|
|
31
|
+
log_event("request_success",
|
|
32
|
+
data: options.merge(
|
|
33
|
+
status: response.status,
|
|
34
|
+
duration_ms: calculate_duration(start_time)
|
|
35
|
+
))
|
|
36
|
+
|
|
29
37
|
response.body
|
|
30
38
|
rescue => e
|
|
31
39
|
# Excon suele envolver excepciones de middleware en Excon::Error::Socket.
|
|
32
40
|
# Intentamos recuperar la causa original si es una de nuestras excepciones.
|
|
33
41
|
actual_error = (e.respond_to?(:cause) && e.cause&.class&.name&.include?("DockerSwarm::Error")) ? e.cause : e
|
|
34
|
-
|
|
35
|
-
log_event("request_failure",
|
|
42
|
+
|
|
43
|
+
log_event("request_failure",
|
|
36
44
|
level: :error,
|
|
37
|
-
data:
|
|
38
|
-
method: options[:method],
|
|
39
|
-
path: options[:path],
|
|
45
|
+
data: options.merge(
|
|
40
46
|
error: actual_error.class.name,
|
|
41
47
|
message: actual_error.message,
|
|
42
|
-
duration_ms: calculate_duration(start_time)
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
duration_ms: calculate_duration(start_time)
|
|
49
|
+
))
|
|
50
|
+
|
|
45
51
|
if actual_error.class.name.include?("DockerSwarm::Error")
|
|
46
52
|
raise actual_error
|
|
47
53
|
elsif actual_error.is_a?(Excon::Error::Socket)
|
|
@@ -59,20 +65,11 @@ module DockerSwarm
|
|
|
59
65
|
return if level == :debug && logger.level > Logger::DEBUG
|
|
60
66
|
|
|
61
67
|
log_block = proc do
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
|
68
|
+
LogHelper.format_kv({
|
|
69
|
+
component: "docker_swarm.connection",
|
|
70
|
+
event: event,
|
|
71
|
+
source: "http"
|
|
72
|
+
}.merge(data))
|
|
76
73
|
end
|
|
77
74
|
|
|
78
75
|
if level == :debug
|
|
@@ -99,9 +96,9 @@ module DockerSwarm
|
|
|
99
96
|
|
|
100
97
|
def client
|
|
101
98
|
debug_enabled = logger&.level == Logger::DEBUG
|
|
102
|
-
|
|
103
|
-
options = {
|
|
104
|
-
middlewares: common_middlewares,
|
|
99
|
+
|
|
100
|
+
options = {
|
|
101
|
+
middlewares: common_middlewares,
|
|
105
102
|
logger: logger,
|
|
106
103
|
debug_request: debug_enabled,
|
|
107
104
|
debug_response: debug_enabled,
|
|
@@ -111,9 +108,9 @@ module DockerSwarm
|
|
|
111
108
|
|
|
112
109
|
@client ||= if socket_path.start_with?("unix://")
|
|
113
110
|
Excon.new("unix:///", options.merge(socket: socket_path.sub(/^unix:\/\//, "")))
|
|
114
|
-
|
|
111
|
+
else
|
|
115
112
|
Excon.new(socket_path, options)
|
|
116
|
-
|
|
113
|
+
end
|
|
117
114
|
end
|
|
118
115
|
end
|
|
119
116
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DockerSwarm
|
|
4
|
+
# Helper module to centralize logging logic and formatting
|
|
5
|
+
module LogHelper
|
|
6
|
+
SENSITIVE_KEYS = /password|token|api_key|auth|secret/i.freeze
|
|
7
|
+
|
|
8
|
+
# Formats a hash into a KV structured string with sensitive data masking
|
|
9
|
+
# @param payload [Hash] The data to format
|
|
10
|
+
# @return [String] KV formatted string
|
|
11
|
+
def self.format_kv(payload)
|
|
12
|
+
payload.map do |k, v|
|
|
13
|
+
val = k.to_s =~ SENSITIVE_KEYS ? "[FILTERED]" : v
|
|
14
|
+
"#{k}=#{val}"
|
|
15
|
+
end.join(" ")
|
|
16
|
+
rescue
|
|
17
|
+
"event=logging_error"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -40,7 +40,7 @@ module DockerSwarm
|
|
|
40
40
|
return unless logger
|
|
41
41
|
|
|
42
42
|
begin
|
|
43
|
-
|
|
43
|
+
kv_string = LogHelper.format_kv({
|
|
44
44
|
component: "docker_swarm.middleware.error_handler",
|
|
45
45
|
event: "business_error",
|
|
46
46
|
source: "http",
|
|
@@ -48,12 +48,7 @@ module DockerSwarm
|
|
|
48
48
|
message: message,
|
|
49
49
|
method: env[:method],
|
|
50
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(" ")
|
|
51
|
+
})
|
|
57
52
|
|
|
58
53
|
logger.error(kv_string)
|
|
59
54
|
rescue
|
|
@@ -4,12 +4,28 @@ module DockerSwarm
|
|
|
4
4
|
module Middleware
|
|
5
5
|
class RequestEncoder < Excon::Middleware::Base
|
|
6
6
|
def request_call(env)
|
|
7
|
-
if env[:body] && env[:body].is_a?(
|
|
8
|
-
env[:
|
|
9
|
-
env[:
|
|
7
|
+
if env[:body] && !env[:body].is_a?(String)
|
|
8
|
+
content_type = (env[:headers]["Content-Type"] || env[:headers][:content_type]).to_s
|
|
9
|
+
env[:body] = serialize_body(env[:body], content_type)
|
|
10
|
+
|
|
11
|
+
if content_type.blank? || content_type.include?("application/json")
|
|
12
|
+
env[:headers]["Content-Type"] ||= "application/json"
|
|
13
|
+
end
|
|
10
14
|
end
|
|
11
15
|
@stack.request_call(env)
|
|
12
16
|
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def serialize_body(body, content_type)
|
|
21
|
+
if content_type.include?("application/x-www-form-urlencoded")
|
|
22
|
+
URI.encode_www_form(body)
|
|
23
|
+
elsif content_type.include?("multipart/form-data")
|
|
24
|
+
body
|
|
25
|
+
else
|
|
26
|
+
body.to_json
|
|
27
|
+
end
|
|
28
|
+
end
|
|
13
29
|
end
|
|
14
30
|
end
|
|
15
31
|
end
|
|
@@ -9,17 +9,29 @@ module DockerSwarm
|
|
|
9
9
|
headers = env[:response][:headers] || {}
|
|
10
10
|
|
|
11
11
|
if body && !body.empty? && headers["Content-Type"]&.include?("application/json")
|
|
12
|
-
|
|
13
|
-
parsed = JSON.parse(body)
|
|
14
|
-
env[:response][:body] = parsed.is_a?(Hash) ? parsed.with_indifferent_access : parsed
|
|
15
|
-
rescue JSON::ParserError
|
|
16
|
-
# Keep original body if parsing fails
|
|
17
|
-
end
|
|
12
|
+
env[:response][:body] = parse_json(body)
|
|
18
13
|
end
|
|
19
14
|
end
|
|
20
|
-
|
|
15
|
+
|
|
21
16
|
@stack.response_call(env)
|
|
22
17
|
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def parse_json(body)
|
|
22
|
+
result = body.is_a?(String) ? JSON.parse(body) : body
|
|
23
|
+
|
|
24
|
+
case result
|
|
25
|
+
when Hash
|
|
26
|
+
result.with_indifferent_access
|
|
27
|
+
when Array
|
|
28
|
+
result.map { |item| item.is_a?(Hash) ? item.with_indifferent_access : item }
|
|
29
|
+
else
|
|
30
|
+
result
|
|
31
|
+
end
|
|
32
|
+
rescue JSON::ParserError
|
|
33
|
+
body
|
|
34
|
+
end
|
|
23
35
|
end
|
|
24
36
|
end
|
|
25
37
|
end
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module DockerSwarm
|
|
4
|
+
# Represents a Docker Container
|
|
5
|
+
# @see https://docs.docker.com/engine/api/v1.41/#tag/Container
|
|
4
6
|
class Container < Base
|
|
5
7
|
include Concerns::Deletable
|
|
8
|
+
include Concerns::Loggable
|
|
6
9
|
|
|
10
|
+
# Starts the container
|
|
11
|
+
# @return [Boolean] true if successful
|
|
7
12
|
def start
|
|
8
13
|
Api.request(action: self.class.routes[:start], arguments: { id: self.ID })
|
|
14
|
+
true
|
|
9
15
|
end
|
|
10
16
|
|
|
17
|
+
# Stops the container
|
|
18
|
+
# @return [Boolean] true if successful
|
|
11
19
|
def stop
|
|
12
20
|
Api.request(action: self.class.routes[:stop], arguments: { id: self.ID })
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def logs(query_params = { stdout: 1, stderr: 1 })
|
|
16
|
-
Api.request(action: self.class.routes[:logs], arguments: { id: self.ID }, query_params: query_params)
|
|
21
|
+
true
|
|
17
22
|
end
|
|
18
23
|
end
|
|
19
24
|
end
|
|
@@ -5,14 +5,5 @@ module DockerSwarm
|
|
|
5
5
|
include Concerns::Creatable
|
|
6
6
|
include Concerns::Updatable
|
|
7
7
|
include Concerns::Deletable
|
|
8
|
-
|
|
9
|
-
validate :validate_name_presence
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
def validate_name_presence
|
|
14
|
-
name = attributes["Name"] || (respond_to?(:Name) ? Name : nil)
|
|
15
|
-
errors.add(:Name, "can't be blank") if name.blank?
|
|
16
|
-
end
|
|
17
8
|
end
|
|
18
9
|
end
|
|
@@ -7,21 +7,6 @@ module DockerSwarm
|
|
|
7
7
|
include Concerns::Creatable
|
|
8
8
|
include Concerns::Updatable
|
|
9
9
|
include Concerns::Deletable
|
|
10
|
-
|
|
11
|
-
validate :validate_name_presence
|
|
12
|
-
|
|
13
|
-
# Fetches logs for the service
|
|
14
|
-
# @param query_params [Hash] Query parameters for the logs endpoint (stdout, stderr, follow, etc.)
|
|
15
|
-
# @return [String] The raw log stream
|
|
16
|
-
def logs(query_params = { stdout: 1, stderr: 1 })
|
|
17
|
-
Api.request(action: self.class.routes[:logs], arguments: { id: self.ID }, query_params: query_params)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def validate_name_presence
|
|
23
|
-
name = attributes["Name"] || (respond_to?(:Name) ? Name : nil)
|
|
24
|
-
errors.add(:Name, "can't be blank") if name.blank?
|
|
25
|
-
end
|
|
10
|
+
include Concerns::Loggable
|
|
26
11
|
end
|
|
27
12
|
end
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module DockerSwarm
|
|
4
|
+
# Access point for Docker Swarm cluster information
|
|
5
|
+
# @see https://docs.docker.com/engine/api/v1.41/#tag/Swarm
|
|
4
6
|
class Swarm < Base
|
|
7
|
+
# Override resource name to match API endpoint
|
|
8
|
+
# @return [String]
|
|
5
9
|
def self.resource_name
|
|
6
10
|
"swarm"
|
|
7
11
|
end
|
|
8
12
|
|
|
13
|
+
# Returns information about the swarm
|
|
14
|
+
# @return [Hash] Raw swarm data
|
|
9
15
|
def self.show
|
|
10
16
|
Api.request(action: routes[:show])
|
|
11
17
|
end
|
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module DockerSwarm
|
|
4
|
+
# Access point for Docker System information and operations
|
|
5
|
+
# @see https://docs.docker.com/engine/api/v1.41/#tag/System
|
|
4
6
|
class System < Base
|
|
7
|
+
# Override resource name to match API endpoint
|
|
8
|
+
# @return [String]
|
|
5
9
|
def self.resource_name
|
|
6
10
|
"system"
|
|
7
11
|
end
|
|
8
12
|
|
|
13
|
+
# Returns system information
|
|
14
|
+
# @return [Hash]
|
|
9
15
|
def self.info
|
|
10
16
|
Api.request(action: routes[:info])
|
|
11
17
|
end
|
|
12
18
|
|
|
19
|
+
# Returns Docker version information
|
|
20
|
+
# @return [Hash]
|
|
13
21
|
def self.version
|
|
14
22
|
Api.request(action: routes[:version])
|
|
15
23
|
end
|
|
16
24
|
|
|
25
|
+
# Checks if the Docker daemon is responding
|
|
26
|
+
# @return [String] "OK" if up
|
|
17
27
|
def self.up
|
|
18
28
|
Api.request(action: routes[:up])
|
|
19
29
|
end
|
|
20
30
|
|
|
31
|
+
# Returns system-wide data usage information
|
|
32
|
+
# @return [Hash]
|
|
21
33
|
def self.df
|
|
22
34
|
Api.request(action: routes[:df])
|
|
23
35
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module DockerSwarm
|
|
4
|
+
# Represents a Docker Swarm Task
|
|
5
|
+
# @see https://docs.docker.com/engine/api/v1.41/#tag/Task
|
|
4
6
|
class Task < Base
|
|
5
|
-
|
|
6
|
-
Api.request(action: self.class.routes[:logs], arguments: { id: self.ID }, query_params: query_params)
|
|
7
|
-
end
|
|
7
|
+
include Concerns::Loggable
|
|
8
8
|
end
|
|
9
9
|
end
|
data/lib/docker_swarm/version.rb
CHANGED
data/lib/docker_swarm.rb
CHANGED
|
@@ -6,6 +6,7 @@ require "active_model"
|
|
|
6
6
|
require "excon"
|
|
7
7
|
require "json"
|
|
8
8
|
require "logger"
|
|
9
|
+
require "set"
|
|
9
10
|
|
|
10
11
|
module DockerSwarm
|
|
11
12
|
class << self
|
|
@@ -14,11 +15,11 @@ module DockerSwarm
|
|
|
14
15
|
def configure
|
|
15
16
|
@configuration ||= Configuration.new
|
|
16
17
|
yield(@configuration) if block_given?
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
if @configuration.logger.respond_to?(:level=)
|
|
19
20
|
@configuration.logger.level = @configuration.log_level
|
|
20
21
|
end
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
@connection = nil
|
|
23
24
|
end
|
|
24
25
|
|
|
@@ -35,6 +36,7 @@ end
|
|
|
35
36
|
|
|
36
37
|
# Primero cargamos la configuración porque la clase DockerSwarm la usa arriba
|
|
37
38
|
require_relative "docker_swarm/configuration"
|
|
39
|
+
require_relative "docker_swarm/log_helper"
|
|
38
40
|
require_relative "docker_swarm/version"
|
|
39
41
|
require_relative "docker_swarm/errors"
|
|
40
42
|
require_relative "docker_swarm/middleware/request_encoder"
|
|
@@ -42,10 +44,15 @@ require_relative "docker_swarm/middleware/response_json_parser"
|
|
|
42
44
|
require_relative "docker_swarm/middleware/error_handler"
|
|
43
45
|
require_relative "docker_swarm/connection"
|
|
44
46
|
require_relative "docker_swarm/api"
|
|
45
|
-
|
|
47
|
+
|
|
48
|
+
# Concerns deben cargarse antes que Base si Base los incluye
|
|
46
49
|
require_relative "docker_swarm/concerns/creatable"
|
|
47
50
|
require_relative "docker_swarm/concerns/updatable"
|
|
48
51
|
require_relative "docker_swarm/concerns/deletable"
|
|
52
|
+
require_relative "docker_swarm/concerns/loggable"
|
|
53
|
+
require_relative "docker_swarm/concerns/inspectable"
|
|
54
|
+
|
|
55
|
+
require_relative "docker_swarm/base"
|
|
49
56
|
|
|
50
57
|
# Models
|
|
51
58
|
require_relative "docker_swarm/models/swarm"
|
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.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gabriel
|
|
@@ -95,10 +95,13 @@ files:
|
|
|
95
95
|
- lib/docker_swarm/base.rb
|
|
96
96
|
- lib/docker_swarm/concerns/creatable.rb
|
|
97
97
|
- lib/docker_swarm/concerns/deletable.rb
|
|
98
|
+
- lib/docker_swarm/concerns/inspectable.rb
|
|
99
|
+
- lib/docker_swarm/concerns/loggable.rb
|
|
98
100
|
- lib/docker_swarm/concerns/updatable.rb
|
|
99
101
|
- lib/docker_swarm/configuration.rb
|
|
100
102
|
- lib/docker_swarm/connection.rb
|
|
101
103
|
- lib/docker_swarm/errors.rb
|
|
104
|
+
- lib/docker_swarm/log_helper.rb
|
|
102
105
|
- lib/docker_swarm/middleware/error_handler.rb
|
|
103
106
|
- lib/docker_swarm/middleware/request_encoder.rb
|
|
104
107
|
- lib/docker_swarm/middleware/response_json_parser.rb
|