docker-swarm 0.5.4 → 0.7.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.
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-swarm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-04-07 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -88,7 +87,11 @@ executables: []
88
87
  extensions: []
89
88
  extra_rdoc_files: []
90
89
  files:
90
+ - CHANGELOG.md
91
+ - LICENSE
91
92
  - README.md
93
+ - docs/behavior/behavior.md
94
+ - docs/glossary/glossary.md
92
95
  - lib/docker-swarm.rb
93
96
  - lib/docker_swarm.rb
94
97
  - lib/docker_swarm/api.rb
@@ -118,15 +121,16 @@ files:
118
121
  - lib/docker_swarm/models/volume.rb
119
122
  - lib/docker_swarm/version.rb
120
123
  - skill/SKILL.md
121
- - skill/references/api-detallada.md
122
- - skill/references/errores.md
123
- homepage: https://github.com/wispro/docker-swarm
124
+ homepage: https://github.com/gedera/docker-swarm
124
125
  licenses:
125
126
  - MIT
126
127
  metadata:
127
- homepage_uri: https://github.com/wispro/docker-swarm
128
- source_code_uri: https://github.com/wispro/docker-swarm
129
- post_install_message:
128
+ homepage_uri: https://github.com/gedera/docker-swarm
129
+ source_code_uri: https://github.com/gedera/docker-swarm
130
+ changelog_uri: https://github.com/gedera/docker-swarm/blob/v0.7.0/CHANGELOG.md
131
+ bug_tracker_uri: https://github.com/gedera/docker-swarm/issues
132
+ documentation_uri: https://github.com/gedera/docker-swarm/blob/v0.7.0/skill/SKILL.md
133
+ rubygems_mfa_required: 'true'
130
134
  rdoc_options: []
131
135
  require_paths:
132
136
  - lib
@@ -134,15 +138,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
138
  requirements:
135
139
  - - ">="
136
140
  - !ruby/object:Gem::Version
137
- version: 2.7.0
141
+ version: 3.2.0
138
142
  required_rubygems_version: !ruby/object:Gem::Requirement
139
143
  requirements:
140
144
  - - ">="
141
145
  - !ruby/object:Gem::Version
142
146
  version: '0'
143
147
  requirements: []
144
- rubygems_version: 3.4.19
145
- signing_key:
148
+ rubygems_version: 3.6.7
146
149
  specification_version: 4
147
150
  summary: A Ruby ORM and API client for Docker Swarm.
148
151
  test_files: []
@@ -1,246 +0,0 @@
1
- # API Detallada
2
-
3
- Referencia completa de modelos, concerns, middleware y métodos públicos de DockerSwarm.
4
-
5
- ## Modelos — Tabla de capacidades
6
-
7
- | Modelo | Creatable | Updatable | Deletable | Loggable | Extra |
8
- |--------|-----------|-----------|-----------|----------|-------|
9
- | Service | x | x | x | x | Ciclo de vida completo |
10
- | Node | | x | x | | Miembros del cluster, no se crean |
11
- | Task | | | | x | Read-only, generados por services |
12
- | Container | | | x | x | `#start`, `#stop` |
13
- | Network | x | x | x | | CRUD completo |
14
- | Volume | x | | x | | `root_key = "Volumes"` |
15
- | Config | x | | x | | Configuración del cluster |
16
- | Secret | x | | x | | Datos sensibles |
17
- | Image | x | | x | | Pull/removal |
18
- | Swarm | | | | | `.show` (estático) |
19
- | System | | | | | `.info`, `.version`, `.up`, `.df` |
20
-
21
- ## Base — Métodos de clase
22
-
23
- ```ruby
24
- # Listar todos (con filtros opcionales)
25
- # @param filters [Hash] Filtros Docker (label:, name:, id:, role:, etc.)
26
- # @return [Array<Model>]
27
- Model.all(filters = {})
28
-
29
- # Alias de .all
30
- Model.where(filters)
31
-
32
- # Buscar por ID (retorna nil si 404)
33
- # @param id [String]
34
- # @return [Model, nil]
35
- Model.find(id)
36
-
37
- # Nombre del recurso pluralizado (ej: "services", "nodes")
38
- Model.resource_name
39
-
40
- # Endpoints del modelo desde Api::ENDPOINTS
41
- Model.routes
42
- ```
43
-
44
- ### Filtros soportados
45
-
46
- ```ruby
47
- # Filtros Docker se serializan como JSON en query param `filters`
48
- DockerSwarm::Service.all(label: ["app=web"], name: ["my-service"])
49
- DockerSwarm::Container.all(status: ["running"])
50
- DockerSwarm::Node.all(role: ["manager"])
51
-
52
- # Parámetros globales (no van en filters)
53
- DockerSwarm::Image.all(all: true) # incluir intermedias
54
- DockerSwarm::Container.all(limit: 10) # limitar resultados
55
- ```
56
-
57
- ## Base — Métodos de instancia
58
-
59
- ```ruby
60
- # ID del recurso
61
- # @return [String]
62
- model.id
63
-
64
- # Hash de atributos (excluye internos de ActiveModel)
65
- # @return [Hash]
66
- model.attributes
67
-
68
- # Recarga desde Docker API
69
- # @return [self]
70
- model.reload
71
-
72
- # Prepara payload para Docker (excluye ID, Version, CreatedAt, extrae Spec)
73
- # @return [Hash]
74
- model.payload_for_docker
75
-
76
- # Persistido? (tiene ID)
77
- # @return [Boolean]
78
- model.persisted?
79
-
80
- # Inspección legible: #<DockerSwarm::Service ID: abc, Name: web, Image: nginx>
81
- model.inspect
82
-
83
- # Serialización
84
- model.as_json
85
- model.serializable_hash
86
- ```
87
-
88
- ## Concern: Creatable
89
-
90
- Incluido en: Service, Network, Volume, Config, Secret, Image.
91
-
92
- ```ruby
93
- # Crear y persistir
94
- # @param attributes [Hash] Atributos PascalCase
95
- # @return [Model] instancia (con ID si exitoso)
96
- Model.create(attributes)
97
-
98
- # Persistir instancia nueva (o delegar a update si persisted?)
99
- # @return [Boolean] false si validación falla
100
- model.save
101
- ```
102
-
103
- Flujo interno de `save`: `valid?` → `Api.request(:create, payload_for_docker)` → asigna ID de response → `reload`.
104
-
105
- ## Concern: Updatable
106
-
107
- Incluido en: Service, Node, Network.
108
-
109
- ```ruby
110
- # Actualizar recurso persistido
111
- # @param new_attributes [Hash] Atributos a mergear
112
- # @return [Boolean] false si validación falla
113
- model.update(new_attributes = {})
114
- ```
115
-
116
- Flujo interno: `assign_attributes` (deep_merge en Spec) → `valid?` → `Api.request(:update, id:, version: Version["Index"], payload:)`.
117
-
118
- **Importante:** El query param `version` se extrae automáticamente de `self.Version["Index"]`. Sin esto, Docker rechaza el update con 500.
119
-
120
- ## Concern: Deletable
121
-
122
- Incluido en: Service, Node, Container, Network, Volume, Config, Secret, Image.
123
-
124
- ```ruby
125
- # Eliminar por instancia
126
- # @return [true, nil] nil si ya no existía (404 graceful)
127
- model.destroy
128
-
129
- # Eliminar por ID (class method)
130
- # @return [true, nil]
131
- Model.destroy(id)
132
- ```
133
-
134
- ## Concern: Loggable
135
-
136
- Incluido en: Service, Task, Container.
137
-
138
- ```ruby
139
- # Obtener logs del recurso
140
- # @param query_params [Hash] stdout:, stderr:, follow:, tail:, since:, timestamps:
141
- # @return [String] Raw log stream
142
- model.logs(query_params = { stdout: 1, stderr: 1 })
143
- ```
144
-
145
- ## Container — Métodos específicos
146
-
147
- ```ruby
148
- container = DockerSwarm::Container.find("container_id")
149
-
150
- # Iniciar contenedor detenido
151
- # @return [Boolean]
152
- container.start
153
-
154
- # Detener contenedor en ejecución
155
- # @return [Boolean]
156
- container.stop
157
- ```
158
-
159
- ## System — Métodos estáticos
160
-
161
- ```ruby
162
- # Ping al daemon
163
- # @return [String] "OK"
164
- DockerSwarm::System.up
165
-
166
- # Información del daemon
167
- # @return [Hash] (Containers, Images, Driver, MemoryLimit, etc.)
168
- DockerSwarm::System.info
169
-
170
- # Versión de Docker
171
- # @return [Hash] (Version, ApiVersion, Os, Arch, etc.)
172
- DockerSwarm::System.version
173
-
174
- # Uso de disco
175
- # @return [Hash] (LayersSize, Images, Containers, Volumes)
176
- DockerSwarm::System.df
177
- ```
178
-
179
- ## Swarm — Método estático
180
-
181
- ```ruby
182
- # Información del cluster Swarm
183
- # @return [Hash] (ID, Version, Spec, JoinTokens, etc.)
184
- DockerSwarm::Swarm.show
185
- ```
186
-
187
- ## Volume — Particularidad
188
-
189
- Volume sobreescribe `root_key` porque Docker envuelve la respuesta en `{"Volumes": [...]}`:
190
-
191
- ```ruby
192
- class Volume < Base
193
- def self.root_key = "Volumes"
194
- end
195
- ```
196
-
197
- ## Api — Bajo nivel
198
-
199
- ```ruby
200
- # Request directo al Docker API
201
- # @param action [Hash] {method:, path:} desde ENDPOINTS
202
- # @param arguments [Hash] Interpolación en path (id:)
203
- # @param query_params [Hash] Query string
204
- # @param payload [Hash, nil] Body del request
205
- DockerSwarm::Api.request(action:, arguments: {}, query_params: {}, payload: nil)
206
- ```
207
-
208
- ### Endpoints registrados
209
-
210
- Todos definidos en `Api::ENDPOINTS` como Hash frozen:
211
-
212
- | Recurso | Acciones |
213
- |---------|----------|
214
- | swarm | show |
215
- | system | info, version, up, df |
216
- | nodes | index, show, update, destroy |
217
- | tasks | index, show, logs |
218
- | services | index, show, create, update, destroy, logs |
219
- | configs | index, show, create, destroy |
220
- | secrets | index, show, create, destroy |
221
- | networks | index, show, create, update, destroy |
222
- | volumes | index, show, create, destroy |
223
- | containers | index, show, create, start, stop, destroy, logs |
224
- | images | index, show, create, destroy |
225
-
226
- ## Middleware Stack
227
-
228
- Orden de ejecución en Excon:
229
-
230
- 1. **Excon defaults** (Retry, Instrumentor, etc.)
231
- 2. **Excon::Middleware::RedirectFollower**
232
- 3. **RequestEncoder** — Serializa body: JSON (default), form-urlencoded, multipart. Detecta por Content-Type header.
233
- 4. **ResponseJSONParser** — Parsea JSON si Content-Type incluye `application/json`. Aplica `with_indifferent_access` recursivo (Hash y Array de Hashes).
234
- 5. **ErrorHandler** — Status 4xx/5xx → excepción tipada. Loguea `business_error` antes de raise.
235
-
236
- ## Configuración
237
-
238
- | Opción | Tipo | Default | Descripción |
239
- |--------|------|---------|-------------|
240
- | `socket_path` | String | `unix:///var/run/docker.sock` | Socket Unix o URL TCP |
241
- | `logger` | Logger | `Logger.new($stdout)` | Logger para KV output |
242
- | `log_level` | Integer | `Logger::INFO` | Nivel de log (se aplica al logger) |
243
- | `read_timeout` | Float | `60.0` | Timeout lectura (segundos) |
244
- | `write_timeout` | Float | `60.0` | Timeout escritura (segundos) |
245
- | `connect_timeout` | Float | `10.0` | Timeout conexión (segundos) |
246
- | `max_retries` | Integer | `3` | Reintentos en Socket/Timeout errors |
@@ -1,157 +0,0 @@
1
- # Catálogo de Errores
2
-
3
- Referencia completa de excepciones de DockerSwarm. Todas heredan de `DockerSwarm::Error`.
4
-
5
- ## Jerarquía
6
-
7
- ```
8
- DockerSwarm::Error (base)
9
- ├── BadRequest (400)
10
- ├── Unauthorized (401)
11
- ├── Forbidden (403)
12
- ├── NotFound (404)
13
- ├── NotAcceptable (406)
14
- ├── RequestTimeout (408)
15
- ├── Conflict (409)
16
- ├── UnprocessableEntity (422)
17
- ├── TooManyRequests (429)
18
- ├── InternalServerError (500)
19
- ├── BadGateway (502)
20
- ├── ServiceUnavailable (503)
21
- ├── GatewayTimeout (504)
22
- └── Communication (socket/red)
23
- ```
24
-
25
- ## Acceso
26
-
27
- Cada excepción tiene 3 formas de acceso equivalentes:
28
-
29
- ```ruby
30
- DockerSwarm::NotFound # alias directo (recomendado)
31
- DockerSwarm::Error::NotFound # acceso via clase Error
32
- DockerSwarm::Errors::NotFound # módulo Errors (const_missing dinámico)
33
- ```
34
-
35
- ## Catálogo completo
36
-
37
- ### BadRequest (400)
38
-
39
- **Causa:** Payload malformado o parámetros inválidos.
40
- **Reproducción:** Enviar JSON con campos incorrectos (ej: `Replicas: "abc"` en vez de integer).
41
- **Resolución:** Validar payload contra la documentación de Docker API. Verificar tipos de datos.
42
-
43
- ### Unauthorized (401)
44
-
45
- **Causa:** Credenciales inválidas o ausentes para Docker daemon con TLS.
46
- **Reproducción:** Conectar a daemon protegido sin certificados.
47
- **Resolución:** Configurar TLS client certificates en Excon o en la URL de conexión.
48
-
49
- ### Forbidden (403)
50
-
51
- **Causa:** Permisos insuficientes para la operación.
52
- **Reproducción:** Intentar operación de swarm en un nodo worker.
53
- **Resolución:** Verificar que el nodo es manager y que el usuario tiene permisos sobre el socket.
54
-
55
- ### NotFound (404)
56
-
57
- **Causa:** Recurso no existe o fue eliminado.
58
- **Reproducción:** `Service.find("id_inexistente")`.
59
- **Resolución:** `Base.find` retorna `nil` automáticamente. `Deletable#destroy` también es graceful (retorna `nil` en 404). No requiere rescue manual en estos casos.
60
-
61
- ### NotAcceptable (406)
62
-
63
- **Causa:** El servidor no puede producir una respuesta aceptable.
64
- **Reproducción:** Raro en Docker API.
65
- **Resolución:** Verificar headers Accept del request.
66
-
67
- ### RequestTimeout (408)
68
-
69
- **Causa:** Docker daemon tardó demasiado en responder.
70
- **Reproducción:** Operación en un cluster sobrecargado.
71
- **Resolución:** Incrementar `read_timeout` en configuración. Verificar estado del cluster.
72
-
73
- ### Conflict (409)
74
-
75
- **Causa:** Nombre duplicado, recurso en uso, o versión desactualizada.
76
- **Reproducción:** `Service.create(Name: "nombre_existente")` o update con `Version.Index` stale.
77
- **Resolución:** Para nombres: verificar existencia antes de crear. Para versiones: hacer `reload` y reintentar el update.
78
-
79
- ### UnprocessableEntity (422)
80
-
81
- **Causa:** Payload semánticamente inválido.
82
- **Reproducción:** Crear servicio con imagen inexistente y restricciones de scheduling imposibles.
83
- **Resolución:** Verificar que la imagen existe y que las constraints del servicio son alcanzables.
84
-
85
- ### TooManyRequests (429)
86
-
87
- **Causa:** Rate limiting del Docker daemon o registry.
88
- **Reproducción:** Burst de requests al API.
89
- **Resolución:** Implementar backoff. Los retries de Excon cubren errores de socket/timeout pero no 429.
90
-
91
- ### InternalServerError (500)
92
-
93
- **Causa:** Error interno del Docker daemon.
94
- **Reproducción:** Bug en Docker, operación sobre estado inconsistente, o update sin `version` query param.
95
- **Resolución:** Verificar logs del Docker daemon (`journalctl -u docker`). Si es por version faltante, usar el modelo (Updatable lo maneja).
96
-
97
- ### BadGateway (502)
98
-
99
- **Causa:** Proxy o load balancer entre cliente y daemon devuelve error.
100
- **Reproducción:** Docker daemon detrás de reverse proxy caído.
101
- **Resolución:** Verificar infraestructura de red y proxy.
102
-
103
- ### ServiceUnavailable (503)
104
-
105
- **Causa:** Docker daemon reiniciando o en mantenimiento.
106
- **Reproducción:** Request durante restart del servicio Docker.
107
- **Resolución:** Reintentar después de esperar. `max_retries` cubre errores de socket pero no 503.
108
-
109
- ### GatewayTimeout (504)
110
-
111
- **Causa:** Proxy entre cliente y daemon timeout.
112
- **Reproducción:** Operación larga detrás de proxy con timeout corto.
113
- **Resolución:** Incrementar timeout del proxy. Verificar que `read_timeout` de la gema es menor que el del proxy.
114
-
115
- ### Communication
116
-
117
- **Causa:** Error de socket o red — daemon caído, socket inexistente, permisos insuficientes.
118
- **Reproducción:** `DockerSwarm::System.up` con daemon apagado.
119
- **Resolución:** Verificar que Docker está corriendo (`systemctl status docker`), que el socket existe y que el usuario tiene permisos de lectura.
120
-
121
- ## Manejo recomendado
122
-
123
- ```ruby
124
- begin
125
- DockerSwarm::Service.create(Name: "web", TaskTemplate: { ... })
126
- rescue DockerSwarm::Conflict => e
127
- # Nombre duplicado — buscar existente
128
- existing = DockerSwarm::Service.all(name: ["web"]).first
129
- rescue DockerSwarm::Communication => e
130
- # Docker caído
131
- logger.error("Docker unreachable: #{e.message}")
132
- rescue DockerSwarm::Error => e
133
- # Cualquier otro error de Docker
134
- logger.error("Docker error: #{e.class} #{e.message}")
135
- end
136
- ```
137
-
138
- ## Logging automático
139
-
140
- El middleware ErrorHandler loguea automáticamente antes de raise:
141
-
142
- ```
143
- component=docker_swarm.middleware.error_handler event=business_error source=http status=409 message="name conflicts" method=post path=/services/create
144
- ```
145
-
146
- Formato KV con masking de datos sensibles via LogHelper.
147
-
148
- ## Causa original (Excon wrapping)
149
-
150
- Excon puede envolver excepciones del middleware en `Excon::Error::Socket`. Connection detecta esto y re-raise la excepción original:
151
-
152
- ```ruby
153
- # Connection#request internamente:
154
- actual_error = e.cause&.class&.name&.include?("DockerSwarm::Error") ? e.cause : e
155
- ```
156
-
157
- La excepción original mantiene la causa via `Exception#cause` de Ruby para trazabilidad completa.