docker-stack 2.3.0__tar.gz → 2.3.1__tar.gz

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.
Files changed (38) hide show
  1. docker_stack-2.3.1/PKG-INFO +392 -0
  2. docker_stack-2.3.1/README.md +366 -0
  3. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/cli.py +178 -6
  4. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/helpers.py +8 -4
  5. docker_stack-2.3.1/docker_stack.egg-info/PKG-INFO +392 -0
  6. {docker_stack-2.3.0 → docker_stack-2.3.1}/setup.py +1 -1
  7. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_docker_stack.py +165 -0
  8. docker_stack-2.3.0/PKG-INFO +0 -411
  9. docker_stack-2.3.0/README.md +0 -385
  10. docker_stack-2.3.0/docker_stack.egg-info/PKG-INFO +0 -411
  11. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/__init__.py +0 -0
  12. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/command_runner.py +0 -0
  13. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/compose.py +0 -0
  14. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/conflict_prompt.py +0 -0
  15. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/docker_objects.py +0 -0
  16. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/envsubst.py +0 -0
  17. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/envsubst_merge.py +0 -0
  18. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/login.py +0 -0
  19. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/manager_api.py +0 -0
  20. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/markers.py +0 -0
  21. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/merge_conf.py +0 -0
  22. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/registry.py +0 -0
  23. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/shell_auth.py +0 -0
  24. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack/url_parser.py +0 -0
  25. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack.egg-info/SOURCES.txt +0 -0
  26. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack.egg-info/dependency_links.txt +0 -0
  27. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack.egg-info/entry_points.txt +0 -0
  28. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack.egg-info/requires.txt +0 -0
  29. {docker_stack-2.3.0 → docker_stack-2.3.1}/docker_stack.egg-info/top_level.txt +0 -0
  30. {docker_stack-2.3.0 → docker_stack-2.3.1}/pyproject.toml +0 -0
  31. {docker_stack-2.3.0 → docker_stack-2.3.1}/setup.cfg +0 -0
  32. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_conflict_prompt.py +0 -0
  33. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_docker_objects.py +0 -0
  34. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_load_env.py +0 -0
  35. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_login.py +0 -0
  36. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_manager_api.py +0 -0
  37. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_node_ls.py +0 -0
  38. {docker_stack-2.3.0 → docker_stack-2.3.1}/tests/test_shell_auth.py +0 -0
@@ -0,0 +1,392 @@
1
+ Metadata-Version: 2.4
2
+ Name: docker-stack
3
+ Version: 2.3.1
4
+ Summary: CLI for deploying and managing Docker stacks.
5
+ Home-page: https://github.com/mesudip/docker-stack
6
+ Author: Sudip Bhattarai
7
+ Author-email: sudip@bhattarai.me
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: PyYAML
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest<9,>=8; extra == "dev"
16
+ Dynamic: author
17
+ Dynamic: author-email
18
+ Dynamic: classifier
19
+ Dynamic: description
20
+ Dynamic: description-content-type
21
+ Dynamic: home-page
22
+ Dynamic: provides-extra
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
26
+
27
+ # Docker Stack CLI Utility
28
+
29
+ A command-line tool for advanced Docker Swarm stack deployments on plain Docker daemons. `docker-stack` extends vanilla `docker stack deploy` with generated secrets, templated configs, versioned stack state, safer rollbacks, and better day-to-day stack workflows.
30
+
31
+ ## Installation
32
+
33
+ Install or upgrade `docker-stack` with:
34
+
35
+ ```bash
36
+ pip install docker-stack --upgrade --break-system-packages
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ### Plain Docker Daemon
42
+
43
+ If you already have a Docker Swarm daemon or Docker context, you can use the advanced stack features directly against it.
44
+
45
+ Typical daemon-only workflow:
46
+
47
+ ```bash
48
+ docker-stack deploy my-stack docker-compose.yml
49
+ docker-stack ls
50
+ docker-stack ls -n team-a
51
+ docker-stack ls -A
52
+ docker-stack versions my-stack
53
+ docker-stack cat my-stack
54
+ docker-stack checkout my-stack v2
55
+ docker-stack node ls
56
+ ```
57
+
58
+ What this gives you on a raw Docker daemon:
59
+
60
+ - richer secret and config handling in Compose
61
+ - generated secrets without external scripts
62
+ - template expansion from env vars and files
63
+ - versioned stack config history
64
+ - stack version inspection and checkout
65
+ - raw daemon compatibility without extra infrastructure
66
+
67
+ ### GitHub Actions
68
+
69
+ #### 1. Normal Docker daemon
70
+
71
+ Use this when the runner already has Docker access through the default Docker context or `DOCKER_HOST`.
72
+
73
+ ```yaml
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - uses: actions/setup-python@v6
77
+ with:
78
+ python-version: '3.x'
79
+ - run: python3 -m pip install --upgrade docker-stack
80
+ - run: docker-stack deploy my-stack docker-compose.yml
81
+ ```
82
+
83
+ Use this option when CI can connect directly to the target Docker daemon.
84
+
85
+ #### 2. Docker-Manager
86
+
87
+ Use the bundled action when deploying through
88
+ [Docker-Manager](https://github.com/mesudip/docker-enterprise). The manager
89
+ repository contains the server source, installation instructions, and deployment
90
+ documentation.
91
+
92
+ For a full compose deployment directly from CI, use the action to configure
93
+ Docker-Manager authentication and then run the normal `docker-stack deploy`
94
+ command:
95
+
96
+ ```yaml
97
+ permissions:
98
+ contents: read
99
+ id-token: write
100
+
101
+ steps:
102
+ - uses: actions/checkout@v4
103
+ - uses: mesudip/docker-stack@v2
104
+ with:
105
+ manager: https://manager.example.com:2378
106
+ - run: docker-stack deploy --namespace team-a --with-registry-auth my-stack docker-compose.yml
107
+ ```
108
+
109
+ You can also deploy the full compose file through action inputs:
110
+
111
+ ```yaml
112
+ permissions:
113
+ contents: read
114
+ id-token: write
115
+
116
+ steps:
117
+ - uses: actions/checkout@v4
118
+ - uses: mesudip/docker-stack@v2
119
+ with:
120
+ manager: https://manager.example.com:2378
121
+ stack: my-stack
122
+ compose-file: docker-compose.yml
123
+ namespace: team-a
124
+ with-registry-auth: "true"
125
+ ```
126
+
127
+ To release new service images without submitting the compose file again:
128
+
129
+ ```yaml
130
+ permissions:
131
+ contents: read
132
+ id-token: write
133
+
134
+ steps:
135
+ - uses: actions/checkout@v4
136
+ - uses: mesudip/docker-stack@v2
137
+ with:
138
+ manager: https://manager.example.com:2378
139
+ stack: my-stack
140
+ namespace: team-a
141
+ with-registry-auth: "true"
142
+ images: |
143
+ api=ghcr.io/acme/api:${{ github.sha }}
144
+ worker=ghcr.io/acme/worker:${{ github.sha }}
145
+ ```
146
+
147
+ Use a full compose deployment when the workflow owns the complete stack
148
+ definition. Use an image-only deployment when the stack is already managed and
149
+ the workflow only needs to release new images. Both forms support namespaces;
150
+ the namespace defaults to `default` when omitted.
151
+
152
+ ### Authenticated Docker-Manager shell
153
+
154
+ Open an isolated Bash or Zsh session for a manager context:
155
+
156
+ ```bash
157
+ docker-stack shell office
158
+ ```
159
+
160
+ If `office` does not exist yet, the CLI asks for its Docker-Manager URL, creates
161
+ the context, authenticates, and opens the shell. You can also provide everything
162
+ non-interactively with `docker-stack shell --context office <manager-url>`.
163
+
164
+ Stack commands use the `default` namespace unless `-n/--namespace` is supplied.
165
+ Listings print the selected namespace; `docker-stack ls -A` (or
166
+ `--all-namespaces`) lists every visible namespace.
167
+
168
+ The prompt displays `(docker:office@cluster)`, keeps the selected manager context active,
169
+ and refreshes authentication when needed. The session supports `docker` and
170
+ `docker compose`; legacy `docker-compose` is not supported. If authentication
171
+ expires, run `docker-stack login` again.
172
+
173
+ Container listing is cluster-aware and includes the owning Swarm node. Select a
174
+ node when working with daemon-local resources such as volumes and images:
175
+
176
+ ```bash
177
+ docker ps
178
+ docker-stack node current
179
+ docker-stack node use worker-02
180
+ docker volume ls
181
+ docker image ls
182
+ docker-stack node use cluster
183
+ ```
184
+
185
+ Node selection is stored only in the managed shell's isolated Docker
186
+ configuration and appears in the prompt as `(docker:office@worker-02)`.
187
+ Selected-node requests remain subject to the manager's Docker permissions;
188
+ image management is root-only because the manager does not define delegated
189
+ image permissions.
190
+
191
+ Cluster-aware output is enabled after the manager has observed compatible
192
+ agents on every discovered node. The manager remembers that capability until it
193
+ restarts, so a temporary agent outage does not make the CLI revert to a legacy
194
+ feature decision. A partial cluster listing prints the available containers,
195
+ reports each failed node on stderr with its incident id, and exits non-zero.
196
+
197
+ `docker ps --quiet` and `docker ps --format ...` use Docker's native formatter
198
+ and therefore do not add the `NODE` column. Explicit Docker overrides such as
199
+ `--context`, `--host`/`-H`, and `--config` bypass managed cluster formatting and
200
+ are sent unchanged to the Docker CLI.
201
+
202
+ ## What It Adds
203
+
204
+ Beyond `docker stack deploy`, against a plain Docker daemon:
205
+
206
+ - **Generated secrets** — no external scripts; see [Object Versioning and Reuse](#object-versioning-and-reuse) for the once-only semantics.
207
+ - **Inline and templated configs/secrets** — content in the compose file, or expanded from environment variables and files.
208
+ - **Automatic versioning** — configs and secrets are content-hashed and versioned, so edits do not require hand-written `_v2` names.
209
+ - **Version inspection and checkout** — `versions`, `cat`, and `checkout` restore a complete recorded stack version, including its configs.
210
+ - **Cluster-aware inspection** — stack and node output that reports the owning Swarm node.
211
+
212
+ ### Concurrent deploys (Docker-Manager)
213
+
214
+ Docker-Manager runs one apply per stack at a time. When `docker-stack deploy`
215
+ or `docker-stack checkout` finds another run in progress (a UI deploy, a CI
216
+ image bump, another operator), it waits and prints who started it:
217
+
218
+ ```
219
+ [manager] waiting: a deploy started by alice 42s ago is still running (waiting up to 300s, set DOCKER_MANAGER_DEPLOY_WAIT_SECS to change)
220
+ [manager] press Enter twice to force your deploy (aborts that run; changes it already made to the daemon stay), Ctrl+C to quit
221
+ ```
222
+
223
+ - It retries every 5 seconds until the stack is free or `DOCKER_MANAGER_DEPLOY_WAIT_SECS` runs out (default: the deploy timeout; `0` fails immediately). CI runs wait the same way, without the prompt.
224
+ - At a terminal, pressing Enter twice within 3 seconds asks the manager to abort the running deployment and deploys as soon as the stack is released. This needs stack deploy permission and is offered once per run. The aborted run stops orchestrating, but daemon requests it already made still complete; your deploy then applies over that state.
225
+ - Ctrl+C exits without touching the other run.
226
+
227
+ ## Compose Extensions
228
+
229
+ `docker-stack` reads extra keys under top-level `configs:` and `secrets:` and
230
+ resolves them into real Docker objects before calling `docker stack deploy`.
231
+ Standard Compose keys (`file:`, `external:`, `name:`) continue to work.
232
+
233
+ | Key | Configs | Secrets | Content comes from |
234
+ | --- | --- | --- | --- |
235
+ | `file:` | yes | yes | the file, verbatim (standard Compose) |
236
+ | `x-content` | yes | yes | a literal string in the compose file |
237
+ | `x-template` | yes | yes | a literal string, with `${VAR}` expanded |
238
+ | `x-template-file` | yes | yes | a file, with `${VAR}` expanded |
239
+ | `environment` | no | yes | the named environment variable |
240
+ | `x-generate` | no | yes | a value generated by `docker-stack` |
241
+
242
+ Exactly one content key per object.
243
+
244
+ ### `x-content` — inline content
245
+
246
+ ```yaml
247
+ secrets:
248
+ my_inline_secret:
249
+ x-content: "This is my secret content defined inline."
250
+
251
+ configs:
252
+ my_inline_config:
253
+ x-content: |
254
+ key=value
255
+ another_key=another_value
256
+ ```
257
+
258
+ ### `x-template` and `x-template-file` — environment substitution
259
+
260
+ `${VAR}` references are expanded from the deploying shell's environment.
261
+
262
+ ```yaml
263
+ secrets:
264
+ my_templated_secret:
265
+ x-template: "${API_KEY_NAME}:${MY_API_KEY}"
266
+
267
+ configs:
268
+ my_config_from_template_file:
269
+ x-template-file: "./templates/my_config.tpl"
270
+ ```
271
+
272
+ ### `environment` — content from a variable
273
+
274
+ ```yaml
275
+ secrets:
276
+ api_token:
277
+ environment: API_TOKEN
278
+ configs:
279
+ app_conf:
280
+ environment: APP_CONF_VALUE
281
+ ```
282
+
283
+ If the variable is unset or empty, the deploy fails before any Docker object is
284
+ created.
285
+
286
+ Configs are supported on Docker-Manager deploys, where the value travels in the
287
+ stack `.env` and the manager resolves it. A raw daemon deploy supports secrets
288
+ only. The two are handled differently on purpose: a secret's value is inlined
289
+ locally so it is never written to the `.env` that is stored with the stack.
290
+
291
+ ### `x-generate` — generated secrets
292
+
293
+ Secrets only. Configs must use `x-content`, `x-template`, or `x-template-file`.
294
+
295
+ ```yaml
296
+ secrets:
297
+ # default options, random length 12-20
298
+ simple:
299
+ x-generate: true
300
+
301
+ # fixed length, default character classes
302
+ fixed_length:
303
+ x-generate: 30
304
+
305
+ # explicit character classes
306
+ api_token:
307
+ x-generate:
308
+ length: 40
309
+ numbers: true # digits 0-9 (default true)
310
+ special: true # punctuation (default true)
311
+ uppercase: true # A-Z (default true)
312
+ ```
313
+
314
+ Lowercase letters are always included and the value always starts with a
315
+ letter.
316
+
317
+ `special: true` leaves out `$`, `'`, `"` and `\`, so generated values are safe
318
+ to paste into a shell or a YAML file. Use `special: false` when the application
319
+ rejects punctuation, or for values that go in URLs or HTTP headers:
320
+
321
+ ```yaml
322
+ secrets:
323
+ bearer_token:
324
+ x-generate:
325
+ length: 64
326
+ numbers: true
327
+ special: false
328
+ uppercase: true
329
+ ```
330
+
331
+ ## Versioning and Reuse
332
+
333
+ Docker configs and secrets cannot be changed in place. `docker-stack` handles
334
+ that for you: when a config's content changes, it creates a new version and
335
+ points your services at it. You never have to add `_v2` to names yourself.
336
+
337
+ **Generated secrets are created once.** Redeploying does not change them, so
338
+ anything holding a generated value keeps working. The value survives
339
+ redeploys, restarts and unrelated changes to the stack.
340
+
341
+ ### Stored source metadata
342
+
343
+ Versioned stack configs include a top-level `x-files` list holding
344
+ base64-encoded source material for recovery and auditing: the original compose
345
+ file as `compose.yml`, a generated `.env` containing referenced non-secret
346
+ environment values, and any config files referenced by `configs.*.file` or
347
+ `configs.*.x-template-file`.
348
+
349
+ Secret source files, and the variables named by `secrets.*.environment`, are
350
+ deliberately **not** stored in `x-files`.
351
+
352
+ ### Rotating a generated secret
353
+
354
+ There is no rotate flag. Remove the secret's newest version, then deploy again
355
+ to get a fresh value:
356
+
357
+ ```bash
358
+ docker secret rm <name>_v<N>
359
+ docker-stack deploy --show-generated my-stack docker-compose.yml
360
+ ```
361
+
362
+ `--show-generated` prints the new value. Update anything still holding the old
363
+ one.
364
+
365
+ ### Secrets you created yourself
366
+
367
+ If a secret already exists because you ran `docker secret create`, pointing
368
+ `x-generate` at it does **not** take it over. The deploy generates a new value
369
+ instead, and anything holding the old one stops working.
370
+
371
+ Either leave it as `external: true`, or move to `x-generate` deliberately:
372
+ deploy once with `--show-generated`, then update your clients. After that it
373
+ behaves like any other generated secret.
374
+
375
+ ## Known Limitations
376
+
377
+ Docker limits config content to 500 KB. Stack history includes encoded source
378
+ files, so stacks with large compose or config files can exceed that limit.
379
+
380
+ ## Development
381
+
382
+ Install runtime and test dependencies with either:
383
+
384
+ ```bash
385
+ python3 -m pip install -r requirements-dev.txt
386
+ ```
387
+
388
+ or:
389
+
390
+ ```bash
391
+ python3 -m pip install -e '.[dev]'
392
+ ```