mantis-cli 22.1.0__tar.gz → 22.3.0__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 (48) hide show
  1. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/PKG-INFO +130 -10
  2. mantis_cli-22.1.0/mantis_cli.egg-info/PKG-INFO → mantis_cli-22.3.0/README.md +108 -30
  3. mantis_cli-22.3.0/mantis/__init__.py +1 -0
  4. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/app.py +2 -1
  5. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/command_line.py +5 -1
  6. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/connection.py +10 -1
  7. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/containers.py +6 -6
  8. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/managers.py +431 -16
  9. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/mantis.tpl +5 -0
  10. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/schema.py +17 -0
  11. mantis_cli-22.1.0/README.md → mantis_cli-22.3.0/mantis_cli.egg-info/PKG-INFO +150 -7
  12. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis_cli.egg-info/SOURCES.txt +2 -1
  13. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis_cli.egg-info/entry_points.txt +0 -1
  14. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/tests/test_managers.py +198 -0
  15. mantis_cli-22.3.0/tests/test_tunnel.py +379 -0
  16. mantis_cli-22.1.0/mantis/__init__.py +0 -1
  17. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/LICENSE +0 -0
  18. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/MANIFEST.in +0 -0
  19. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/__main__.py +0 -0
  20. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/__init__.py +0 -0
  21. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/compose.py +0 -0
  22. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/configuration.py +0 -0
  23. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/core.py +0 -0
  24. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/django.py +0 -0
  25. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/images.py +0 -0
  26. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/nginx.py +0 -0
  27. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/postgres.py +0 -0
  28. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/secrets.py +0 -0
  29. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/services.py +0 -0
  30. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/commands/volumes.py +0 -0
  31. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/config.py +0 -0
  32. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/cryptography.py +0 -0
  33. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/environment.py +0 -0
  34. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/extensions/__init__.py +0 -0
  35. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/extensions/django.py +0 -0
  36. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/extensions/nginx.py +0 -0
  37. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/extensions/postgres.py +0 -0
  38. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis/helpers.py +0 -0
  39. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis_cli.egg-info/dependency_links.txt +0 -0
  40. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis_cli.egg-info/requires.txt +0 -0
  41. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/mantis_cli.egg-info/top_level.txt +0 -0
  42. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/setup.cfg +0 -0
  43. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/setup.py +0 -0
  44. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/tests/__init__.py +0 -0
  45. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/tests/test_build_config.py +0 -0
  46. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/tests/test_command_line.py +0 -0
  47. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/tests/test_config.py +0 -0
  48. {mantis_cli-22.1.0 → mantis_cli-22.3.0}/tests/test_helpers.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: mantis_cli
3
- Version: 22.1.0
3
+ Version: 22.3.0
4
4
  Summary: Management command to build and deploy webapps, especially based on Django
5
5
  Home-page: https://github.com/PragmaticMates/mantis-cli
6
6
  Author: Erik Telepovský
@@ -9,7 +9,6 @@ Maintainer: Pragmatic Mates
9
9
  Maintainer-email: info@pragmaticmates.com
10
10
  License: GNU General Public License (GPL)
11
11
  Keywords: management deployment docker command
12
- Platform: UNKNOWN
13
12
  Classifier: Programming Language :: Python
14
13
  Classifier: Operating System :: OS Independent
15
14
  Classifier: Environment :: Web Environment
@@ -19,6 +18,27 @@ Classifier: License :: OSI Approved :: GNU General Public License (GPL)
19
18
  Classifier: Development Status :: 5 - Production/Stable
20
19
  Description-Content-Type: text/markdown
21
20
  License-File: LICENSE
21
+ Requires-Dist: cffi
22
+ Requires-Dist: click
23
+ Requires-Dist: cryptography
24
+ Requires-Dist: pycryptodome
25
+ Requires-Dist: pydantic
26
+ Requires-Dist: PyYAML
27
+ Requires-Dist: rich
28
+ Requires-Dist: typer
29
+ Dynamic: author
30
+ Dynamic: author-email
31
+ Dynamic: classifier
32
+ Dynamic: description
33
+ Dynamic: description-content-type
34
+ Dynamic: home-page
35
+ Dynamic: keywords
36
+ Dynamic: license
37
+ Dynamic: license-file
38
+ Dynamic: maintainer
39
+ Dynamic: maintainer-email
40
+ Dynamic: requires-dist
41
+ Dynamic: summary
22
42
 
23
43
  # mantis-cli
24
44
 
@@ -69,6 +89,10 @@ You can use ``<MANTIS>`` variable in your paths if needed as a relative referenc
69
89
  | project_path | string | path to folder with project files on remote server |
70
90
  | connection | string | single connection string (use instead of connections) |
71
91
  | connections | dict | definition of your connections for each environment |
92
+ | tunnel | dict | SSH tunnel settings |
93
+ | tunnel.enabled | bool | share a single SSH connection for the whole run (null = auto)|
94
+ | tunnel.remote_socket | string | path to the docker socket on the server |
95
+ | tunnel.ssh_options | array | extra options passed to the ssh command |
72
96
 
73
97
  TODO:
74
98
  - default values
@@ -144,6 +168,70 @@ Environment files are looked up directly in the `environment.folder` instead of
144
168
 
145
169
  **Note:** You cannot define both `connection` and `connections` in the same config file.
146
170
 
171
+ #### SSH tunnel
172
+
173
+ With a plain `ssh://` connection, Docker opens a **separate SSH connection for every
174
+ command** mantis runs. A single deployment issues dozens of them, and `compose pull` fans
175
+ out over all services at once. That burst runs into sshd's `MaxStartups`, which drops
176
+ connections beyond its threshold:
177
+
178
+ ```
179
+ kex_exchange_identification: read: Connection reset by peer
180
+ ```
181
+
182
+ It is also slow when the connection goes through a `ProxyCommand` (Cloudflare Access,
183
+ bastion hosts, ...), because each connection spawns its own proxy process.
184
+
185
+ The tunnel makes mantis open **one** SSH connection per run, forwarding the remote docker
186
+ socket to a local one and pointing every docker command at it.
187
+
188
+ Docker itself offers no way to pass `ssh` options (`ControlMaster` and friends), so this
189
+ is handled entirely by mantis — no `~/.ssh/config` changes are needed, and connection
190
+ details keep coming from your `ssh://` connection string. Unlike `ControlMaster`
191
+ multiplexing, forwarded channels are not counted against sshd's `MaxSessions`, so no
192
+ server-side configuration is required either.
193
+
194
+ `tunnel.enabled` decides how much mantis verifies before trusting it:
195
+
196
+ | value | behaviour |
197
+ |-------|-----------|
198
+ | unset (default) | detect per run: tunnel, and keep it only if the docker daemon answers through it |
199
+ | `true` | tunnel without detecting, for a server already known to support it |
200
+ | `false` | never tunnel |
201
+
202
+ ```json
203
+ "tunnel": {
204
+ "enabled": true
205
+ }
206
+ ```
207
+
208
+ Detection costs one extra round-trip per run and cannot be skipped by opening the forward
209
+ alone: `ssh -L` to a unix socket succeeds even when nothing listens on the far end, so a
210
+ tunnel only proves itself once the daemon has replied. Set `enabled` explicitly once
211
+ `check-tunnel` (below) confirms a server, and that round-trip goes away.
212
+
213
+ Requirements on the server: the connecting user must be able to read the docker socket
214
+ (typically membership in the `docker` group), and `AllowStreamLocalForwarding` must not
215
+ be disabled — it defaults to `yes`. Whenever the tunnel cannot be used, mantis warns and
216
+ falls back to a connection per docker command, so deployments keep working either way.
217
+
218
+ The check ignores `tunnel.enabled`, so it answers "would this work" rather than "is this
219
+ on" — use it before setting `enabled` to `true`:
220
+
221
+ ```bash
222
+ mantis -e production check-tunnel
223
+ ```
224
+
225
+ It opens the tunnel, asks the remote docker daemon for its version and closes it again,
226
+ exiting non-zero on failure. A refused forward and an unreachable socket are reported
227
+ separately, since they need different fixes (`sshd_config` versus group membership).
228
+
229
+ Pass `--no-tunnel` to disable it for a single run:
230
+
231
+ ```bash
232
+ mantis -e production --no-tunnel deploy
233
+ ```
234
+
147
235
  ### Encryption
148
236
 
149
237
  If you plan to use encryption and decryption of your environment files, you need to create encryption key.
@@ -257,18 +345,18 @@ Run `mantis --help` to see all available commands with their descriptions.
257
345
 
258
346
  | Command / Shortcut | Description |
259
347
  |---------------------------------------|-----------------------------------------------------------|
260
- | logs [CONTAINER] / l | Prints logs of containers |
348
+ | logs [CONTAINER\|SERVICE] / l | Prints logs of containers |
261
349
  | networks / n | Prints docker networks |
262
- | healthcheck [CONTAINER] / hc | Execute health-check of container |
350
+ | healthcheck [CONTAINER\|SERVICE] / hc | Execute health-check of container |
263
351
  | stop [CONTAINERS...] | Stops containers |
264
352
  | start [CONTAINERS...] | Starts containers |
265
353
  | kill [CONTAINERS...] | Kills containers |
266
354
  | remove [CONTAINERS...] [--force] | Removes containers |
267
355
  | rename CONTAINER NEW_NAME | Rename container |
268
- | bash CONTAINER | Runs bash in container |
269
- | sh CONTAINER | Runs sh in container |
270
- | exec CONTAINER COMMAND... | Executes command in container |
271
- | exec-it CONTAINER COMMAND... | Executes command in container (interactive) |
356
+ | bash CONTAINER\|SERVICE | Runs bash in container |
357
+ | sh CONTAINER\|SERVICE | Runs sh in container |
358
+ | exec CONTAINER\|SERVICE COMMAND... | Executes command in container |
359
+ | exec-it CONTAINER\|SERVICE COMMAND... | Executes command in container (interactive) |
272
360
  | get-container-name SERVICE | Gets container name for service |
273
361
  | remove-suffixes [PREFIX] | Removes numerical suffixes from container names |
274
362
 
@@ -323,6 +411,7 @@ Run `mantis --help` to see all available commands with their descriptions.
323
411
  | contexts | Prints all docker contexts |
324
412
  | create-context | Creates docker context |
325
413
  | ssh | Connects to remote host via SSH |
414
+ | check-tunnel | Checks if the docker socket can be tunnelled over SSH |
326
415
 
327
416
  **Django extension:**
328
417
 
@@ -451,6 +540,38 @@ If you need to follow logs of a specific container, you can do it by passing con
451
540
  mantis -e <ENVIRONMENT> logs <container-name>
452
541
  ```
453
542
 
543
+ #### Container or service name
544
+
545
+ Commands taking a container (`logs`, `healthcheck`, `bash`, `sh`, `exec`, `exec-it`) also accept a
546
+ plain service name and mantis finds its container(s) for you, including scaled ones with numerical
547
+ suffixes and services declaring their own `container_name`:
548
+
549
+ ```bash
550
+ mantis -e production logs app # reads logs of <project>-app container
551
+ mantis -e production bash app # same container, no need to type the project prefix
552
+ ```
553
+
554
+ A name which is not a service is still matched against container names without their project
555
+ prefix, which covers services numbered in the compose file:
556
+
557
+ ```bash
558
+ mantis -e production logs htmltopdf # reads <project>-htmltopdf-1 and <project>-htmltopdf-2
559
+ ```
560
+
561
+ An exact container name always takes precedence: if a container literally named `app` exists,
562
+ `logs app` reads that one instead of `<project>-app`. Names matching no container at all are
563
+ passed to docker as they are.
564
+
565
+ `logs` follows all matching containers at once, prefixing every line with a container name:
566
+
567
+ ```
568
+ itfitness-htmltopdf-1 | POST /generate-pdf 200 3355.969 ms - 837045
569
+ itfitness-htmltopdf-2 | POST /generate-pdf 200 889.662 ms - 747746
570
+ ```
571
+
572
+ Commands which can only operate on one container (`bash`, `sh`, `exec`, `exec-it`, `healthcheck`)
573
+ use the first match and warn about the rest.
574
+
454
575
  ### 5. Another useful commands
455
576
 
456
577
  Sometimes, instead of calling whole deployment process, you just need to call compose commands directly:
@@ -490,4 +611,3 @@ Works as follows:
490
611
  ## Release notes
491
612
 
492
613
  Mantis uses semantic versioning. See more in [changelog](https://github.com/PragmaticMates/mantis-cli/blob/master/CHANGES.md).
493
-
@@ -1,25 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: mantis-cli
3
- Version: 22.1.0
4
- Summary: Management command to build and deploy webapps, especially based on Django
5
- Home-page: https://github.com/PragmaticMates/mantis-cli
6
- Author: Erik Telepovský
7
- Author-email: info@pragmaticmates.com
8
- Maintainer: Pragmatic Mates
9
- Maintainer-email: info@pragmaticmates.com
10
- License: GNU General Public License (GPL)
11
- Keywords: management deployment docker command
12
- Platform: UNKNOWN
13
- Classifier: Programming Language :: Python
14
- Classifier: Operating System :: OS Independent
15
- Classifier: Environment :: Web Environment
16
- Classifier: Intended Audience :: Developers
17
- Classifier: Framework :: Django
18
- Classifier: License :: OSI Approved :: GNU General Public License (GPL)
19
- Classifier: Development Status :: 5 - Production/Stable
20
- Description-Content-Type: text/markdown
21
- License-File: LICENSE
22
-
23
1
  # mantis-cli
24
2
 
25
3
  Mantis is a CLI (command line interface) tool designed as a wrapper upon docker and docker compose commands for your project.
@@ -69,6 +47,10 @@ You can use ``<MANTIS>`` variable in your paths if needed as a relative referenc
69
47
  | project_path | string | path to folder with project files on remote server |
70
48
  | connection | string | single connection string (use instead of connections) |
71
49
  | connections | dict | definition of your connections for each environment |
50
+ | tunnel | dict | SSH tunnel settings |
51
+ | tunnel.enabled | bool | share a single SSH connection for the whole run (null = auto)|
52
+ | tunnel.remote_socket | string | path to the docker socket on the server |
53
+ | tunnel.ssh_options | array | extra options passed to the ssh command |
72
54
 
73
55
  TODO:
74
56
  - default values
@@ -144,6 +126,70 @@ Environment files are looked up directly in the `environment.folder` instead of
144
126
 
145
127
  **Note:** You cannot define both `connection` and `connections` in the same config file.
146
128
 
129
+ #### SSH tunnel
130
+
131
+ With a plain `ssh://` connection, Docker opens a **separate SSH connection for every
132
+ command** mantis runs. A single deployment issues dozens of them, and `compose pull` fans
133
+ out over all services at once. That burst runs into sshd's `MaxStartups`, which drops
134
+ connections beyond its threshold:
135
+
136
+ ```
137
+ kex_exchange_identification: read: Connection reset by peer
138
+ ```
139
+
140
+ It is also slow when the connection goes through a `ProxyCommand` (Cloudflare Access,
141
+ bastion hosts, ...), because each connection spawns its own proxy process.
142
+
143
+ The tunnel makes mantis open **one** SSH connection per run, forwarding the remote docker
144
+ socket to a local one and pointing every docker command at it.
145
+
146
+ Docker itself offers no way to pass `ssh` options (`ControlMaster` and friends), so this
147
+ is handled entirely by mantis — no `~/.ssh/config` changes are needed, and connection
148
+ details keep coming from your `ssh://` connection string. Unlike `ControlMaster`
149
+ multiplexing, forwarded channels are not counted against sshd's `MaxSessions`, so no
150
+ server-side configuration is required either.
151
+
152
+ `tunnel.enabled` decides how much mantis verifies before trusting it:
153
+
154
+ | value | behaviour |
155
+ |-------|-----------|
156
+ | unset (default) | detect per run: tunnel, and keep it only if the docker daemon answers through it |
157
+ | `true` | tunnel without detecting, for a server already known to support it |
158
+ | `false` | never tunnel |
159
+
160
+ ```json
161
+ "tunnel": {
162
+ "enabled": true
163
+ }
164
+ ```
165
+
166
+ Detection costs one extra round-trip per run and cannot be skipped by opening the forward
167
+ alone: `ssh -L` to a unix socket succeeds even when nothing listens on the far end, so a
168
+ tunnel only proves itself once the daemon has replied. Set `enabled` explicitly once
169
+ `check-tunnel` (below) confirms a server, and that round-trip goes away.
170
+
171
+ Requirements on the server: the connecting user must be able to read the docker socket
172
+ (typically membership in the `docker` group), and `AllowStreamLocalForwarding` must not
173
+ be disabled — it defaults to `yes`. Whenever the tunnel cannot be used, mantis warns and
174
+ falls back to a connection per docker command, so deployments keep working either way.
175
+
176
+ The check ignores `tunnel.enabled`, so it answers "would this work" rather than "is this
177
+ on" — use it before setting `enabled` to `true`:
178
+
179
+ ```bash
180
+ mantis -e production check-tunnel
181
+ ```
182
+
183
+ It opens the tunnel, asks the remote docker daemon for its version and closes it again,
184
+ exiting non-zero on failure. A refused forward and an unreachable socket are reported
185
+ separately, since they need different fixes (`sshd_config` versus group membership).
186
+
187
+ Pass `--no-tunnel` to disable it for a single run:
188
+
189
+ ```bash
190
+ mantis -e production --no-tunnel deploy
191
+ ```
192
+
147
193
  ### Encryption
148
194
 
149
195
  If you plan to use encryption and decryption of your environment files, you need to create encryption key.
@@ -257,18 +303,18 @@ Run `mantis --help` to see all available commands with their descriptions.
257
303
 
258
304
  | Command / Shortcut | Description |
259
305
  |---------------------------------------|-----------------------------------------------------------|
260
- | logs [CONTAINER] / l | Prints logs of containers |
306
+ | logs [CONTAINER\|SERVICE] / l | Prints logs of containers |
261
307
  | networks / n | Prints docker networks |
262
- | healthcheck [CONTAINER] / hc | Execute health-check of container |
308
+ | healthcheck [CONTAINER\|SERVICE] / hc | Execute health-check of container |
263
309
  | stop [CONTAINERS...] | Stops containers |
264
310
  | start [CONTAINERS...] | Starts containers |
265
311
  | kill [CONTAINERS...] | Kills containers |
266
312
  | remove [CONTAINERS...] [--force] | Removes containers |
267
313
  | rename CONTAINER NEW_NAME | Rename container |
268
- | bash CONTAINER | Runs bash in container |
269
- | sh CONTAINER | Runs sh in container |
270
- | exec CONTAINER COMMAND... | Executes command in container |
271
- | exec-it CONTAINER COMMAND... | Executes command in container (interactive) |
314
+ | bash CONTAINER\|SERVICE | Runs bash in container |
315
+ | sh CONTAINER\|SERVICE | Runs sh in container |
316
+ | exec CONTAINER\|SERVICE COMMAND... | Executes command in container |
317
+ | exec-it CONTAINER\|SERVICE COMMAND... | Executes command in container (interactive) |
272
318
  | get-container-name SERVICE | Gets container name for service |
273
319
  | remove-suffixes [PREFIX] | Removes numerical suffixes from container names |
274
320
 
@@ -323,6 +369,7 @@ Run `mantis --help` to see all available commands with their descriptions.
323
369
  | contexts | Prints all docker contexts |
324
370
  | create-context | Creates docker context |
325
371
  | ssh | Connects to remote host via SSH |
372
+ | check-tunnel | Checks if the docker socket can be tunnelled over SSH |
326
373
 
327
374
  **Django extension:**
328
375
 
@@ -451,6 +498,38 @@ If you need to follow logs of a specific container, you can do it by passing con
451
498
  mantis -e <ENVIRONMENT> logs <container-name>
452
499
  ```
453
500
 
501
+ #### Container or service name
502
+
503
+ Commands taking a container (`logs`, `healthcheck`, `bash`, `sh`, `exec`, `exec-it`) also accept a
504
+ plain service name and mantis finds its container(s) for you, including scaled ones with numerical
505
+ suffixes and services declaring their own `container_name`:
506
+
507
+ ```bash
508
+ mantis -e production logs app # reads logs of <project>-app container
509
+ mantis -e production bash app # same container, no need to type the project prefix
510
+ ```
511
+
512
+ A name which is not a service is still matched against container names without their project
513
+ prefix, which covers services numbered in the compose file:
514
+
515
+ ```bash
516
+ mantis -e production logs htmltopdf # reads <project>-htmltopdf-1 and <project>-htmltopdf-2
517
+ ```
518
+
519
+ An exact container name always takes precedence: if a container literally named `app` exists,
520
+ `logs app` reads that one instead of `<project>-app`. Names matching no container at all are
521
+ passed to docker as they are.
522
+
523
+ `logs` follows all matching containers at once, prefixing every line with a container name:
524
+
525
+ ```
526
+ itfitness-htmltopdf-1 | POST /generate-pdf 200 3355.969 ms - 837045
527
+ itfitness-htmltopdf-2 | POST /generate-pdf 200 889.662 ms - 747746
528
+ ```
529
+
530
+ Commands which can only operate on one container (`bash`, `sh`, `exec`, `exec-it`, `healthcheck`)
531
+ use the first match and warn about the rest.
532
+
454
533
  ### 5. Another useful commands
455
534
 
456
535
  Sometimes, instead of calling whole deployment process, you just need to call compose commands directly:
@@ -489,5 +568,4 @@ Works as follows:
489
568
 
490
569
  ## Release notes
491
570
 
492
- Mantis uses semantic versioning. See more in [changelog](https://github.com/PragmaticMates/mantis-cli/blob/master/CHANGES.md).
493
-
571
+ Mantis uses semantic versioning. See more in [changelog](https://github.com/PragmaticMates/mantis-cli/blob/master/CHANGES.md).
@@ -0,0 +1 @@
1
+ VERSION = '22.3.0'
@@ -191,6 +191,7 @@ def main(
191
191
  environment: Optional[str] = typer.Option(None, "--env", "-e", help="Environment ID"),
192
192
  mode: str = typer.Option("remote", "--mode", "-m", help="Execution mode: remote, ssh, host"),
193
193
  dry_run: bool = typer.Option(False, "--dry-run", "-n", help="Show commands without executing"),
194
+ no_tunnel: bool = typer.Option(False, "--no-tunnel", help="Do not tunnel the remote docker socket over a single SSH connection"),
194
195
  version: bool = typer.Option(False, "--version", "-v", callback=version_callback, is_eager=True, help="Show version and exit"),
195
196
  ):
196
197
  """Mantis CLI - Docker deployment tool."""
@@ -216,4 +217,4 @@ def main(
216
217
 
217
218
  state._mode = mode
218
219
  state._dry_run = dry_run
219
- state._manager = get_manager(environment, mode, dry_run=dry_run, commands=commands)
220
+ state._manager = get_manager(environment, mode, dry_run=dry_run, commands=commands, use_tunnel=not no_tunnel)
@@ -99,6 +99,7 @@ def parse_global_options(global_opts: List[str]) -> dict:
99
99
  'env': None,
100
100
  'mode': 'remote',
101
101
  'dry_run': False,
102
+ 'use_tunnel': True,
102
103
  }
103
104
 
104
105
  i = 0
@@ -113,6 +114,9 @@ def parse_global_options(global_opts: List[str]) -> dict:
113
114
  elif opt in ('-n', '--dry-run'):
114
115
  result['dry_run'] = True
115
116
  i += 1
117
+ elif opt == '--no-tunnel':
118
+ result['use_tunnel'] = False
119
+ i += 1
116
120
  else:
117
121
  i += 1
118
122
 
@@ -185,7 +189,7 @@ def run():
185
189
  all_commands = [group[0] for group in cmd_groups if group]
186
190
  state._mode = opts['mode']
187
191
  state._dry_run = opts['dry_run']
188
- state._manager = get_manager(opts['env'], opts['mode'], dry_run=opts['dry_run'], commands=all_commands)
192
+ state._manager = get_manager(opts['env'], opts['mode'], dry_run=opts['dry_run'], commands=all_commands, use_tunnel=opts['use_tunnel'])
189
193
 
190
194
  # Get Click app from Typer
191
195
  click_app = typer.main.get_command(app)
@@ -1,4 +1,6 @@
1
- """Connection commands: contexts, create-context, ssh."""
1
+ """Connection commands: contexts, create-context, ssh, check-tunnel."""
2
+ import typer
3
+
2
4
  from mantis.app import command, state
3
5
 
4
6
 
@@ -18,3 +20,10 @@ def create_context():
18
20
  def ssh_cmd():
19
21
  """Connects to remote host via SSH"""
20
22
  state.ssh()
23
+
24
+
25
+ @command(name="check-tunnel", panel="Connections")
26
+ def check_tunnel():
27
+ """Checks if the docker socket can be tunnelled over SSH"""
28
+ if not state.check_tunnel():
29
+ raise typer.Exit(code=1)
@@ -8,7 +8,7 @@ from mantis.app import command, state
8
8
 
9
9
  @command(shortcut="l", panel="Containers")
10
10
  def logs(
11
- container: Optional[str] = typer.Argument(None, help="Container name"),
11
+ container: Optional[str] = typer.Argument(None, help="Container or service name"),
12
12
  ):
13
13
  """Prints logs of containers"""
14
14
  state.logs(container)
@@ -22,7 +22,7 @@ def networks():
22
22
 
23
23
  @command(shortcut="hc", panel="Containers")
24
24
  def healthcheck(
25
- container: Optional[str] = typer.Argument(None, help="Container name"),
25
+ container: Optional[str] = typer.Argument(None, help="Container or service name"),
26
26
  ):
27
27
  """Execute health-check of container"""
28
28
  state.healthcheck(container)
@@ -72,7 +72,7 @@ def rename(
72
72
 
73
73
  @command(panel="Containers")
74
74
  def bash(
75
- container: str = typer.Argument(..., help="Container name"),
75
+ container: str = typer.Argument(..., help="Container or service name"),
76
76
  ):
77
77
  """Runs bash in container"""
78
78
  state.bash(container)
@@ -80,7 +80,7 @@ def bash(
80
80
 
81
81
  @command(panel="Containers")
82
82
  def sh(
83
- container: str = typer.Argument(..., help="Container name"),
83
+ container: str = typer.Argument(..., help="Container or service name"),
84
84
  ):
85
85
  """Runs sh in container"""
86
86
  state.sh(container)
@@ -88,7 +88,7 @@ def sh(
88
88
 
89
89
  @command(name="exec", panel="Containers")
90
90
  def exec_cmd(
91
- container: str = typer.Argument(..., help="Container name"),
91
+ container: str = typer.Argument(..., help="Container or service name"),
92
92
  cmd: List[str] = typer.Argument(..., help="Command to execute"),
93
93
  ):
94
94
  """Executes command in container"""
@@ -97,7 +97,7 @@ def exec_cmd(
97
97
 
98
98
  @command(name="exec-it", panel="Containers")
99
99
  def exec_it(
100
- container: str = typer.Argument(..., help="Container name"),
100
+ container: str = typer.Argument(..., help="Container or service name"),
101
101
  cmd: List[str] = typer.Argument(..., help="Command to execute"),
102
102
  ):
103
103
  """Executes command in container (interactive)"""