|
1 | 1 | """Support for executing Docker format containers using Singularity {2,3}.x or Apptainer 1.x.""" |
2 | 2 |
|
| 3 | +import atexit |
3 | 4 | import copy |
4 | 5 | import hashlib |
5 | 6 | import json |
|
11 | 12 | import sys |
12 | 13 | import threading |
13 | 14 | from collections.abc import Callable, MutableMapping |
| 15 | +from importlib.resources import files |
14 | 16 | from subprocess import check_call, check_output, run # nosec |
| 17 | +from tempfile import NamedTemporaryFile |
15 | 18 | from typing import cast |
16 | 19 |
|
17 | 20 | from mypy_extensions import mypyc_attr |
@@ -590,23 +593,50 @@ def create_runtime( |
590 | 593 | """Return the Singularity runtime list of commands and options.""" |
591 | 594 | any_path_okay = self.builder.get_requirement("DockerRequirement")[1] or False |
592 | 595 |
|
593 | | - runtime = [ |
594 | | - "singularity", |
595 | | - "--quiet", |
596 | | - "run" if (is_apptainer_1_1_or_newer() or is_version_3_10_or_newer()) else "exec", |
597 | | - "--ipc", |
598 | | - "--contain", |
599 | | - ] |
600 | 596 | mpi_req, is_req = self.builder.get_requirement(MPIRequirementName) |
601 | | - if not mpi_req or not is_req: |
602 | | - runtime.append("--cleanenv") |
603 | | - else: |
| 597 | + mpi_enabled = mpi_req and is_req |
| 598 | + mpi_env_vars_reference_file_name: str | None = None |
| 599 | + runtime: list[str] = [] |
| 600 | + if mpi_enabled: |
| 601 | + # Save current environment variables. The ``cwl_singularity_wrapper.sh`` will |
| 602 | + # diff it against the env vars produced by mpirun/srun/etc., and use the new |
| 603 | + # env vars as Singularity ``--env`` arguments for MPI. |
| 604 | + with NamedTemporaryFile(mode="wb", delete=False) as f: |
| 605 | + for k, v in os.environ.items(): |
| 606 | + f.write(f"{k}={v}\n") |
| 607 | + mpi_env_vars_reference_file_name = f.name |
| 608 | + |
| 609 | + def delete_mpi_baseline_env() -> None: |
| 610 | + """Clean up the MPI baseline environment variables file at exit.""" |
| 611 | + try: |
| 612 | + os.remove(mpi_env_vars_reference_file_name) |
| 613 | + except FileNotFoundError: |
| 614 | + pass |
| 615 | + atexit.register(delete_mpi_baseline_env) |
| 616 | + |
| 617 | + runtime.extend([ |
| 618 | + str(files("cwltool") / "singularity_wrapper.sh"), |
| 619 | + mpi_env_vars_reference_file_name |
| 620 | + ]) |
| 621 | + |
| 622 | + # MPI implementations like OpenMPI and MPICH use shared memory. |
604 | 623 | self.append_volume( |
605 | 624 | runtime, |
606 | 625 | runtime_context.create_tmpdir(), |
607 | 626 | "/dev/shm", |
608 | 627 | writable=True, |
609 | 628 | ) |
| 629 | + else: |
| 630 | + runtime.append("singularity") |
| 631 | + |
| 632 | + runtime.extend([ |
| 633 | + "--quiet", |
| 634 | + "run" if (is_apptainer_1_1_or_newer() or is_version_3_10_or_newer()) else "exec", |
| 635 | + "--contain", |
| 636 | + "--ipc", |
| 637 | + "--cleanenv", |
| 638 | + ]) |
| 639 | + |
610 | 640 | if is_apptainer_1_1_or_newer() or is_version_3_10_or_newer(): |
611 | 641 | runtime.append("--no-eval") |
612 | 642 |
|
|
0 commit comments