Skip to content

Commit 03a0374

Browse files
authored
Merge pull request #719 from common-workflow-language/singularity_userns
Singularity userns support
2 parents 88a1aee + 763b16b commit 03a0374

File tree

7 files changed

+263
-26
lines changed

7 files changed

+263
-26
lines changed

cwltool/docker.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,25 @@
44
import os
55
import re
66
import shutil
7-
import subprocess
87
import sys
98
import tempfile
109
from io import open
11-
1210
import datetime
11+
import threading
12+
1313
import requests
1414
from typing import (Dict, List, Text, Any, MutableMapping, Set)
15-
import threading
1615

1716
from .docker_id import docker_vm_id
1817
from .errors import WorkflowException
1918
from .job import ContainerCommandLineJob
2019
from .pathmapper import PathMapper, ensure_writable
2120
from .secrets import SecretStore
2221
from .utils import docker_windows_path_adjust, onWindows
22+
if os.name == 'posix' and sys.version_info[0] < 3:
23+
import subprocess32 as subprocess # type: ignore
24+
else:
25+
import subprocess # type: ignore
2326

2427
_logger = logging.getLogger("cwltool")
2528

cwltool/docker_id.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
from __future__ import print_function
22
from __future__ import absolute_import
3-
4-
import subprocess
3+
import os
4+
import sys
55
from typing import List, Text, Tuple
6+
if os.name == 'posix' and sys.version_info[0] < 3:
7+
import subprocess32 as subprocess # type: ignore
8+
else:
9+
import subprocess # type: ignore
610

711

812
def docker_vm_id(): # type: () -> Tuple[int, int]

cwltool/job.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import re
1010
import shutil
1111
import stat
12-
import subprocess
1312
import sys
1413
import tempfile
1514
from abc import ABCMeta, abstractmethod
@@ -28,6 +27,11 @@
2827
from .secrets import SecretStore
2928
from .utils import bytes2str_in_dicts
3029
from .utils import copytree_with_merge, onWindows
30+
if os.name == 'posix' and sys.version_info[0] < 3:
31+
import subprocess32 as subprocess # type: ignore
32+
else:
33+
import subprocess # type: ignore
34+
3135

3236
_logger = logging.getLogger("cwltool")
3337

cwltool/sandboxjs.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,23 @@
55
import os
66
import re
77
import select
8-
import subprocess
98
import threading
109
import sys
1110
from io import BytesIO
1211
from typing import Any, Dict, List, Mapping, Text, Tuple, Union
13-
from .utils import onWindows
14-
from pkg_resources import resource_stream
15-
1612
import six
13+
from pkg_resources import resource_stream
14+
from .utils import onWindows
1715

1816
try:
1917
import queue # type: ignore
2018
except ImportError:
2119
import Queue as queue # type: ignore
20+
if os.name == 'posix' and sys.version_info[0] < 3:
21+
import subprocess32 as subprocess # type: ignore
22+
else:
23+
import subprocess # type: ignore
24+
2225

2326
class JavascriptException(Exception):
2427
pass
@@ -194,7 +197,7 @@ def terminate():
194197

195198
PROCESS_FINISHED_STR = "r1cepzbhUTxtykz5XTC4\n"
196199

197-
def process_finished(): # type: () -> bool
200+
def process_finished(): # type: () -> bool
198201
return stdout_buf.getvalue().decode('utf-8').endswith(PROCESS_FINISHED_STR) and \
199202
stderr_buf.getvalue().decode('utf-8').endswith(PROCESS_FINISHED_STR)
200203

@@ -363,4 +366,4 @@ def fn_linenum(): # type: () -> Text
363366
return json.loads(stdout)
364367
except ValueError as e:
365368
raise JavascriptException(u"%s\nscript was:\n%s\nstdout was: '%s'\nstderr was: '%s'\n" %
366-
(e, fn_linenum(), stdout, stderr))
369+
(e, fn_linenum(), stdout, stderr))

cwltool/singularity.py

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,41 @@
1+
"""Support for executing Docker containers using Singularity."""
12
from __future__ import absolute_import
2-
33
import logging
44
import os
55
import re
66
import shutil
7-
import subprocess
87
import sys
9-
from io import open
10-
11-
from typing import (Dict, List, Text, Optional, MutableMapping, Any)
12-
8+
from io import open # pylint: disable=redefined-builtin
9+
from typing import (Dict, List, Text, Optional, MutableMapping)
1310
from .errors import WorkflowException
1411
from .job import ContainerCommandLineJob
1512
from .pathmapper import PathMapper, ensure_writable
1613
from .process import (UnsupportedRequirement)
1714
from .utils import docker_windows_path_adjust
15+
if os.name == 'posix' and sys.version_info[0] < 3:
16+
from subprocess32 import (check_call, check_output, # pylint: disable=import-error
17+
CalledProcessError, DEVNULL, PIPE, Popen,
18+
TimeoutExpired)
19+
elif os.name == 'posix':
20+
from subprocess import (check_call, check_output, # type: ignore
21+
CalledProcessError, DEVNULL, PIPE, Popen,
22+
TimeoutExpired)
23+
else: # we're not on Unix, so none of this matters
24+
pass
1825

1926
_logger = logging.getLogger("cwltool")
27+
_USERNS = None
28+
29+
def _singularity_supports_userns(): # type: ()->bool
30+
global _USERNS # pylint: disable=global-statement
31+
if _USERNS is None:
32+
try:
33+
_USERNS = "No valid /bin/sh" in Popen(
34+
[u"singularity", u"exec", u"--userns", u"/etc", u"true"],
35+
stderr=PIPE, stdout=DEVNULL).communicate(timeout=60)[1]
36+
except TimeoutExpired:
37+
_USERNS = False
38+
return _USERNS
2039

2140

2241
class SingularityCommandLineJob(ContainerCommandLineJob):
@@ -82,7 +101,7 @@ def get_image(dockerRequirement, # type: Dict[Text, Text]
82101
str(dockerRequirement["dockerPull"])]
83102
_logger.info(Text(cmd))
84103
if not dry_run:
85-
subprocess.check_call(cmd, stdout=sys.stderr)
104+
check_call(cmd, stdout=sys.stderr)
86105
found = True
87106

88107
return found
@@ -107,8 +126,8 @@ def get_from_requirements(self,
107126
if r:
108127
errmsg = None
109128
try:
110-
subprocess.check_output(["singularity", "--version"])
111-
except subprocess.CalledProcessError as err:
129+
check_output(["singularity", "--version"])
130+
except CalledProcessError as err:
112131
errmsg = "Cannot execute 'singularity --version' {}".format(err)
113132
except OSError as err:
114133
errmsg = "'singularity' executable not found: {}".format(err)
@@ -154,7 +173,7 @@ def add_volumes(self, pathmapper, runtime, stage_output):
154173
elif vol.type == "WritableFile":
155174
if self.inplace_update:
156175
runtime.append(u"--bind")
157-
runtime.append("{}:{}:rw".format(
176+
runtime.append(u"{}:{}:rw".format(
158177
docker_windows_path_adjust(vol.resolved),
159178
docker_windows_path_adjust(containertgt)))
160179
else:
@@ -166,7 +185,7 @@ def add_volumes(self, pathmapper, runtime, stage_output):
166185
else:
167186
if self.inplace_update:
168187
runtime.append(u"--bind")
169-
runtime.append("{}:{}:rw".format(
188+
runtime.append(u"{}:{}:rw".format(
170189
docker_windows_path_adjust(vol.resolved),
171190
docker_windows_path_adjust(containertgt)))
172191
else:
@@ -176,7 +195,7 @@ def add_volumes(self, pathmapper, runtime, stage_output):
176195
with open(createtmp, "wb") as tmp:
177196
tmp.write(vol.resolved.encode("utf-8"))
178197
runtime.append(u"--bind")
179-
runtime.append("{}:{}:ro".format(
198+
runtime.append(u"{}:{}:ro".format(
180199
docker_windows_path_adjust(createtmp),
181200
docker_windows_path_adjust(vol.target)))
182201

@@ -192,7 +211,9 @@ def create_runtime(self,
192211
""" Returns the Singularity runtime list of commands and options."""
193212

194213
runtime = [u"singularity", u"--quiet", u"exec", u"--contain", u"--pid",
195-
u"--ipc"] # , u"--userns"]
214+
u"--ipc"]
215+
if _singularity_supports_userns():
216+
runtime.append(u"--userns")
196217
runtime.append(u"--bind")
197218
runtime.append(u"{}:{}:rw".format(
198219
docker_windows_path_adjust(os.path.realpath(self.outdir)),

setup.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
'six >= 1.8.0',
5959
],
6060
extras_require={
61-
':python_version<"3"': [ 'pathlib2' ],
61+
':python_version<"3" and platform_system=="Linux"':
62+
['subprocess32 == 3.5.0rc1'],
63+
':python_version<"3"': ['pathlib2'],
6264
'deps': ["galaxy-lib >= 17.09.3"]
6365
},
6466
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4',

0 commit comments

Comments
 (0)