@@ -19,11 +19,13 @@ class MissingAuthorization(Exception):
19
19
pass
20
20
21
21
22
- def get_api ():
23
- if not connexion .request .headers .get ('Authorization' ):
24
- raise MissingAuthorization ()
25
- authtoken = connexion .request .headers ['Authorization' ]
26
- if authtoken .startswith ("Bearer " ) or authtoken .startswith ("OAuth2 " ):
22
+ def get_api (authtoken = None ):
23
+ if authtoken is None :
24
+ if not connexion .request .headers .get ('Authorization' ):
25
+ raise MissingAuthorization ()
26
+ authtoken = connexion .request .headers ['Authorization' ]
27
+ if not authtoken .startswith ("Bearer " ) or authtoken .startswith ("OAuth2 " ):
28
+ raise ValueError ("Authorization token must start with 'Bearer '" )
27
29
authtoken = authtoken [7 :]
28
30
return arvados .api_from_config (version = "v1" , apiconfig = {
29
31
"ARVADOS_API_HOST" : os .environ ["ARVADOS_API_HOST" ],
@@ -55,6 +57,10 @@ def catch_exceptions_wrapper(self, *args, **kwargs):
55
57
return {"msg" : str (e ), "status_code" : 500 }, 500
56
58
except MissingAuthorization :
57
59
return {"msg" : "'Authorization' header is missing or empty, expecting Arvados API token" , "status_code" : 401 }, 401
60
+ except ValueError as e :
61
+ return {"msg" : str (e ), "status_code" : 400 }, 400
62
+ except Exception as e :
63
+ return {"msg" : str (e ), "status_code" : 500 }, 500
58
64
59
65
return catch_exceptions_wrapper
60
66
@@ -66,7 +72,7 @@ def GetServiceInfo(self):
66
72
"workflow_type_versions" : {
67
73
"CWL" : {"workflow_type_version" : ["v1.0" ]}
68
74
},
69
- "supported_wes_versions" : ["0.2.1 " ],
75
+ "supported_wes_versions" : ["0.3.0 " ],
70
76
"supported_filesystem_protocols" : ["http" , "https" , "keep" ],
71
77
"workflow_engine_versions" : {
72
78
"arvados-cwl-runner" : stderr
@@ -108,6 +114,11 @@ def ListRuns(self, page_size=None, page_token=None, state_search=None):
108
114
"next_page_token" : workflow_list [- 1 ]["run_id" ] if workflow_list else ""
109
115
}
110
116
117
+ def log_for_run (self , run_id , message , authtoken = None ):
118
+ get_api (authtoken ).logs ().create (body = {"log" : {"object_uuid" : run_id ,
119
+ "event_type" : "stderr" ,
120
+ "properties" : {"text" : message + "\n " }}}).execute ()
121
+
111
122
def invoke_cwl_runner (self , cr_uuid , workflow_url , workflow_params ,
112
123
env , project_uuid ,
113
124
tempdir ):
@@ -118,9 +129,18 @@ def invoke_cwl_runner(self, cr_uuid, workflow_url, workflow_params,
118
129
})
119
130
120
131
try :
121
- with tempfile .NamedTemporaryFile () as inputtemp :
132
+ with tempfile .NamedTemporaryFile (dir = tempdir , suffix = ".json" ) as inputtemp :
122
133
json .dump (workflow_params , inputtemp )
123
134
inputtemp .flush ()
135
+
136
+ msg = ""
137
+ for dirpath , dirs , files in os .walk (tempdir ):
138
+ for f in files :
139
+ msg += " " + dirpath + "/" + f + "\n "
140
+
141
+ self .log_for_run (cr_uuid , "Contents of %s:\n %s" % (tempdir , msg ),
142
+ env ['ARVADOS_API_TOKEN' ])
143
+
124
144
# TODO: run submission process in a container to prevent
125
145
# a-c-r submission processes from seeing each other.
126
146
@@ -133,6 +153,8 @@ def invoke_cwl_runner(self, cr_uuid, workflow_url, workflow_params,
133
153
cmd .append (workflow_url )
134
154
cmd .append (inputtemp .name )
135
155
156
+ self .log_for_run (cr_uuid , "Executing %s" % cmd , env ['ARVADOS_API_TOKEN' ])
157
+
136
158
proc = subprocess .Popen (cmd , env = env ,
137
159
cwd = tempdir ,
138
160
stdout = subprocess .PIPE ,
@@ -141,9 +163,8 @@ def invoke_cwl_runner(self, cr_uuid, workflow_url, workflow_params,
141
163
if proc .returncode != 0 :
142
164
api .container_requests ().update (uuid = cr_uuid , body = {"priority" : 0 }).execute ()
143
165
144
- api .logs ().create (body = {"log" : {"object_uuid" : cr_uuid ,
145
- "event_type" : "stderr" ,
146
- "properties" : {"text" : stderrdata }}}).execute ()
166
+ self .log_for_run (cr_uuid , stderrdata , env ['ARVADOS_API_TOKEN' ])
167
+
147
168
if tempdir :
148
169
shutil .rmtree (tempdir )
149
170
@@ -153,8 +174,6 @@ def invoke_cwl_runner(self, cr_uuid, workflow_url, workflow_params,
153
174
154
175
@catch_exceptions
155
176
def RunWorkflow (self , ** args ):
156
- tempdir , body = self .collect_attachments ()
157
-
158
177
if not connexion .request .headers .get ('Authorization' ):
159
178
raise MissingAuthorization ()
160
179
@@ -178,17 +197,25 @@ def RunWorkflow(self, **args):
178
197
"output_path" : "n/a" ,
179
198
"priority" : 500 }}).execute ()
180
199
181
- workflow_url = body .get ("workflow_url" )
200
+ try :
201
+ tempdir , body = self .collect_attachments (cr ["uuid" ])
202
+
203
+ workflow_url = body .get ("workflow_url" )
182
204
183
- project_uuid = body .get ("workflow_engine_parameters" , {}).get ("project_uuid" )
205
+ project_uuid = body .get ("workflow_engine_parameters" , {}).get ("project_uuid" )
184
206
185
- threading .Thread (target = self .invoke_cwl_runner , args = (cr ["uuid" ],
186
- workflow_url ,
187
- body ["workflow_params" ],
188
- env ,
189
- project_uuid ,
190
- tempdir )).start ()
207
+ threading .Thread (target = self .invoke_cwl_runner , args = (cr ["uuid" ],
208
+ workflow_url ,
209
+ body ["workflow_params" ],
210
+ env ,
211
+ project_uuid ,
212
+ tempdir )).start ()
191
213
214
+ except Exception as e :
215
+ self .log_for_run (cr ["uuid" ], str (e ))
216
+ cr = api .container_requests ().update (uuid = cr ["uuid" ],
217
+ body = {"container_request" :
218
+ {"priority" : 0 }}).execute ()
192
219
return {"run_id" : cr ["uuid" ]}
193
220
194
221
@catch_exceptions
@@ -203,7 +230,11 @@ def GetRunLog(self, run_id):
203
230
containers_map = {c ["uuid" ]: c for c in tasks }
204
231
containers_map [container ["uuid" ]] = container
205
232
else :
206
- container = {"state" : "Queued" , "exit_code" : None , "log" : None }
233
+ container = {
234
+ "state" : "Queued" if request ["priority" ] > 0 else "Cancelled" ,
235
+ "exit_code" : None ,
236
+ "log" : None
237
+ }
207
238
tasks = []
208
239
containers_map = {}
209
240
task_reqs = []
@@ -256,7 +287,7 @@ def log_object(cr):
256
287
"workflow_params" : request ["mounts" ].get ("/var/lib/cwl/cwl.input.json" , {}).get ("content" , {})
257
288
},
258
289
"state" : statemap [container ["state" ]],
259
- "workflow_log " : log_object (request ),
290
+ "run_log " : log_object (request ),
260
291
"task_logs" : [log_object (t ) for t in task_reqs ],
261
292
"outputs" : outputobj
262
293
}
0 commit comments