Skip to content

Commit 32da8eb

Browse files
author
Vasileios Karakasis
authored
Merge pull request #2613 from teojgo/feat/apptainer_support
[feat] Add support for the Apptainer container platform
2 parents 0cd7802 + d6f4195 commit 32da8eb

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

docs/config_reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ ReFrame can launch containerized applications, but you need to configure properl
467467
The type of the container platform.
468468
Available values are the following:
469469

470+
- ``Apptainer``: The `Apptainer <https://apptainer.org/>`__ container runtime.
470471
- ``Docker``: The `Docker <https://www.docker.com/>`__ container runtime.
471472
- ``Sarus``: The `Sarus <https://sarus.readthedocs.io/>`__ container runtime.
472473
- ``Shifter``: The `Shifter <https://github.com/NERSC/shifter>`__ container runtime.

reframe/core/containers.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ class Singularity(ContainerPlatform):
243243
def __init__(self):
244244
super().__init__()
245245
self.with_cuda = False
246+
self._launch_command = 'singularity'
246247

247248
def emit_prepare_commands(self, stagedir):
248249
return []
@@ -259,10 +260,23 @@ def launch_command(self, stagedir):
259260

260261
run_opts += self.options
261262
if self.command:
262-
return (f'singularity exec {" ".join(run_opts)} '
263+
return (f'{self._launch_command} exec {" ".join(run_opts)} '
263264
f'{self.image} {self.command}')
264265

265-
return f'singularity run {" ".join(run_opts)} {self.image}'
266+
return f'{self._launch_command} run {" ".join(run_opts)} {self.image}'
267+
268+
269+
class Apptainer(Singularity):
270+
'''Container platform backend for running containers with `Apptainer
271+
<https://apptainer.org/>`__.
272+
273+
.. versionadded:: 4.0.0
274+
275+
'''
276+
277+
def __init__(self):
278+
super().__init__()
279+
self._launch_command = 'apptainer'
266280

267281

268282
class ContainerPlatformField(fields.TypedField):

unittests/test_containers.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
'Sarus', 'Sarus+nocommand', 'Sarus+nopull', 'Sarus+mpi', 'Sarus+load',
1414
'Shifter', 'Shifter+nocommand', 'Shifter+mpi', 'Shifter+nopull',
1515
'Shifter+load',
16-
'Singularity', 'Singularity+nocommand', 'Singularity+cuda'
16+
'Singularity', 'Singularity+nocommand', 'Singularity+cuda',
17+
'Apptainer', 'Apptainer+nocommand', 'Apptainer+cuda'
1718
])
1819
def container_variant(request):
1920
return request.param
@@ -101,7 +102,7 @@ def expected_cmd_mount_points(container_variant):
101102
'--mount=type=bind,source="/path/two",destination="/two" '
102103
'--mount=type=bind,source="/foo",destination="/rfm_workdir" '
103104
'load/library/image:tag cmd')
104-
elif container_variant in {'Singularity', 'Singularity+nopull'}:
105+
elif container_variant == 'Singularity':
105106
return ('singularity exec -B"/path/one:/one" '
106107
'-B"/path/two:/two" -B"/foo:/rfm_workdir" '
107108
'--pwd /rfm_workdir image:tag cmd')
@@ -113,6 +114,19 @@ def expected_cmd_mount_points(container_variant):
113114
return ('singularity run -B"/path/one:/one" '
114115
'-B"/path/two:/two" -B"/foo:/rfm_workdir" '
115116
'--pwd /rfm_workdir image:tag')
117+
elif container_variant == 'Apptainer':
118+
return ('apptainer exec -B"/path/one:/one" '
119+
'-B"/path/two:/two" -B"/foo:/rfm_workdir" '
120+
'--pwd /rfm_workdir image:tag cmd')
121+
elif container_variant == 'Apptainer+cuda':
122+
return ('apptainer exec -B"/path/one:/one" '
123+
'-B"/path/two:/two" -B"/foo:/rfm_workdir" --nv '
124+
'--pwd /rfm_workdir image:tag cmd')
125+
elif container_variant == 'Apptainer+nocommand':
126+
return ('apptainer run -B"/path/one:/one" '
127+
'-B"/path/two:/two" -B"/foo:/rfm_workdir" '
128+
'--pwd /rfm_workdir image:tag')
129+
116130

117131

118132
@pytest.fixture
@@ -180,7 +194,7 @@ def expected_cmd_run_opts(container_variant):
180194
'--mount=type=bind,source="/path/one",destination="/one" '
181195
'--mount=type=bind,source="/foo",destination="/rfm_workdir" '
182196
'--mpi --foo --bar image:tag cmd')
183-
elif container_variant in {'Singularity'}:
197+
elif container_variant == 'Singularity':
184198
return ('singularity exec -B"/path/one:/one" -B"/foo:/rfm_workdir" '
185199
'--foo --bar image:tag cmd')
186200
elif container_variant == 'Singularity+cuda':
@@ -189,6 +203,15 @@ def expected_cmd_run_opts(container_variant):
189203
elif container_variant == 'Singularity+nocommand':
190204
return ('singularity run -B"/path/one:/one" -B"/foo:/rfm_workdir" '
191205
'--foo --bar image:tag')
206+
elif container_variant == 'Apptainer':
207+
return ('apptainer exec -B"/path/one:/one" -B"/foo:/rfm_workdir" '
208+
'--foo --bar image:tag cmd')
209+
elif container_variant == 'Apptainer+cuda':
210+
return ('apptainer exec -B"/path/one:/one" -B"/foo:/rfm_workdir" '
211+
'--nv --foo --bar image:tag cmd')
212+
elif container_variant == 'Apptainer+nocommand':
213+
return ('apptainer run -B"/path/one:/one" -B"/foo:/rfm_workdir" '
214+
'--foo --bar image:tag')
192215

193216

194217
def test_mount_points(container_platform, expected_cmd_mount_points):
@@ -245,6 +268,9 @@ def expected_run_with_commands(container_variant_noopt):
245268
elif container_variant_noopt == 'Singularity':
246269
return ("singularity exec -B\"/foo:/rfm_workdir\" "
247270
"--foo image:tag bash -c 'cmd1; cmd2'")
271+
elif container_variant_noopt == 'Apptainer':
272+
return ("apptainer exec -B\"/foo:/rfm_workdir\" "
273+
"--foo image:tag bash -c 'cmd1; cmd2'")
248274

249275

250276
@pytest.fixture
@@ -267,6 +293,9 @@ def expected_run_with_workdir(container_variant_noopt):
267293
elif container_variant_noopt == 'Singularity':
268294
return ('singularity exec -B\"/foo:/rfm_workdir\" --pwd foodir '
269295
'--foo image:tag cmd1')
296+
elif container_variant_noopt == 'Apptainer':
297+
return ('apptainer exec -B\"/foo:/rfm_workdir\" --pwd foodir '
298+
'--foo image:tag cmd1')
270299

271300

272301
def test_run_with_workdir(container_platform_with_opts,

0 commit comments

Comments
 (0)