Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/cwltool/singularity.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/cwltool/singularity.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,375 +0,0 @@ -"""Support for executing Docker containers using the Singularity 2.x engine.""" -from __future__ import absolute_import - -import os -import os.path -import re -import shutil -import tempfile -import sys -from distutils import spawn -from io import open # pylint: disable=redefined-builtin -from typing import Dict, List, MutableMapping, Optional, Tuple - -from schema_salad.sourceline import SourceLine -from typing_extensions import Text # pylint: disable=unused-import -# move to a regular typing import when Python 3.3-3.6 is no longer supported - -from .context import RuntimeContext # pylint: disable=unused-import -from .errors import WorkflowException -from .job import ContainerCommandLineJob -from .loghandler import _logger -from .pathmapper import PathMapper, MapperEnt # pylint: disable=unused-import -from .pathmapper import ensure_writable, ensure_non_writable -from .process import UnsupportedRequirement -from .utils import docker_windows_path_adjust - -if os.name == 'posix': - if sys.version_info < (3, 5): - from subprocess32 import ( # nosec # pylint: disable=import-error,no-name-in-module - check_call, check_output, CalledProcessError, DEVNULL, PIPE, Popen, - TimeoutExpired) - else: - from subprocess import ( # nosec # pylint: disable=import-error,no-name-in-module - check_call, check_output, CalledProcessError, DEVNULL, PIPE, Popen, - TimeoutExpired) - -else: # we're not on Unix, so none of this matters - pass - -_USERNS = None -_SINGULARITY_VERSION = "" - -def _singularity_supports_userns(): # type: ()->bool - global _USERNS # pylint: disable=global-statement - if _USERNS is None: - try: - hello_image = os.path.join(os.path.dirname(__file__), 'hello.simg') - result = Popen( # nosec - [u"singularity", u"exec", u"--userns", hello_image, u"true"], - stderr=PIPE, stdout=DEVNULL, - universal_newlines=True).communicate(timeout=60)[1] - _USERNS = "No valid /bin/sh" in result - except TimeoutExpired: - _USERNS = False - return _USERNS - - -def get_version(): # type: ()->Text - global _SINGULARITY_VERSION # pylint: disable=global-statement - if not _SINGULARITY_VERSION: - _SINGULARITY_VERSION = check_output(["singularity", "--version"], universal_newlines=True) - if _SINGULARITY_VERSION.startswith("singularity version "): - _SINGULARITY_VERSION = _SINGULARITY_VERSION[20:] - return _SINGULARITY_VERSION - -def is_version_2_6(): # type: ()->bool - return get_version().startswith("2.6") - -def is_version_3_or_newer(): # type: ()->bool - return int(get_version()[0]) >= 3 - -def is_version_3_1_or_newer(): # type: ()->bool - version = get_version().split('.') - return int(version[0]) >= 4 or (int(version[0]) == 3 and int(version[1]) >= 1) - -def _normalize_image_id(string): # type: (Text)->Text - return string.replace('/', '_') + '.img' - -def _normalize_sif_id(string): # type: (Text)->Text - return string.replace('/', '_') + '.sif' - -class SingularityCommandLineJob(ContainerCommandLineJob): - - @staticmethod - def get_image(dockerRequirement, # type: Dict[Text, Text] - pull_image, # type: bool - force_pull=False # type: bool - ): - # type: (...) -> bool - """ - Acquire the software container image in the specified dockerRequirement. - - Uses Singularity and returns the success as a bool. Updates the - provided dockerRequirement with the specific dockerImageId to the full - path of the local image, if found. Likewise the - dockerRequirement['dockerPull'] is updated to a docker:// URI if needed. - """ - found = False - - candidates = [] - - cache_folder = None - if "CWL_SINGULARITY_CACHE" in os.environ: - cache_folder = os.environ["CWL_SINGULARITY_CACHE"] - elif is_version_2_6() and "SINGULARITY_PULLFOLDER" in os.environ: - cache_folder = os.environ["SINGULARITY_PULLFOLDER"] - - if "dockerImageId" not in dockerRequirement and "dockerPull" in dockerRequirement: - match = re.search(pattern=r'([a-z]*://)', string=dockerRequirement["dockerPull"]) - img_name = _normalize_image_id(dockerRequirement['dockerPull']) - candidates.append(img_name) - if is_version_3_or_newer(): - sif_name = _normalize_sif_id(dockerRequirement['dockerPull']) - candidates.append(sif_name) - dockerRequirement["dockerImageId"] = sif_name - else: - dockerRequirement["dockerImageId"] = img_name - if not match: - dockerRequirement["dockerPull"] = "docker://" + dockerRequirement["dockerPull"] - elif "dockerImageId" in dockerRequirement: - if os.path.isfile(dockerRequirement['dockerImageId']): - found = True - candidates.append(dockerRequirement['dockerImageId']) - candidates.append(_normalize_image_id(dockerRequirement['dockerImageId'])) - if is_version_3_or_newer(): - candidates.append(_normalize_sif_id(dockerRequirement['dockerPull'])) - - targets = [os.getcwd()] - if "CWL_SINGULARITY_CACHE" in os.environ: - targets.append(os.environ["CWL_SINGULARITY_CACHE"]) - if is_version_2_6() and "SINGULARITY_PULLFOLDER" in os.environ: - targets.append(os.environ["SINGULARITY_PULLFOLDER"]) - for target in targets: - for dirpath, subdirs, files in os.walk(target): - for entry in files: - if entry in candidates: - path = os.path.join(dirpath, entry) - if os.path.isfile(path): - _logger.info( - "Using local copy of Singularity image found in %s", - dirpath) - dockerRequirement["dockerImageId"] = path - found = True - if (force_pull or not found) and pull_image: - cmd = [] # type: List[Text] - if "dockerPull" in dockerRequirement: - if cache_folder: - env = os.environ.copy() - if is_version_2_6(): - env['SINGULARITY_PULLFOLDER'] = cache_folder - cmd = ["singularity", "pull", "--force", "--name", - dockerRequirement["dockerImageId"], - str(dockerRequirement["dockerPull"])] - else: - cmd = ["singularity", "pull", "--force", "--name", - "{}/{}".format( - cache_folder, - dockerRequirement["dockerImageId"]), - str(dockerRequirement["dockerPull"])] - - _logger.info(Text(cmd)) - check_call(cmd, env=env, stdout=sys.stderr) # nosec - dockerRequirement["dockerImageId"] = '{}/{}'.format( - cache_folder, dockerRequirement["dockerImageId"]) - found = True - else: - cmd = ["singularity", "pull", "--force", "--name", - str(dockerRequirement["dockerImageId"]), - str(dockerRequirement["dockerPull"])] - _logger.info(Text(cmd)) - check_call(cmd, stdout=sys.stderr) # nosec - found = True - - elif "dockerFile" in dockerRequirement: - raise WorkflowException(SourceLine( - dockerRequirement, 'dockerFile').makeError( - "dockerFile is not currently supported when using the " - "Singularity runtime for Docker containers.")) - elif "dockerLoad" in dockerRequirement: - if is_version_3_1_or_newer(): - if 'dockerImageId' in dockerRequirement: - name = "{}.sif".format(dockerRequirement["dockerImageId"]) - else: - name = "{}.sif".format(dockerRequirement["dockerLoad"]) - cmd = ["singularity", "build", name, - "docker-archive://{}".format(dockerRequirement["dockerLoad"])] - _logger.info(Text(cmd)) - check_call(cmd, stdout=sys.stderr) # nosec - found = True - dockerRequirement['dockerImageId'] = name - raise WorkflowException(SourceLine( - dockerRequirement, 'dockerLoad').makeError( - "dockerLoad is not currently supported when using the " - "Singularity runtime (version less than 3.1) for Docker containers.")) - elif "dockerImport" in dockerRequirement: - raise WorkflowException(SourceLine( - dockerRequirement, 'dockerImport').makeError( - "dockerImport is not currently supported when using the " - "Singularity runtime for Docker containers.")) - - return found - - def get_from_requirements(self, - r, # type: Dict[Text, Text] - pull_image, # type: bool - force_pull=False, # type: bool - tmp_outdir_prefix=None # type: Optional[Text] - ): - # type: (...) -> Optional[Text] - """ - Return the filename of the Singularity image. - - (e.g. hello-world-latest.{img,sif}). - """ - if not bool(spawn.find_executable('singularity')): - raise WorkflowException('singularity executable is not available') - - if not self.get_image(r, pull_image, force_pull): - raise WorkflowException(u"Container image {} not " - "found".format(r["dockerImageId"])) - - return os.path.abspath(r["dockerImageId"]) - - @staticmethod - def append_volume(runtime, source, target, writable=False): - # type: (List[Text], Text, Text, bool) -> None - runtime.append(u"--bind") - runtime.append("{}:{}:{}".format( - docker_windows_path_adjust(source), - docker_windows_path_adjust(target), "rw" if writable else "ro")) - - def add_file_or_directory_volume(self, - runtime, # type: List[Text] - volume, # type: MapperEnt - host_outdir_tgt # type: Optional[Text] - ): # type: (...) -> None - if host_outdir_tgt is not None: - # workaround for lack of overlapping mounts in Singularity - # revert to daa923d5b0be3819b6ed0e6440e7193e65141052 - # once https://github.com/sylabs/singularity/issues/1607 - # is fixed - if volume.type == "File": - shutil.copy(volume.resolved, host_outdir_tgt) - else: - shutil.copytree(volume.resolved, host_outdir_tgt) - ensure_non_writable(host_outdir_tgt) - elif not volume.resolved.startswith("_:"): - self.append_volume(runtime, volume.resolved, volume.target) - - def add_writable_file_volume(self, - runtime, # type: List[Text] - volume, # type: MapperEnt - host_outdir_tgt, # type: Optional[Text] - tmpdir_prefix # type: Text - ): # type: (...) -> None - if host_outdir_tgt is not None: - # workaround for lack of overlapping mounts in Singularity - # revert to daa923d5b0be3819b6ed0e6440e7193e65141052 - # once https://github.com/sylabs/singularity/issues/1607 - # is fixed - if self.inplace_update: - try: - os.link(os.path.realpath(volume.resolved), - host_outdir_tgt) - except os.error: - shutil.copy(volume.resolved, host_outdir_tgt) - else: - shutil.copy(volume.resolved, host_outdir_tgt) - ensure_writable(host_outdir_tgt) - elif self.inplace_update: - self.append_volume( - runtime, volume.resolved, volume.target, writable=True) - ensure_writable(volume.resolved) - else: - tmp_dir, tmp_prefix = os.path.split(tmpdir_prefix) - file_copy = os.path.join( - tempfile.mkdtemp(prefix=tmp_prefix, dir=tmp_dir), - os.path.basename(volume.resolved)) - shutil.copy(volume.resolved, file_copy) - #volume.resolved = file_copy - self.append_volume( - runtime, file_copy, volume.target, writable=True) - ensure_writable(file_copy) - - def add_writable_directory_volume(self, - runtime, # type: List[Text] - volume, # type: MapperEnt - host_outdir_tgt, # type: Optional[Text] - tmpdir_prefix # type: Text - ): # type: (...) -> None - if volume.resolved.startswith("_:"): - if host_outdir_tgt is not None: - new_dir = host_outdir_tgt - else: - tmp_dir, tmp_prefix = os.path.split(tmpdir_prefix) - new_dir = os.path.join( - tempfile.mkdtemp(prefix=tmp_prefix, dir=tmp_dir), - os.path.basename(volume.resolved)) - os.makedirs(new_dir) - else: - if host_outdir_tgt is not None: - # workaround for lack of overlapping mounts in Singularity - # revert to daa923d5b0be3819b6ed0e6440e7193e65141052 - # once https://github.com/sylabs/singularity/issues/1607 - # is fixed - shutil.copytree(volume.resolved, host_outdir_tgt) - ensure_writable(host_outdir_tgt) - else: - if not self.inplace_update: - tmp_dir, tmp_prefix = os.path.split(tmpdir_prefix) - dir_copy = os.path.join( - tempfile.mkdtemp(prefix=tmp_prefix, dir=tmp_dir), - os.path.basename(volume.resolved)) - shutil.copytree(volume.resolved, dir_copy) - source = dir_copy - #volume.resolved = dir_copy - else: - source = volume.resolved - self.append_volume( - runtime, source, volume.target, writable=True) - ensure_writable(source) - - - def create_runtime(self, - env, # type: MutableMapping[Text, Text] - runtime_context # type: RuntimeContext - ): # type: (...) -> Tuple[List[Text], Optional[Text]] - """Return the Singularity runtime list of commands and options.""" - any_path_okay = self.builder.get_requirement("DockerRequirement")[1] \ - or False - runtime = [u"singularity", u"--quiet", u"exec", u"--contain", u"--pid", - u"--ipc"] - if _singularity_supports_userns(): - runtime.append(u"--userns") - if is_version_3_1_or_newer(): - runtime.append(u"--home") - runtime.append(u"{}:{}".format( - docker_windows_path_adjust(os.path.realpath(self.outdir)), - self.builder.outdir)) - else: - runtime.append(u"--bind") - runtime.append(u"{}:{}:rw".format( - docker_windows_path_adjust(os.path.realpath(self.outdir)), - self.builder.outdir)) - runtime.append(u"--bind") - tmpdir = "/tmp" # nosec - runtime.append(u"{}:{}:rw".format( - docker_windows_path_adjust(os.path.realpath(self.tmpdir)), tmpdir)) - - self.add_volumes(self.pathmapper, runtime, any_path_okay=True, - secret_store=runtime_context.secret_store, - tmpdir_prefix=runtime_context.tmpdir_prefix) - if self.generatemapper is not None: - self.add_volumes( - self.generatemapper, runtime, any_path_okay=any_path_okay, - secret_store=runtime_context.secret_store, - tmpdir_prefix=runtime_context.tmpdir_prefix) - - runtime.append(u"--pwd") - runtime.append(u"%s" % (docker_windows_path_adjust(self.builder.outdir))) - - - if runtime_context.custom_net: - raise UnsupportedRequirement( - "Singularity implementation does not support custom networking") - elif runtime_context.disable_net: - runtime.append(u"--net") - - env["SINGULARITYENV_TMPDIR"] = tmpdir - env["SINGULARITYENV_HOME"] = self.builder.outdir - - for name, value in self.environment.items(): - env["SINGULARITYENV_{}".format(name)] = str(value) - return (runtime, None) -