snakemake-software-deployment-plugin-container 0.5.2__tar.gz → 0.6.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.
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/.github/workflows/ci.yml +4 -0
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/.gitignore +5 -0
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/CHANGELOG.md +19 -0
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/PKG-INFO +1 -1
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/pyproject.toml +1 -1
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/src/snakemake_software_deployment_plugin_container/__init__.py +42 -2
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/tests/test_plugin.py +21 -27
- snakemake_software_deployment_plugin_container-0.5.2/pixi.lock +0 -1464
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/.github/workflows/conventional-prs.yml +0 -0
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/.github/workflows/release-please.yml +0 -0
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/LICENSE +0 -0
- {snakemake_software_deployment_plugin_container-0.5.2 → snakemake_software_deployment_plugin_container-0.6.1}/README.md +0 -0
|
@@ -41,6 +41,10 @@ jobs:
|
|
|
41
41
|
- name: Setup pixi
|
|
42
42
|
uses: prefix-dev/setup-pixi@v0
|
|
43
43
|
|
|
44
|
+
- run: |
|
|
45
|
+
sudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0
|
|
46
|
+
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
|
47
|
+
|
|
44
48
|
- name: Run pytest
|
|
45
49
|
run: pixi run test -v
|
|
46
50
|
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.1](https://github.com/snakemake/snakemake-software-deployment-plugin-container/compare/v0.6.0...v0.6.1) (2026-06-03)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* add parse and unparse func for runtime argument ([e4f9a8d](https://github.com/snakemake/snakemake-software-deployment-plugin-container/commit/e4f9a8df27ea4848b46127f7f88e8045202ed489))
|
|
9
|
+
|
|
10
|
+
## [0.6.0](https://github.com/snakemake/snakemake-software-deployment-plugin-container/compare/v0.5.2...v0.6.0) (2026-03-10)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* support for docker ([#14](https://github.com/snakemake/snakemake-software-deployment-plugin-container/issues/14)) ([1ccee66](https://github.com/snakemake/snakemake-software-deployment-plugin-container/commit/1ccee662f69a60b4a3afa300c4ec3c70da96bc6a))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* properly handle docker:// urls for non-apptainer runtimes ([2b8323d](https://github.com/snakemake/snakemake-software-deployment-plugin-container/commit/2b8323d0a1731d75393ca9d5c1c2b362358ab6ba))
|
|
21
|
+
|
|
3
22
|
## [0.5.2](https://github.com/snakemake/snakemake-software-deployment-plugin-container/compare/v0.5.1...v0.5.2) (2026-03-10)
|
|
4
23
|
|
|
5
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: snakemake-software-deployment-plugin-container
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Project-URL: repository, https://github.com/snakemake/snakemake-software-deployment-plugin-container
|
|
5
5
|
Project-URL: documentation, https://snakemake.github.io/snakemake-plugin-catalog/plugins/software-deployment/container.html
|
|
6
6
|
Author-email: Ben Carrillo <ben.uzh@pm.me>, Johannes Köster <johannes.koester@uni-due.de>
|
|
@@ -5,6 +5,7 @@ __copyright__ = "Copyright 2025, ben carrillo"
|
|
|
5
5
|
__email__ = "ben.uzh@pm.me"
|
|
6
6
|
__license__ = "MIT"
|
|
7
7
|
|
|
8
|
+
import os
|
|
8
9
|
import shlex
|
|
9
10
|
from dataclasses import dataclass, field
|
|
10
11
|
from os import getcwd
|
|
@@ -33,6 +34,7 @@ class Runtime(SettingsEnumBase):
|
|
|
33
34
|
UDOCKER = 0
|
|
34
35
|
PODMAN = 1
|
|
35
36
|
APPTAINER = 2
|
|
37
|
+
DOCKER = 3
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
@dataclass
|
|
@@ -44,6 +46,8 @@ class Settings(SoftwareDeploymentSettingsBase):
|
|
|
44
46
|
"env_var": False,
|
|
45
47
|
"required": False,
|
|
46
48
|
"choices": Runtime.choices(),
|
|
49
|
+
"parse_func": Runtime.parse_choice,
|
|
50
|
+
"unparse_func": Runtime.item_to_choice,
|
|
47
51
|
},
|
|
48
52
|
)
|
|
49
53
|
mountpoints: List[str] = field(
|
|
@@ -54,6 +58,16 @@ class Settings(SoftwareDeploymentSettingsBase):
|
|
|
54
58
|
"Current working directory and the system tmpdir are always mounted.",
|
|
55
59
|
},
|
|
56
60
|
)
|
|
61
|
+
use_user_namespaces: bool = field(
|
|
62
|
+
default=False,
|
|
63
|
+
metadata={
|
|
64
|
+
"help": "Whether to use user namespaces (if supported by the runtime). "
|
|
65
|
+
"This can be useful to avoid permission issues, but is not always "
|
|
66
|
+
"supported. For non-docker runtimes, this is not needed. "
|
|
67
|
+
"For docker, the fallback option is to set the user and group id via "
|
|
68
|
+
"--user. This happens automatically if this flag here is not used.",
|
|
69
|
+
},
|
|
70
|
+
)
|
|
57
71
|
|
|
58
72
|
|
|
59
73
|
common_settings = CommonSettings(provides="container")
|
|
@@ -92,6 +106,10 @@ class Env(EnvBase):
|
|
|
92
106
|
self.runtime_manager = RuntimeManager(self)
|
|
93
107
|
if self.settings.runtime == Runtime.APPTAINER:
|
|
94
108
|
self.runtime_manager = RuntimeManagerApptainer(self)
|
|
109
|
+
elif self.settings.runtime == Runtime.DOCKER:
|
|
110
|
+
self.runtime_manager = RuntimeManagerDocker(self)
|
|
111
|
+
elif self.settings.runtime == Runtime.UDOCKER:
|
|
112
|
+
self.runtime_manager = RuntimeManagerUdocker(self)
|
|
95
113
|
|
|
96
114
|
# The decorator ensures that the decorated method is only called once
|
|
97
115
|
# in case multiple environments of the same kind are created.
|
|
@@ -156,7 +174,10 @@ class RuntimeManager:
|
|
|
156
174
|
return "-v"
|
|
157
175
|
|
|
158
176
|
def image_uri(self) -> str:
|
|
159
|
-
|
|
177
|
+
image_uri = self.env.spec.image_uri
|
|
178
|
+
if image_uri.startswith("docker://"):
|
|
179
|
+
return image_uri[9:]
|
|
180
|
+
return image_uri
|
|
160
181
|
|
|
161
182
|
def subcommand(self) -> str:
|
|
162
183
|
return "run"
|
|
@@ -186,7 +207,7 @@ class RuntimeManager:
|
|
|
186
207
|
f" {self.workdir_option()} {getcwd()!r}" # Working directory inside container
|
|
187
208
|
f" {mountpoints}"
|
|
188
209
|
f" {self.image_uri()}" # Container image
|
|
189
|
-
" /bin/
|
|
210
|
+
" /bin/bash" # Shell executable
|
|
190
211
|
f" -c {shlex.quote(cmd)}" # The command to execute
|
|
191
212
|
)
|
|
192
213
|
|
|
@@ -208,3 +229,22 @@ class RuntimeManagerApptainer(RuntimeManager):
|
|
|
208
229
|
if re.match(r"[a-z\.]+://", super().image_uri()):
|
|
209
230
|
return super().image_uri()
|
|
210
231
|
return f"docker://{super().image_uri()}"
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class RuntimeManagerDocker(RuntimeManager):
|
|
235
|
+
def options(self) -> str:
|
|
236
|
+
options = super().options()
|
|
237
|
+
if self.env.settings.use_user_namespaces:
|
|
238
|
+
options += " --userns keep-id"
|
|
239
|
+
else:
|
|
240
|
+
uid = os.getuid()
|
|
241
|
+
gid = os.getgid()
|
|
242
|
+
options += f" --user {uid}:{gid}"
|
|
243
|
+
return options
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class RuntimeManagerUdocker(RuntimeManager):
|
|
247
|
+
def options(self) -> str:
|
|
248
|
+
options = super().options()
|
|
249
|
+
options += " --nobanner --env TINI_SUBREAPER=1"
|
|
250
|
+
return options
|
|
@@ -21,18 +21,13 @@ from snakemake_software_deployment_plugin_container import (
|
|
|
21
21
|
Runtime,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
# There can be multiple subclasses of SoftwareDeploymentProviderBase here.
|
|
25
|
-
# This way, you can implement multiple test scenarios.
|
|
26
|
-
# For each subclass, the test suite tests the environment activation and execution
|
|
27
|
-
# within, and, if applicable, environment deployment and archiving.
|
|
28
|
-
|
|
29
24
|
|
|
30
25
|
class TestBase(TestSoftwareDeploymentBase):
|
|
31
|
-
test_container = "
|
|
26
|
+
test_container = "quay.io/biocontainers/samtools:1.23.1--ha83d96e_0"
|
|
32
27
|
|
|
33
28
|
def get_contained_executable(self) -> str:
|
|
34
29
|
# just provide something that is available inside of the container
|
|
35
|
-
return "
|
|
30
|
+
return "samtools"
|
|
36
31
|
|
|
37
32
|
def get_env_spec(self) -> EnvSpecBase:
|
|
38
33
|
# If the software deployment provider does not support deployable environments,
|
|
@@ -50,27 +45,11 @@ class TestBase(TestSoftwareDeploymentBase):
|
|
|
50
45
|
def get_test_cmd(self) -> str:
|
|
51
46
|
# Return a test command that should be executed within the environment
|
|
52
47
|
# with exit code 0 (i.e. without error).
|
|
53
|
-
return "
|
|
48
|
+
return "samtools --version"
|
|
54
49
|
|
|
55
50
|
|
|
56
51
|
class TestApptainerContainer(TestBase):
|
|
57
|
-
|
|
58
|
-
# ERROR : Could not write info to setgroups: Permission denied
|
|
59
|
-
# ERROR : Error while waiting event for user namespace mappings: no event received
|
|
60
|
-
__test__ = False
|
|
61
|
-
|
|
62
|
-
def get_settings(
|
|
63
|
-
self,
|
|
64
|
-
) -> Optional[SoftwareDeploymentSettingsBase]:
|
|
65
|
-
return Settings(runtime=Runtime.APPTAINER)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class TestApptainerContainerWithScheme(TestBase):
|
|
69
|
-
# TODO reactivate apptainer tests, they currently fail in CI with
|
|
70
|
-
# ERROR : Could not write info to setgroups: Permission denied
|
|
71
|
-
# ERROR : Error while waiting event for user namespace mappings: no event received
|
|
72
|
-
__test__ = False
|
|
73
|
-
test_container = "docker://alpine:latest"
|
|
52
|
+
__test__ = True
|
|
74
53
|
|
|
75
54
|
def get_settings(
|
|
76
55
|
self,
|
|
@@ -87,18 +66,33 @@ class TestUDockerContainer(TestBase):
|
|
|
87
66
|
return Settings(runtime=Runtime.UDOCKER)
|
|
88
67
|
|
|
89
68
|
|
|
90
|
-
# Helper function to check if podman is available
|
|
91
69
|
def is_podman_available():
|
|
92
70
|
return shutil.which("podman") is not None
|
|
93
71
|
|
|
94
72
|
|
|
73
|
+
def is_docker_available():
|
|
74
|
+
return shutil.which("docker") is not None
|
|
75
|
+
|
|
76
|
+
|
|
95
77
|
@pytest.mark.skipif(
|
|
96
78
|
not is_podman_available(), reason="podman not available on the system"
|
|
97
79
|
)
|
|
98
80
|
class TestPodmanContainer(TestBase):
|
|
99
81
|
__test__ = True # activate automatic testing
|
|
100
82
|
|
|
101
|
-
def
|
|
83
|
+
def get_settings(
|
|
102
84
|
self,
|
|
103
85
|
) -> Optional[SoftwareDeploymentSettingsBase]:
|
|
104
86
|
return Settings(runtime=Runtime.PODMAN)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@pytest.mark.skipif(
|
|
90
|
+
not is_docker_available(), reason="docker not available on the system"
|
|
91
|
+
)
|
|
92
|
+
class TestDockerContainer(TestBase):
|
|
93
|
+
__test__ = True # activate automatic testing
|
|
94
|
+
|
|
95
|
+
def get_settings(
|
|
96
|
+
self,
|
|
97
|
+
) -> Optional[SoftwareDeploymentSettingsBase]:
|
|
98
|
+
return Settings(runtime=Runtime.DOCKER)
|