12
12
from .pathmapper import PathMapper , ensure_writable
13
13
from .process import (UnsupportedRequirement )
14
14
from .utils import docker_windows_path_adjust
15
+ from schema_salad .sourceline import SourceLine
15
16
if os .name == 'posix' and sys .version_info [0 ] < 3 :
16
17
from subprocess32 import (check_call , check_output , # pylint: disable=import-error
17
18
CalledProcessError , DEVNULL , PIPE , Popen ,
@@ -30,19 +31,27 @@ def _singularity_supports_userns(): # type: ()->bool
30
31
global _USERNS # pylint: disable=global-statement
31
32
if _USERNS is None :
32
33
try :
33
- _USERNS = "No valid /bin/sh" in Popen (
34
+ result = Popen (
34
35
[u"singularity" , u"exec" , u"--userns" , u"/etc" , u"true" ],
35
- stderr = PIPE , stdout = DEVNULL ).communicate (timeout = 60 )[1 ]
36
+ stderr = PIPE , stdout = DEVNULL ,
37
+ universal_newlines = True ).communicate (timeout = 60 )[1 ]
38
+ _USERNS = "No valid /bin/sh" in result
36
39
except TimeoutExpired :
37
40
_USERNS = False
38
41
return _USERNS
39
42
43
+ def _normalizeImageId (string ): # type: (Text)->Text
44
+ candidate = re .sub (pattern = r'([a-z]*://)' , repl = r'' , string = string )
45
+ return re .sub (pattern = r'[:/]' , repl = r'-' , string = candidate ) + ".img"
46
+
40
47
41
48
class SingularityCommandLineJob (ContainerCommandLineJob ):
49
+
42
50
@staticmethod
43
51
def get_image (dockerRequirement , # type: Dict[Text, Text]
44
52
pull_image , # type: bool
45
- dry_run = False # type: bool
53
+ dry_run = False , # type: bool
54
+ force_pull = False # type: bool
46
55
):
47
56
# type: (...) -> bool
48
57
"""
@@ -54,55 +63,56 @@ def get_image(dockerRequirement, # type: Dict[Text, Text]
54
63
"""
55
64
found = False
56
65
66
+ candidates = []
67
+
57
68
if "dockerImageId" not in dockerRequirement and "dockerPull" in dockerRequirement :
58
69
match = re .search (pattern = r'([a-z]*://)' , string = dockerRequirement ["dockerPull" ])
59
- if match :
60
- dockerRequirement ["dockerImageId" ] = re .sub (pattern = r'([a-z]*://)' , repl = r'' ,
61
- string = dockerRequirement ["dockerPull" ])
62
- dockerRequirement ["dockerImageId" ] = re .sub (
63
- pattern = r'[:/]' , repl = r'-' , string = dockerRequirement ["dockerImageId" ]) + ".img"
64
- else :
65
- dockerRequirement ["dockerImageId" ] = re .sub (
66
- pattern = r'[:/]' , repl = r'-' , string = dockerRequirement ["dockerPull" ]) + ".img"
70
+ candidate = _normalizeImageId (dockerRequirement ['dockerPull' ])
71
+ candidates .append (candidate )
72
+ dockerRequirement ['dockerImageId' ] = candidate
73
+ if not match :
67
74
dockerRequirement ["dockerPull" ] = "docker://" + dockerRequirement ["dockerPull" ]
75
+ elif "dockerImageId" in dockerRequirement :
76
+ candidates .append (dockerRequirement ['dockerImageId' ])
77
+ candidates .append (_normalizeImageId (dockerRequirement ['dockerImageId' ]))
68
78
69
79
# check if Singularity image is available in $SINGULARITY_CACHEDIR
70
- if "SINGULARITY_CACHEDIR" in os .environ and os .path .isfile (
71
- os .path .join (os .environ ["SINGULARITY_CACHEDIR" ],
72
- dockerRequirement ["dockerImageId" ])):
73
- _logger .info ("Using local copy of Singularity image found in "
74
- "$SINGULARITY_CACHEDIR" )
75
- dockerRequirement ["dockerImageId" ] = os .path .join (
76
- os .environ ["SINGULARITY_CACHEDIR" ],
77
- dockerRequirement ["dockerImageId" ])
78
- found = True
79
-
80
- # check if Singularity image is available in $SINGULARITY_PULLFOLDER
81
- elif "SINGULARITY_PULLFOLDER" in os .environ and os .path .isfile (
82
- os .path .join (os .environ ["SINGULARITY_PULLFOLDER" ],
83
- dockerRequirement ["dockerImageId" ])):
84
- _logger .info ("Using local copy of Singularity image found in "
85
- "$SINGULARITY_PULLFOLDER" )
86
- dockerRequirement ["dockerImageId" ] = os .path .join (
87
- os .environ ["SINGULARITY_PULLFOLDER" ],
88
- dockerRequirement ["dockerImageId" ])
89
- found = True
90
-
91
- # check if Singularity image is available in current working directory
92
- elif os .path .isfile (dockerRequirement ["dockerImageId" ]):
93
- _logger .info ("Using local copy of Singularity image" )
94
- found = True
95
-
96
- # if the .img file is not already present, pull the image
97
- elif pull_image :
80
+ for target in ("SINGULARITY_CACHEDIR" , "SINGULARITY_PULLFOLDER" ,
81
+ os .getcwd ()):
82
+ if target in os .environ :
83
+ for candidate in candidates :
84
+ path = os .path .join (os .environ [target ], candidate )
85
+ if os .path .isfile (path ):
86
+ _logger .info ("Using local copy of Singularity image "
87
+ "found in {}" .format (target ))
88
+ dockerRequirement ["dockerImageId" ] = path
89
+ found = True
90
+
91
+ if (force_pull or not found ) and pull_image :
98
92
cmd = [] # type: List[Text]
99
93
if "dockerPull" in dockerRequirement :
100
- cmd = ["singularity" , "pull" , "--name" , str (dockerRequirement ["dockerImageId" ]),
94
+ cmd = ["singularity" , "pull" , "--force" , "--name" ,
95
+ str (dockerRequirement ["dockerImageId" ]),
101
96
str (dockerRequirement ["dockerPull" ])]
102
97
_logger .info (Text (cmd ))
103
98
if not dry_run :
104
99
check_call (cmd , stdout = sys .stderr )
105
100
found = True
101
+ elif "dockerFile" in dockerRequirement :
102
+ raise WorkflowException (SourceLine (
103
+ dockerRequirement , 'dockerFile' ).makeError (
104
+ "dockerFile is not currently supported when using the "
105
+ "Singularity runtime for Docker containers." ))
106
+ elif "dockerLoad" in dockerRequirement :
107
+ raise WorkflowException (SourceLine (
108
+ dockerRequirement , 'dockerLoad' ).makeError (
109
+ "dockerLoad is not currently supported when using the "
110
+ "Singularity runtime for Docker containers." ))
111
+ elif "dockerImport" in dockerRequirement :
112
+ raise WorkflowException (SourceLine (
113
+ dockerRequirement , 'dockerImport' ).makeError (
114
+ "dockerImport is not currently supported when using the "
115
+ "Singularity runtime for Docker containers." ))
106
116
107
117
return found
108
118
@@ -119,10 +129,6 @@ def get_from_requirements(self,
119
129
hello-world-latest.img).
120
130
"""
121
131
122
- if force_pull :
123
- _logger .warning ("--force-docker-pull currently not supported for "
124
- "singularity" )
125
-
126
132
if r :
127
133
errmsg = None
128
134
try :
@@ -138,7 +144,7 @@ def get_from_requirements(self,
138
144
else :
139
145
return None
140
146
141
- if self .get_image (r , pull_image , dry_run ):
147
+ if self .get_image (r , pull_image , dry_run , force_pull ):
142
148
return os .path .abspath (r ["dockerImageId" ])
143
149
else :
144
150
if req :
0 commit comments