t2-server 0.6.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rvmrc +1 -0
- data/CHANGES.rdoc +48 -0
- data/LICENCE.rdoc +2 -2
- data/README.rdoc +245 -10
- data/Rakefile +108 -0
- data/bin/t2-delete-runs +21 -34
- data/bin/t2-get-output +134 -0
- data/bin/t2-run-workflow +121 -109
- data/bin/t2-server-admin +128 -0
- data/bin/t2-server-info +25 -38
- data/lib/t2-server-cli.rb +116 -0
- data/lib/t2-server.rb +16 -27
- data/lib/t2-server/admin.rb +147 -0
- data/lib/t2-server/connection-parameters.rb +144 -0
- data/lib/t2-server/connection.rb +352 -0
- data/lib/t2-server/credentials.rb +84 -0
- data/lib/t2-server/exceptions.rb +42 -21
- data/lib/t2-server/port.rb +472 -0
- data/lib/t2-server/run.rb +822 -227
- data/lib/t2-server/server.rb +313 -317
- data/lib/t2-server/util.rb +71 -0
- data/lib/t2-server/xml/libxml.rb +87 -0
- data/lib/t2-server/xml/nokogiri.rb +85 -0
- data/lib/t2-server/xml/rexml.rb +85 -0
- data/lib/t2-server/xml/xml.rb +111 -0
- data/lib/t2server.rb +4 -1
- data/t2-server.gemspec +112 -0
- data/test/tc_admin.rb +63 -0
- data/test/{tc_paths.rb → tc_params.rb} +11 -25
- data/test/tc_perms.rb +132 -0
- data/test/tc_run.rb +200 -67
- data/test/tc_secure.rb +191 -0
- data/test/tc_server.rb +25 -23
- data/test/tc_util.rb +74 -0
- data/test/ts_t2server.rb +57 -12
- data/test/workflows/always_fail.t2flow +69 -0
- data/test/workflows/list_and_value.t2flow +12 -0
- data/test/workflows/list_with_errors.t2flow +107 -0
- data/test/workflows/secure/basic-http.t2flow +74 -0
- data/test/workflows/secure/basic-https.t2flow +74 -0
- data/test/workflows/secure/client-https.t2flow +162 -0
- data/test/workflows/secure/digest-http.t2flow +129 -0
- data/test/workflows/secure/digest-https.t2flow +107 -0
- data/test/workflows/secure/heater-pk.pem +20 -0
- data/test/workflows/secure/user-cert.p12 +0 -0
- data/test/workflows/secure/ws-http.t2flow +180 -0
- data/test/workflows/secure/ws-https.t2flow +180 -0
- data/test/workflows/strings.txt +10 -0
- data/test/workflows/xml_xpath.t2flow +136 -136
- data/version.yml +4 -0
- metadata +132 -34
- data/lib/t2-server/xml.rb +0 -86
data/lib/t2-server/run.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2010
|
1
|
+
# Copyright (c) 2010-2012 The University of Manchester, UK.
|
2
2
|
#
|
3
3
|
# All rights reserved.
|
4
4
|
#
|
@@ -14,7 +14,7 @@
|
|
14
14
|
#
|
15
15
|
# * Neither the names of The University of Manchester nor the names of its
|
16
16
|
# contributors may be used to endorse or promote products derived from this
|
17
|
-
# software without specific prior written permission.
|
17
|
+
# software without specific prior written permission.
|
18
18
|
#
|
19
19
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
20
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
@@ -30,9 +30,10 @@
|
|
30
30
|
#
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
|
-
require '
|
34
|
-
require 'libxml'
|
33
|
+
require 'base64'
|
35
34
|
require 'time'
|
35
|
+
require 'rubygems'
|
36
|
+
require 'taverna-baclava'
|
36
37
|
|
37
38
|
module T2Server
|
38
39
|
|
@@ -40,267 +41,378 @@ module T2Server
|
|
40
41
|
# setup and configuration required.
|
41
42
|
#
|
42
43
|
# A run can be in one of three states:
|
43
|
-
# *
|
44
|
+
# * :initialized - The run has been accepted by the server. It may not yet be
|
44
45
|
# ready to run though as its input port may not have been set.
|
45
|
-
# *
|
46
|
-
# *
|
47
|
-
# download.
|
46
|
+
# * :running - The run is being run by the server.
|
47
|
+
# * :finished - The run has finished running and its outputs are available
|
48
|
+
# for download.
|
48
49
|
class Run
|
49
|
-
include
|
50
|
+
include XML::Methods
|
50
51
|
|
51
52
|
private_class_method :new
|
52
53
|
|
53
|
-
# The identifier of this run on the server.
|
54
|
-
|
55
|
-
|
54
|
+
# The identifier of this run on the server.
|
55
|
+
attr_reader :identifier
|
56
|
+
alias :id :identifier
|
57
|
+
|
58
|
+
# The server instance that this run is hosted on.
|
59
|
+
attr_reader :server
|
60
|
+
|
61
|
+
# The owner (username) of this run
|
62
|
+
attr_reader :owner
|
56
63
|
|
57
64
|
# :stopdoc:
|
58
|
-
|
59
|
-
|
60
|
-
:
|
61
|
-
:
|
62
|
-
:
|
65
|
+
XPaths = {
|
66
|
+
# Run XPath queries
|
67
|
+
:run_desc => XML::Methods.xpath_compile("/nsr:runDescription"),
|
68
|
+
:dir => XML::Methods.xpath_compile("//nss:dir"),
|
69
|
+
:file => XML::Methods.xpath_compile("//nss:file"),
|
70
|
+
:expiry => XML::Methods.xpath_compile("//nsr:expiry"),
|
71
|
+
:workflow => XML::Methods.xpath_compile("//nsr:creationWorkflow"),
|
72
|
+
:status => XML::Methods.xpath_compile("//nsr:status"),
|
73
|
+
:createtime => XML::Methods.xpath_compile("//nsr:createTime"),
|
74
|
+
:starttime => XML::Methods.xpath_compile("//nsr:startTime"),
|
75
|
+
:finishtime => XML::Methods.xpath_compile("//nsr:finishTime"),
|
76
|
+
:wdir => XML::Methods.xpath_compile("//nsr:workingDirectory"),
|
77
|
+
:inputs => XML::Methods.xpath_compile("//nsr:inputs"),
|
78
|
+
:output => XML::Methods.xpath_compile("//nsr:output"),
|
79
|
+
:securectx => XML::Methods.xpath_compile("//nsr:securityContext"),
|
80
|
+
:listeners => XML::Methods.xpath_compile("//nsr:listeners"),
|
81
|
+
:baclava => XML::Methods.xpath_compile("//nsr:baclava"),
|
82
|
+
:inputexp => XML::Methods.xpath_compile("//nsr:expected"),
|
83
|
+
|
84
|
+
# Port descriptions XPath queries
|
85
|
+
:port_in => XML::Methods.xpath_compile("//port:input"),
|
86
|
+
:port_out => XML::Methods.xpath_compile("//port:output"),
|
87
|
+
|
88
|
+
# Run security XPath queries
|
89
|
+
:sec_creds => XML::Methods.xpath_compile("//nsr:credentials"),
|
90
|
+
:sec_perms => XML::Methods.xpath_compile("//nsr:permissions"),
|
91
|
+
:sec_trusts => XML::Methods.xpath_compile("//nsr:trusts"),
|
92
|
+
:sec_perm =>
|
93
|
+
XML::Methods.xpath_compile("/nsr:permissionsDescriptor/nsr:permission"),
|
94
|
+
:sec_uname => XML::Methods.xpath_compile("nsr:userName"),
|
95
|
+
:sec_uperm => XML::Methods.xpath_compile("nsr:permission"),
|
96
|
+
:sec_cred => XML::Methods.xpath_compile("/nsr:credential"),
|
97
|
+
:sec_suri => XML::Methods.xpath_compile("nss:serviceURI"),
|
98
|
+
:sec_trust =>
|
99
|
+
XML::Methods.xpath_compile("/nsr:trustedIdentities/nsr:trust")
|
63
100
|
}
|
64
101
|
|
102
|
+
# The name to be used internally for retrieving results via baclava
|
103
|
+
BACLAVA_FILE = "out.xml"
|
104
|
+
|
65
105
|
# New is private but rdoc does not get it right! Hence :stopdoc: section.
|
66
|
-
def initialize(server,
|
106
|
+
def initialize(server, id, credentials = nil)
|
67
107
|
@server = server
|
68
|
-
@
|
108
|
+
@identifier = id
|
69
109
|
@workflow = ""
|
70
110
|
@baclava_in = false
|
71
|
-
@baclava_out =
|
72
|
-
|
73
|
-
@
|
74
|
-
|
111
|
+
@baclava_out = false
|
112
|
+
|
113
|
+
@credentials = credentials
|
114
|
+
|
115
|
+
run_desc = xml_document(@server.get_run_attribute(@identifier, "",
|
116
|
+
"application/xml", @credentials))
|
117
|
+
@owner = xpath_attr(run_desc, XPaths[:run_desc], "owner")
|
118
|
+
@links = get_attributes(run_desc)
|
119
|
+
|
120
|
+
# initialize ports lists to nil as an empty list means no inputs/outputs
|
121
|
+
@input_ports = nil
|
122
|
+
@output_ports = nil
|
75
123
|
end
|
76
124
|
# :startdoc:
|
77
125
|
|
78
126
|
# :call-seq:
|
79
127
|
# Run.create(server, workflow) -> run
|
128
|
+
# Run.create(server, workflow, connection_parameters) -> run
|
129
|
+
# Run.create(server, workflow, user_credentials) -> run
|
130
|
+
# Run.create(server, workflow, ...) {|run| ...}
|
80
131
|
#
|
81
|
-
# Create a new run in the
|
132
|
+
# Create a new run in the :initialized state. The run will be created on
|
82
133
|
# the server with address supplied by _server_. This can either be a
|
83
134
|
# String of the form <tt>http://example.com:8888/blah</tt> or an already
|
84
135
|
# created instance of T2Server::Server. The _workflow_ must also be
|
85
|
-
# supplied as a string in t2flow or scufl format.
|
86
|
-
|
87
|
-
|
88
|
-
|
136
|
+
# supplied as a string in t2flow or scufl format. User credentials and
|
137
|
+
# connection parameters can be supplied if required but are both optional.
|
138
|
+
# If _server_ is an instance of T2Server::Server then
|
139
|
+
# _connection_parameters_ will be ignored.
|
140
|
+
#
|
141
|
+
# This method will _yield_ the newly created Run if a block is given.
|
142
|
+
def Run.create(server, workflow, *rest)
|
143
|
+
credentials = nil
|
144
|
+
id = nil
|
145
|
+
conn_params = nil
|
146
|
+
|
147
|
+
rest.each do |param|
|
148
|
+
case param
|
149
|
+
when String
|
150
|
+
id = param
|
151
|
+
when ConnectionParameters
|
152
|
+
conn_params = param
|
153
|
+
when HttpCredentials
|
154
|
+
credentials = param
|
155
|
+
end
|
89
156
|
end
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
157
|
+
|
158
|
+
if server.class != Server
|
159
|
+
server = Server.new(server, conn_params)
|
160
|
+
end
|
161
|
+
|
162
|
+
if id.nil?
|
163
|
+
id = server.initialize_run(workflow, credentials)
|
94
164
|
end
|
165
|
+
|
166
|
+
run = new(server, id, credentials)
|
167
|
+
yield(run) if block_given?
|
168
|
+
run
|
95
169
|
end
|
96
170
|
|
171
|
+
# :stopdoc:
|
172
|
+
def uuid
|
173
|
+
warn "[DEPRECATION] 'uuid' is deprecated and will be removed in 1.0. " +
|
174
|
+
"Please use Run#id or Run#identifier instead."
|
175
|
+
@identifier
|
176
|
+
end
|
177
|
+
# :startdoc:
|
178
|
+
|
97
179
|
# :call-seq:
|
98
|
-
#
|
180
|
+
# delete
|
99
181
|
#
|
100
182
|
# Delete this run from the server.
|
101
183
|
def delete
|
102
|
-
@server.delete_run
|
184
|
+
@server.delete_run(@identifier, @credentials)
|
103
185
|
end
|
104
186
|
|
105
|
-
# :
|
106
|
-
# run.inputs -> string
|
107
|
-
#
|
108
|
-
# Return the path to the input ports of this run on the server.
|
187
|
+
# :stopdoc:
|
109
188
|
def inputs
|
189
|
+
warn "[DEPRECATION] 'inputs' is deprecated and will be removed in 1.0."
|
110
190
|
@links[:inputs]
|
111
191
|
end
|
112
192
|
|
193
|
+
def set_input(input, value)
|
194
|
+
warn "[DEPRECATION] 'Run#set_input' is deprecated and will be removed " +
|
195
|
+
"in 1.0. Input ports are set directly instead. The most direct " +
|
196
|
+
"replacement for this method is: 'Run#input_port(input).value = value'"
|
197
|
+
|
198
|
+
input_port(input).value = value
|
199
|
+
end
|
200
|
+
|
201
|
+
def set_input_file(input, filename)
|
202
|
+
warn "[DEPRECATION] 'Run#set_input_file' is deprecated and will be " +
|
203
|
+
"removed in 1.0. Input ports are set directly instead. The most " +
|
204
|
+
"direct replacement for this method is: " +
|
205
|
+
"'Run#input_port(input).remote_file = filename'"
|
206
|
+
|
207
|
+
input_port(input).remote_file = filename
|
208
|
+
end
|
209
|
+
# :startdoc:
|
210
|
+
|
113
211
|
# :call-seq:
|
114
|
-
#
|
212
|
+
# input_ports -> Hash
|
115
213
|
#
|
116
|
-
#
|
117
|
-
|
118
|
-
|
119
|
-
def set_input(input, value)
|
120
|
-
state = status
|
121
|
-
raise RunStateError.new(state, STATE[:initialized]) if state != STATE[:initialized]
|
214
|
+
# Return a hash (name, port) of all the input ports this run expects.
|
215
|
+
def input_ports
|
216
|
+
@input_ports = _get_input_port_info if @input_ports.nil?
|
122
217
|
|
123
|
-
@
|
218
|
+
@input_ports
|
124
219
|
end
|
125
220
|
|
126
221
|
# :call-seq:
|
127
|
-
#
|
222
|
+
# input_port(port) -> Port
|
128
223
|
#
|
129
|
-
#
|
130
|
-
|
224
|
+
# Get _port_.
|
225
|
+
def input_port(port)
|
226
|
+
input_ports[port]
|
227
|
+
end
|
228
|
+
|
229
|
+
# :call-seq:
|
230
|
+
# output_ports -> Hash
|
131
231
|
#
|
132
|
-
#
|
133
|
-
|
134
|
-
|
135
|
-
|
232
|
+
# Return a hash (name, port) of all the output ports this run has. Until
|
233
|
+
# the run is finished this method will return _nil_.
|
234
|
+
def output_ports
|
235
|
+
if finished? and @output_ports.nil?
|
236
|
+
@output_ports = _get_output_port_info
|
237
|
+
end
|
136
238
|
|
137
|
-
@
|
239
|
+
@output_ports
|
138
240
|
end
|
139
241
|
|
140
242
|
# :call-seq:
|
141
|
-
#
|
243
|
+
# output_port(port) -> Port
|
142
244
|
#
|
143
|
-
#
|
245
|
+
# Get output port _port_.
|
246
|
+
def output_port(port)
|
247
|
+
output_ports[port] if finished?
|
248
|
+
end
|
249
|
+
|
250
|
+
# :stopdoc:
|
144
251
|
def get_output_ports
|
252
|
+
warn "[DEPRECATION] 'get_output_ports' is deprecated and will be " +
|
253
|
+
"removed in 1.0. Please use 'Run#output_ports' instead."
|
145
254
|
lists, items = _ls_ports("out")
|
146
255
|
items + lists
|
147
256
|
end
|
148
257
|
|
149
|
-
# :call-seq:
|
150
|
-
# run.get_output(output, refs=false) -> string or list
|
151
|
-
#
|
152
|
-
# Return the values of the workflow output port _output_. These are
|
153
|
-
# returned as a list of strings or, if the output port represents a
|
154
|
-
# singleton value, then a string returned. By default this method returns
|
155
|
-
# the actual data from the output port but if _refs_ is set to true then
|
156
|
-
# it will instead return URIs to the actual data in the same list format.
|
157
|
-
# See also Run#get_output_refs.
|
158
258
|
def get_output(output, refs=false)
|
259
|
+
warn "[DEPRECATION] 'get_output' is deprecated and will be removed " +
|
260
|
+
"in 1.0. Please use 'Run#output_port(port).values' instead."
|
159
261
|
_get_output(output, refs)
|
160
262
|
end
|
161
263
|
|
162
|
-
# :call-seq:
|
163
|
-
# run.get_output_refs(output) -> string or list
|
164
|
-
#
|
165
|
-
# Return references (URIs) to the values of the workflow output port
|
166
|
-
# _output_. These are returned as a list of URIs or, if the output port
|
167
|
-
# represents a singleton value, then a single URI is returned. The URIs
|
168
|
-
# are returned as strings.
|
169
264
|
def get_output_refs(output)
|
265
|
+
warn "[DEPRECATION] 'get_output_refs' is deprecated and will be " +
|
266
|
+
"removed in 1.0. Please use 'Run#output_port(port).data' instead."
|
170
267
|
_get_output(output, true)
|
171
268
|
end
|
269
|
+
# :startdoc:
|
172
270
|
|
173
271
|
# :call-seq:
|
174
|
-
#
|
272
|
+
# expiry -> string
|
175
273
|
#
|
176
274
|
# Return the expiry time of this run as an instance of class Time.
|
177
275
|
def expiry
|
178
|
-
Time.parse(@server.get_run_attribute(@
|
276
|
+
Time.parse(@server.get_run_attribute(@identifier, @links[:expiry],
|
277
|
+
"text/plain", @credentials))
|
179
278
|
end
|
180
279
|
|
181
280
|
# :call-seq:
|
182
|
-
#
|
281
|
+
# expiry=(time) -> bool
|
183
282
|
#
|
184
|
-
# Set the expiry time of this run to _time_.
|
185
|
-
#
|
186
|
-
# not specify a date then today's date will be assumed. If a time/date
|
187
|
-
# the past is specified, the expiry time will not be changed.
|
283
|
+
# Set the expiry time of this run to _time_. _time_ should either be a Time
|
284
|
+
# object or something that the Time class can parse. If the value given
|
285
|
+
# does not specify a date then today's date will be assumed. If a time/date
|
286
|
+
# in the past is specified, the expiry time will not be changed.
|
188
287
|
def expiry=(time)
|
288
|
+
unless time.instance_of? Time
|
289
|
+
time = Time.parse(time)
|
290
|
+
end
|
291
|
+
|
189
292
|
# need to massage the xmlschema format slightly as the server cannot
|
190
293
|
# parse timezone offsets with a colon (eg +00:00)
|
191
|
-
date_str =
|
294
|
+
date_str = time.xmlschema(2)
|
192
295
|
date_str = date_str[0..-4] + date_str[-2..-1]
|
193
|
-
@server.set_run_attribute(@
|
296
|
+
@server.set_run_attribute(@identifier, @links[:expiry], date_str,
|
297
|
+
"text/plain", @credentials)
|
194
298
|
end
|
195
299
|
|
196
300
|
# :call-seq:
|
197
|
-
#
|
301
|
+
# workflow -> string
|
198
302
|
#
|
199
303
|
# Get the workflow that this run represents.
|
200
304
|
def workflow
|
201
305
|
if @workflow == ""
|
202
|
-
@workflow = @server.get_run_attribute(@
|
306
|
+
@workflow = @server.get_run_attribute(@identifier, @links[:workflow],
|
307
|
+
"application/xml", @credentials)
|
203
308
|
end
|
204
309
|
@workflow
|
205
310
|
end
|
206
311
|
|
207
312
|
# :call-seq:
|
208
|
-
#
|
313
|
+
# status -> string
|
209
314
|
#
|
210
|
-
# Get the status of this run.
|
315
|
+
# Get the status of this run. Status can be one of :initialized,
|
316
|
+
# :running or :finished.
|
211
317
|
def status
|
212
|
-
@server.get_run_attribute(@
|
318
|
+
text_to_state(@server.get_run_attribute(@identifier, @links[:status],
|
319
|
+
"text/plain", @credentials))
|
213
320
|
end
|
214
321
|
|
215
322
|
# :call-seq:
|
216
|
-
#
|
323
|
+
# start
|
217
324
|
#
|
218
325
|
# Start this run on the server.
|
219
326
|
#
|
220
|
-
# Raises RunStateError if the run is not in the
|
327
|
+
# Raises RunStateError if the run is not in the :initialized state.
|
221
328
|
def start
|
222
329
|
state = status
|
223
|
-
raise RunStateError.new(state,
|
330
|
+
raise RunStateError.new(state, :initialized) if state != :initialized
|
224
331
|
|
225
|
-
|
332
|
+
# set all the inputs
|
333
|
+
_check_and_set_inputs unless baclava_input?
|
334
|
+
|
335
|
+
@server.set_run_attribute(@identifier, @links[:status],
|
336
|
+
state_to_text(:running), "text/plain", @credentials)
|
226
337
|
end
|
227
338
|
|
228
339
|
# :call-seq:
|
229
|
-
#
|
340
|
+
# wait(check_interval = 1)
|
230
341
|
#
|
231
|
-
# Wait (block) for this run to finish.
|
232
|
-
#
|
233
|
-
# * :interval - How often (in seconds) to test for run completion.
|
234
|
-
# Default +1+.
|
235
|
-
# * :progress - Print a dot (.) each interval to show that something is
|
236
|
-
# actually happening. Default +false+.
|
342
|
+
# Wait (block) for this run to finish. How often (in seconds) the run is
|
343
|
+
# tested for completion can be specified with check_interval.
|
237
344
|
#
|
238
|
-
# Raises RunStateError if the run is
|
239
|
-
def wait(params
|
345
|
+
# Raises RunStateError if the run is still in the :initialised state.
|
346
|
+
def wait(*params)
|
240
347
|
state = status
|
241
|
-
raise RunStateError.new(state,
|
348
|
+
raise RunStateError.new(state, :running) if state == :initialized
|
349
|
+
|
350
|
+
interval = 1
|
351
|
+
params.each do |param|
|
352
|
+
case param
|
353
|
+
when Hash
|
354
|
+
warn "[DEPRECATION] 'Run#wait(params={})' is deprecated and will " +
|
355
|
+
"be removed in 1.0. Please use Run#wait(check_interval) instead."
|
356
|
+
interval = param[:interval] || 1
|
357
|
+
when Integer
|
358
|
+
interval = param
|
359
|
+
end
|
360
|
+
end
|
242
361
|
|
243
|
-
interval = params[:interval] || 1
|
244
|
-
progress = params[:progress] || false
|
245
|
-
keepalive = params[:keepalive] || false ### TODO maybe move out of params
|
246
|
-
|
247
362
|
# wait
|
248
363
|
until finished?
|
249
364
|
sleep(interval)
|
250
|
-
if progress
|
251
|
-
print "."
|
252
|
-
STDOUT.flush
|
253
|
-
end
|
254
365
|
end
|
255
|
-
|
256
|
-
# tidy up output if there is any
|
257
|
-
puts if progress
|
258
366
|
end
|
259
367
|
|
260
368
|
# :call-seq:
|
261
|
-
#
|
369
|
+
# exitcode -> integer
|
262
370
|
#
|
263
371
|
# Get the return code of the run. Zero indicates success.
|
264
372
|
def exitcode
|
265
|
-
@server.get_run_attribute(@
|
373
|
+
@server.get_run_attribute(@identifier, @links[:exitcode], "text/plain",
|
374
|
+
@credentials).to_i
|
266
375
|
end
|
267
376
|
|
268
377
|
# :call-seq:
|
269
|
-
#
|
378
|
+
# stdout -> string
|
270
379
|
#
|
271
380
|
# Get anything that the run printed to the standard out stream.
|
272
381
|
def stdout
|
273
|
-
@server.get_run_attribute(@
|
382
|
+
@server.get_run_attribute(@identifier, @links[:stdout], "text/plain",
|
383
|
+
@credentials)
|
274
384
|
end
|
275
385
|
|
276
386
|
# :call-seq:
|
277
|
-
#
|
387
|
+
# stderr -> string
|
278
388
|
#
|
279
389
|
# Get anything that the run printed to the standard error stream.
|
280
390
|
def stderr
|
281
|
-
@server.get_run_attribute(@
|
391
|
+
@server.get_run_attribute(@identifier, @links[:stderr], "text/plain",
|
392
|
+
@credentials)
|
282
393
|
end
|
283
394
|
|
284
395
|
# :call-seq:
|
285
|
-
#
|
396
|
+
# mkdir(dir) -> bool
|
286
397
|
#
|
287
398
|
# Create a directory in the run's working directory on the server. This
|
288
399
|
# could be used to store input data.
|
289
400
|
def mkdir(dir)
|
290
|
-
dir.
|
401
|
+
dir = Util.strip_path_slashes(dir)
|
291
402
|
if dir.include? ?/
|
292
403
|
# if a path is given then separate the leaf from the
|
293
404
|
# end and add the rest of the path to the wdir link
|
294
405
|
leaf = dir.split("/")[-1]
|
295
406
|
path = dir[0...-(leaf.length + 1)]
|
296
|
-
@server.
|
407
|
+
@server.create_dir(@identifier, "#{@links[:wdir]}/#{path}", leaf,
|
408
|
+
@credentials)
|
297
409
|
else
|
298
|
-
@server.
|
410
|
+
@server.create_dir(@identifier, @links[:wdir], dir, @credentials)
|
299
411
|
end
|
300
412
|
end
|
301
413
|
|
302
414
|
# :call-seq:
|
303
|
-
#
|
415
|
+
# upload_file(filename, params={}) -> string
|
304
416
|
#
|
305
417
|
# Upload a file, with name _filename_, to the server. Possible values that
|
306
418
|
# can be passed in via _params_ are:
|
@@ -313,160 +425,578 @@ module T2Server
|
|
313
425
|
location = params[:dir] || ""
|
314
426
|
location = "#{@links[:wdir]}/#{location}"
|
315
427
|
rename = params[:rename] || ""
|
316
|
-
@server.
|
428
|
+
@server.upload_file(@identifier, filename, location, rename,
|
429
|
+
@credentials)
|
317
430
|
end
|
318
431
|
|
319
432
|
# :call-seq:
|
320
|
-
#
|
321
|
-
#
|
322
|
-
# Upload a file, with name _filename_, to the server and set it as the
|
323
|
-
# input data for input port _input_. Possible values that can be passed
|
324
|
-
# in via _params_ are:
|
325
|
-
# * :dir - The directory to upload to. If this is not left blank the
|
326
|
-
# corresponding directory will need to have been created by Run#mkdir.
|
327
|
-
# * :rename - Save the file on the server with a different name.
|
328
|
-
#
|
329
|
-
# The name of the file on the server is returned.
|
433
|
+
# upload_data(data, remote_name, remote_directory = "") -> bool
|
330
434
|
#
|
331
|
-
#
|
435
|
+
# Upload data to the server and store it in <tt>remote_file</tt>. The
|
436
|
+
# remote directory to put this file in can also be specified, but if it is
|
437
|
+
# it must first have been created by a call to Run#mkdir.
|
438
|
+
def upload_data(data, remote_name, remote_directory = "")
|
439
|
+
location = "#{@links[:wdir]}/#{remote_directory}"
|
440
|
+
@server.upload_data(@identifier, data, remote_name, location,
|
441
|
+
@credentials)
|
442
|
+
end
|
443
|
+
|
444
|
+
# :stopdoc:
|
332
445
|
def upload_input_file(input, filename, params={})
|
333
|
-
|
334
|
-
|
446
|
+
warn "[DEPRECATION] 'Run#upload_input_file' is deprecated and will be " +
|
447
|
+
"removed in 1.0. Input ports are set directly instead. The most " +
|
448
|
+
"direct replacement for this method is: " +
|
449
|
+
"'Run#input_port(input).file = filename'"
|
335
450
|
|
336
|
-
file =
|
337
|
-
set_input_file(input, file)
|
451
|
+
input_port(input).file = filename
|
338
452
|
end
|
453
|
+
# :startdoc:
|
339
454
|
|
340
455
|
# :call-seq:
|
341
|
-
#
|
456
|
+
# baclava_input=(filename) -> bool
|
342
457
|
#
|
343
|
-
#
|
344
|
-
def
|
458
|
+
# Use a baclava file for the workflow inputs.
|
459
|
+
def baclava_input=(filename)
|
345
460
|
state = status
|
346
|
-
raise RunStateError.new(state,
|
461
|
+
raise RunStateError.new(state, :initialized) if state != :initialized
|
347
462
|
|
348
|
-
@baclava_in = true
|
349
463
|
rename = upload_file(filename)
|
350
|
-
@server.set_run_attribute(@
|
464
|
+
result = @server.set_run_attribute(@identifier, @links[:baclava], rename,
|
465
|
+
"text/plain", @credentials)
|
466
|
+
|
467
|
+
@baclava_in = true if result
|
468
|
+
|
469
|
+
result
|
351
470
|
end
|
352
471
|
|
472
|
+
# :stopdoc:
|
473
|
+
def upload_baclava_input(filename)
|
474
|
+
warn "[DEPRECATION] 'upload_baclava_input' is deprecated and will be " +
|
475
|
+
"removed in 1.0. Please use 'Run#baclava_input=' instead."
|
476
|
+
self.baclava_input = filename
|
477
|
+
end
|
478
|
+
|
479
|
+
def upload_baclava_file(filename)
|
480
|
+
warn "[DEPRECATION] 'upload_baclava_file' is deprecated and will be " +
|
481
|
+
"removed in 1.0. Please use 'Run#baclava_input=' instead."
|
482
|
+
self.baclava_input = filename
|
483
|
+
end
|
484
|
+
# :startdoc:
|
485
|
+
|
353
486
|
# :call-seq:
|
354
|
-
#
|
487
|
+
# request_baclava_output -> bool
|
355
488
|
#
|
356
|
-
# Set the server to save the outputs of this run in baclava format.
|
357
|
-
#
|
358
|
-
|
359
|
-
|
489
|
+
# Set the server to save the outputs of this run in baclava format. This
|
490
|
+
# must be done before the run is started.
|
491
|
+
def request_baclava_output
|
492
|
+
return if @baclava_out
|
360
493
|
state = status
|
361
|
-
raise RunStateError.new(state,
|
362
|
-
|
363
|
-
@baclava_out =
|
364
|
-
|
494
|
+
raise RunStateError.new(state, :initialized) if state != :initialized
|
495
|
+
|
496
|
+
@baclava_out = @server.set_run_attribute(@identifier, @links[:output],
|
497
|
+
BACLAVA_FILE, "text/plain", @credentials)
|
498
|
+
end
|
499
|
+
|
500
|
+
# :stopdoc:
|
501
|
+
def set_baclava_output(name="")
|
502
|
+
warn "[DEPRECATION] 'set_baclava_output' is deprecated and will be " +
|
503
|
+
"removed in 1.0. Please use 'Run#request_baclava_output' instead."
|
504
|
+
self.request_baclava_output
|
365
505
|
end
|
506
|
+
# :startdoc:
|
366
507
|
|
367
508
|
# :call-seq:
|
368
|
-
#
|
509
|
+
# baclava_input? -> bool
|
510
|
+
#
|
511
|
+
# Have the inputs to this run been set by a baclava document?
|
512
|
+
def baclava_input?
|
513
|
+
@baclava_in
|
514
|
+
end
|
515
|
+
|
516
|
+
# :call-seq:
|
517
|
+
# baclava_output? -> bool
|
518
|
+
#
|
519
|
+
# Has this run been set to return results in baclava format?
|
520
|
+
def baclava_output?
|
521
|
+
@baclava_out
|
522
|
+
end
|
523
|
+
|
524
|
+
# :call-seq:
|
525
|
+
# baclava_output -> string
|
369
526
|
#
|
370
527
|
# Get the outputs of this run in baclava format. This can only be done if
|
371
528
|
# the output has been requested in baclava format by #set_baclava_output
|
372
529
|
# before starting the run.
|
530
|
+
def baclava_output
|
531
|
+
state = status
|
532
|
+
raise RunStateError.new(state, :finished) if state != :finished
|
533
|
+
|
534
|
+
raise AccessForbiddenError.new("baclava output") if !@baclava_out
|
535
|
+
@server.get_run_attribute(@identifier,
|
536
|
+
"#{@links[:wdir]}/#{BACLAVA_FILE}", "*/*", @credentials)
|
537
|
+
end
|
538
|
+
|
539
|
+
# :stopdoc:
|
373
540
|
def get_baclava_output
|
541
|
+
warn "[DEPRECATION] 'get_baclava_output' is deprecated and will be " +
|
542
|
+
"removed in 1.0. Please use 'Run#baclava_output' instead."
|
543
|
+
baclava_output
|
544
|
+
end
|
545
|
+
# :startdoc:
|
546
|
+
|
547
|
+
# :call-seq:
|
548
|
+
# zip_output -> binary blob
|
549
|
+
#
|
550
|
+
# Get the working directory of this run directly from the server in zip
|
551
|
+
# format.
|
552
|
+
def zip_output
|
374
553
|
state = status
|
375
|
-
raise RunStateError.new(state,
|
376
|
-
|
377
|
-
|
378
|
-
|
554
|
+
raise RunStateError.new(state, :finished) if state != :finished
|
555
|
+
|
556
|
+
@server.get_run_attribute(@identifier, "#{@links[:wdir]}/out",
|
557
|
+
"application/zip", @credentials)
|
379
558
|
end
|
380
559
|
|
381
560
|
# :call-seq:
|
382
|
-
#
|
561
|
+
# initialized? -> bool
|
383
562
|
#
|
384
|
-
# Is this run in the
|
563
|
+
# Is this run in the :initialized state?
|
385
564
|
def initialized?
|
386
|
-
status ==
|
565
|
+
status == :initialized
|
387
566
|
end
|
388
567
|
|
389
568
|
# :call-seq:
|
390
|
-
#
|
569
|
+
# running? -> bool
|
391
570
|
#
|
392
|
-
# Is this run in the
|
571
|
+
# Is this run in the :running state?
|
393
572
|
def running?
|
394
|
-
status ==
|
573
|
+
status == :running
|
395
574
|
end
|
396
575
|
|
397
576
|
# :call-seq:
|
398
|
-
#
|
577
|
+
# finished? -> bool
|
399
578
|
#
|
400
|
-
# Is this run in the
|
579
|
+
# Is this run in the :finished state?
|
401
580
|
def finished?
|
402
|
-
status ==
|
581
|
+
status == :finished
|
403
582
|
end
|
404
583
|
|
405
584
|
# :call-seq:
|
406
|
-
#
|
585
|
+
# create_time -> string
|
407
586
|
#
|
408
587
|
# Get the creation time of this run as an instance of class Time.
|
409
588
|
def create_time
|
410
|
-
Time.parse(@server.get_run_attribute(@
|
589
|
+
Time.parse(@server.get_run_attribute(@identifier, @links[:createtime],
|
590
|
+
"text/plain", @credentials))
|
411
591
|
end
|
412
592
|
|
413
593
|
# :call-seq:
|
414
|
-
#
|
594
|
+
# start_time -> string
|
415
595
|
#
|
416
596
|
# Get the start time of this run as an instance of class Time.
|
417
597
|
def start_time
|
418
|
-
Time.parse(@server.get_run_attribute(@
|
598
|
+
Time.parse(@server.get_run_attribute(@identifier, @links[:starttime],
|
599
|
+
"text/plain", @credentials))
|
419
600
|
end
|
420
601
|
|
421
602
|
# :call-seq:
|
422
|
-
#
|
603
|
+
# finish_time -> string
|
423
604
|
#
|
424
605
|
# Get the finish time of this run as an instance of class Time.
|
425
606
|
def finish_time
|
426
|
-
Time.parse(@server.get_run_attribute(@
|
607
|
+
Time.parse(@server.get_run_attribute(@identifier, @links[:finishtime],
|
608
|
+
"text/plain", @credentials))
|
609
|
+
end
|
610
|
+
|
611
|
+
# :call-seq:
|
612
|
+
# owner? -> bool
|
613
|
+
#
|
614
|
+
# Are the credentials being used to access this run those of the owner?
|
615
|
+
# The owner of the run can give other users certain access rights to their
|
616
|
+
# runs but only the owner can change these rights - or even see what they
|
617
|
+
# are. Sometimes it is useful to know if the user accessing the run is
|
618
|
+
# actually the owner of it or not.
|
619
|
+
def owner?
|
620
|
+
@credentials.username == @owner
|
621
|
+
end
|
622
|
+
|
623
|
+
# :call-seq:
|
624
|
+
# grant_permission(username, permission) -> username
|
625
|
+
#
|
626
|
+
# Grant the user the stated permission. A permission can be one of
|
627
|
+
# <tt>:none</tt>, <tt>:read</tt>, <tt>:update</tt> or <tt>:destroy</tt>.
|
628
|
+
# Only the owner of a run may grant permissions on it. +nil+ is returned
|
629
|
+
# if a user other than the owner uses this method.
|
630
|
+
def grant_permission(username, permission)
|
631
|
+
return unless owner?
|
632
|
+
|
633
|
+
value = XML::Fragments::PERM_UPDATE % [username, permission.to_s]
|
634
|
+
@server.create_run_attribute(@identifier, @links[:sec_perms], value,
|
635
|
+
"application/xml", @credentials)
|
636
|
+
end
|
637
|
+
|
638
|
+
# :call-seq:
|
639
|
+
# permissions -> hash
|
640
|
+
#
|
641
|
+
# Return a hash (username => permission) of all the permissions set for
|
642
|
+
# this run. Only the owner of a run may query its permissions. +nil+ is
|
643
|
+
# returned if a user other than the owner uses this method.
|
644
|
+
def permissions
|
645
|
+
return unless owner?
|
646
|
+
|
647
|
+
perms = {}
|
648
|
+
doc = xml_document(@server.get_run_attribute(@identifier,
|
649
|
+
@links[:sec_perms], "application/xml", @credentials))
|
650
|
+
|
651
|
+
xpath_find(doc, XPaths[:sec_perm]).each do |p|
|
652
|
+
user = xml_node_content(xpath_first(p, XPaths[:sec_uname]))
|
653
|
+
perm = xml_node_content(xpath_first(p, XPaths[:sec_uperm])).to_sym
|
654
|
+
perms[user] = perm
|
655
|
+
end
|
656
|
+
|
657
|
+
perms
|
658
|
+
end
|
659
|
+
|
660
|
+
# :call-seq:
|
661
|
+
# permission(username) -> permission
|
662
|
+
#
|
663
|
+
# Return the permission granted to the supplied username, if any. Only the
|
664
|
+
# owner of a run may query its permissions. +nil+ is returned if a user
|
665
|
+
# other than the owner uses this method.
|
666
|
+
def permission(username)
|
667
|
+
return unless owner?
|
668
|
+
|
669
|
+
permissions[username]
|
670
|
+
end
|
671
|
+
|
672
|
+
# :call-seq:
|
673
|
+
# revoke_permission(username) -> bool
|
674
|
+
#
|
675
|
+
# Revoke whatever permissions that have been granted to the user. Only the
|
676
|
+
# owner of a run may revoke permissions on it. +nil+ is returned if a user
|
677
|
+
# other than the owner uses this method.
|
678
|
+
def revoke_permission(username)
|
679
|
+
return unless owner?
|
680
|
+
|
681
|
+
path = "#{@links[:sec_perms]}/#{username}"
|
682
|
+
@server.delete_run_attribute(@identifier, path, @credentials)
|
683
|
+
end
|
684
|
+
|
685
|
+
# :call-seq:
|
686
|
+
# add_password_credential(service_uri, username, password) -> String
|
687
|
+
#
|
688
|
+
# Provide a username and password credential for the secure service at the
|
689
|
+
# specified URI. The id of the credential on the server is returned. Only
|
690
|
+
# the owner of a run may supply credentials for it. +nil+ is returned if a
|
691
|
+
# user other than the owner uses this method.
|
692
|
+
def add_password_credential(uri, username, password)
|
693
|
+
return unless owner?
|
694
|
+
|
695
|
+
# Is this a new credential, or an update?
|
696
|
+
id = credential(uri)
|
697
|
+
|
698
|
+
# basic uri checks
|
699
|
+
uri = _check_cred_uri(uri)
|
700
|
+
|
701
|
+
cred = XML::Fragments::USERPASS_CRED % [uri, username, password]
|
702
|
+
value = XML::Fragments::CREDENTIAL % cred
|
703
|
+
|
704
|
+
if id.nil?
|
705
|
+
@server.create_run_attribute(@identifier, @links[:sec_creds], value,
|
706
|
+
"application/xml", @credentials)
|
707
|
+
else
|
708
|
+
path = "#{@links[:sec_creds]}/#{id}"
|
709
|
+
@server.set_run_attribute(@identifier, path, value, "application/xml",
|
710
|
+
@credentials)
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
# :call-seq:
|
715
|
+
# add_keypair_credential(service_uri, filename, password,
|
716
|
+
# alias = "Imported Certificate", type = :pkcs12) -> String
|
717
|
+
#
|
718
|
+
# Provide a client certificate credential for the secure service at the
|
719
|
+
# specified URI. You will need to provide the password to unlock the
|
720
|
+
# private key. You will also need to provide the 'alias' or 'friendlyName'
|
721
|
+
# of the key you wish to use if it differs from the default. The id of the
|
722
|
+
# credential on the server is returned. Only the owner of a run may supply
|
723
|
+
# credentials for it. +nil+ is returned if a user other than the owner uses
|
724
|
+
# this method.
|
725
|
+
def add_keypair_credential(uri, filename, password,
|
726
|
+
name = "Imported Certificate", type = :pkcs12)
|
727
|
+
return unless owner?
|
728
|
+
|
729
|
+
type = type.to_s.upcase
|
730
|
+
contents = Base64.encode64(IO.read(filename))
|
731
|
+
|
732
|
+
# basic uri checks
|
733
|
+
uri = _check_cred_uri(uri)
|
734
|
+
|
735
|
+
cred = XML::Fragments::KEYPAIR_CRED % [uri, name, contents,
|
736
|
+
type, password]
|
737
|
+
value = XML::Fragments::CREDENTIAL % cred
|
738
|
+
|
739
|
+
@server.create_run_attribute(@identifier, @links[:sec_creds], value,
|
740
|
+
"application/xml", @credentials)
|
427
741
|
end
|
428
742
|
|
743
|
+
# :call-seq:
|
744
|
+
# credentials -> Hash
|
745
|
+
#
|
746
|
+
# Return a hash (service_uri => identifier) of all the credentials provided
|
747
|
+
# for this run. Only the owner of a run may query its credentials. +nil+ is
|
748
|
+
# returned if a user other than the owner uses this method.
|
749
|
+
def credentials
|
750
|
+
return unless owner?
|
751
|
+
|
752
|
+
creds = {}
|
753
|
+
doc = xml_document(@server.get_run_attribute(@identifier,
|
754
|
+
@links[:sec_creds], "application/xml", @credentials))
|
755
|
+
|
756
|
+
xpath_find(doc, XPaths[:sec_cred]).each do |c|
|
757
|
+
uri = xml_node_content(xpath_first(c, XPaths[:sec_suri]))
|
758
|
+
id = xml_node_attribute(c, "href").split('/')[-1]
|
759
|
+
creds[uri] = id
|
760
|
+
end
|
761
|
+
|
762
|
+
creds
|
763
|
+
end
|
764
|
+
|
765
|
+
# :call-seq:
|
766
|
+
# credential(service_uri) -> String
|
767
|
+
#
|
768
|
+
# Return the identifier of the credential set for the supplied service, if
|
769
|
+
# any. Only the owner of a run may query its credentials. +nil+ is
|
770
|
+
# returned if a user other than the owner uses this method.
|
771
|
+
def credential(uri)
|
772
|
+
return unless owner?
|
773
|
+
|
774
|
+
credentials[uri]
|
775
|
+
end
|
776
|
+
|
777
|
+
# :call-seq:
|
778
|
+
# delete_credential(service_uri) -> bool
|
779
|
+
#
|
780
|
+
# Delete the credential that has been provided for the specified service.
|
781
|
+
# Only the owner of a run may delete its credentials. +nil+ is returned if
|
782
|
+
# a user other than the owner uses this method.
|
783
|
+
def delete_credential(uri)
|
784
|
+
return unless owner?
|
785
|
+
|
786
|
+
path = "#{@links[:sec_creds]}/#{credentials[uri]}"
|
787
|
+
@server.delete_run_attribute(@identifier, path, @credentials)
|
788
|
+
end
|
789
|
+
|
790
|
+
# :call-seq:
|
791
|
+
# delete_all_credentials -> bool
|
792
|
+
#
|
793
|
+
# Delete all credentials associated with this workflow run. Only the owner
|
794
|
+
# of a run may delete its credentials. +nil+ is returned if a user other
|
795
|
+
# than the owner uses this method.
|
796
|
+
def delete_all_credentials
|
797
|
+
return unless owner?
|
798
|
+
|
799
|
+
@server.delete_run_attribute(@identifier, @links[:sec_creds],
|
800
|
+
@credentials)
|
801
|
+
end
|
802
|
+
|
803
|
+
# :call-seq:
|
804
|
+
# add_trust(filename, type = :x509) -> String
|
805
|
+
#
|
806
|
+
# Add a trusted identity (server public key) to verify peers when using
|
807
|
+
# https connections to Web Services. The id of the trust on the server is
|
808
|
+
# returned. Only the owner of a run may add a trust. +nil+ is returned if
|
809
|
+
# a user other than the owner uses this method.
|
810
|
+
def add_trust(filename, type = :x509)
|
811
|
+
return unless owner?
|
812
|
+
|
813
|
+
type = type.to_s.upcase
|
814
|
+
|
815
|
+
contents = Base64.encode64(IO.read(filename))
|
816
|
+
|
817
|
+
value = XML::Fragments::TRUST % [contents, type]
|
818
|
+
@server.create_run_attribute(@identifier, @links[:sec_trusts], value,
|
819
|
+
"application/xml", @credentials)
|
820
|
+
end
|
821
|
+
|
822
|
+
# :call-seq:
|
823
|
+
# trusts -> Array
|
824
|
+
#
|
825
|
+
# Return a list of all the ids of trusts that have been registered for this
|
826
|
+
# run. At present there is no way to differentiate between trusts without
|
827
|
+
# noting the id returned when originally uploaded. Only the owner of a run
|
828
|
+
# may query its trusts. +nil+ is returned if a user other than the owner
|
829
|
+
# uses this method.
|
830
|
+
def trusts
|
831
|
+
return unless owner?
|
832
|
+
|
833
|
+
t_ids = []
|
834
|
+
doc = xml_document(@server.get_run_attribute(@identifier,
|
835
|
+
@links[:sec_trusts], "application/xml", @credentials))
|
836
|
+
|
837
|
+
xpath_find(doc, XPaths[:sec_trust]). each do |t|
|
838
|
+
t_ids << xml_node_attribute(t, "href").split('/')[-1]
|
839
|
+
end
|
840
|
+
|
841
|
+
t_ids
|
842
|
+
end
|
843
|
+
|
844
|
+
# :call-seq:
|
845
|
+
# delete_trust(id) -> bool
|
846
|
+
#
|
847
|
+
# Delete the trust with the provided id. Only the owner of a run may
|
848
|
+
# delete its trusts. +nil+ is returned if a user other than the owner uses
|
849
|
+
# this method.
|
850
|
+
def delete_trust(id)
|
851
|
+
return unless owner?
|
852
|
+
|
853
|
+
path = "#{@links[:sec_trusts]}/#{id}"
|
854
|
+
@server.delete_run_attribute(@identifier, path, @credentials)
|
855
|
+
end
|
856
|
+
|
857
|
+
# :call-seq:
|
858
|
+
# delete_all_trusts -> bool
|
859
|
+
#
|
860
|
+
# Delete all trusted identities associated with this workflow run. Only
|
861
|
+
# the owner of a run may delete its trusts. +nil+ is returned if a user
|
862
|
+
# other than the owner uses this method.
|
863
|
+
def delete_all_trusts
|
864
|
+
return unless owner?
|
865
|
+
|
866
|
+
@server.delete_run_attribute(@identifier, @links[:sec_trusts],
|
867
|
+
@credentials)
|
868
|
+
end
|
869
|
+
|
870
|
+
# :stopdoc:
|
871
|
+
# Outputs are represented as a directory structure with the eventual list
|
872
|
+
# items (leaves) as files. This method (not part of the public API)
|
873
|
+
# downloads a file from the run's working directory.
|
874
|
+
def download_output_data(path, range = nil)
|
875
|
+
@server.download_run_file(@identifier, "#{@links[:wdir]}/out/#{path}",
|
876
|
+
range, @credentials)
|
877
|
+
end
|
878
|
+
# :startdoc:
|
879
|
+
|
429
880
|
private
|
430
881
|
|
882
|
+
# Check each input to see if it requires a list input and call the
|
883
|
+
# requisite upload method for the entire set of inputs.
|
884
|
+
def _check_and_set_inputs
|
885
|
+
lists = false
|
886
|
+
input_ports.each_value do |port|
|
887
|
+
if port.depth > 0
|
888
|
+
lists = true
|
889
|
+
break
|
890
|
+
end
|
891
|
+
end
|
892
|
+
|
893
|
+
lists ? _fake_lists : _set_all_inputs
|
894
|
+
end
|
895
|
+
|
896
|
+
# Set all the inputs on the server. The inputs must have been set prior to
|
897
|
+
# this call using the InputPort API.
|
898
|
+
def _set_all_inputs
|
899
|
+
input_ports.each_value do |port|
|
900
|
+
next unless port.set?
|
901
|
+
|
902
|
+
if port.file?
|
903
|
+
# If we're using a local file upload it first then set the port to
|
904
|
+
# use a remote file.
|
905
|
+
unless port.remote_file?
|
906
|
+
file = upload_file(port.file)
|
907
|
+
port.remote_file = file
|
908
|
+
end
|
909
|
+
|
910
|
+
xml_value = xml_text_node(port.file)
|
911
|
+
path = "#{@links[:inputs]}/input/#{port.name}"
|
912
|
+
@server.set_run_attribute(self, path,
|
913
|
+
XML::Fragments::RUNINPUTFILE % xml_value, "application/xml",
|
914
|
+
@credentials)
|
915
|
+
else
|
916
|
+
xml_value = xml_text_node(port.value)
|
917
|
+
path = "#{@links[:inputs]}/input/#{port.name}"
|
918
|
+
@server.set_run_attribute(self, path,
|
919
|
+
XML::Fragments::RUNINPUTVALUE % xml_value, "application/xml",
|
920
|
+
@credentials)
|
921
|
+
end
|
922
|
+
end
|
923
|
+
end
|
924
|
+
|
925
|
+
# Fake being able to handle lists as inputs by converting everything into
|
926
|
+
# one big baclava document and uploading that. This has to be done for all
|
927
|
+
# inputs or none at all. The inputs must have been set prior to this call
|
928
|
+
# using the InputPort API.
|
929
|
+
def _fake_lists
|
930
|
+
data_map = {}
|
931
|
+
|
932
|
+
input_ports.each_value do |port|
|
933
|
+
next unless port.set?
|
934
|
+
|
935
|
+
if port.file?
|
936
|
+
unless port.remote_file?
|
937
|
+
file = File.read(port.file)
|
938
|
+
data_map[port.name] = Taverna::Baclava::Node.new(file)
|
939
|
+
end
|
940
|
+
else
|
941
|
+
data_map[port.name] = Taverna::Baclava::Node.new(port.value)
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
945
|
+
# Create and upload the baclava data.
|
946
|
+
baclava = Taverna::Baclava::Writer.write(data_map)
|
947
|
+
upload_data(baclava, "in.baclava")
|
948
|
+
@server.set_run_attribute(@identifier, @links[:baclava], "in.baclava",
|
949
|
+
"text/plain", @credentials)
|
950
|
+
end
|
951
|
+
|
952
|
+
# Check that the uri passed in is suitable for credential use:
|
953
|
+
# * rserve uris must not have a path.
|
954
|
+
# * http(s) uris must have at least "/" as their path.
|
955
|
+
def _check_cred_uri(uri)
|
956
|
+
u = URI(uri)
|
957
|
+
|
958
|
+
case u.scheme
|
959
|
+
when "rserve"
|
960
|
+
u.path = ""
|
961
|
+
when /https?/
|
962
|
+
u.path = "/" if u.path == ""
|
963
|
+
end
|
964
|
+
|
965
|
+
u.to_s
|
966
|
+
end
|
967
|
+
|
431
968
|
# List a directory in the run's workspace on the server. If dir is left
|
432
969
|
# blank then / is listed. As there is no concept of changing into a
|
433
970
|
# directory (cd) in Taverna Server then all paths passed into _ls_ports
|
434
971
|
# should be full paths starting at "root". The contents of a directory are
|
435
972
|
# returned as a list of two lists, "lists" and "values" respectively.
|
436
973
|
def _ls_ports(dir="", top=true)
|
437
|
-
dir.
|
438
|
-
dir_list = @server.get_run_attribute(@
|
974
|
+
dir = Util.strip_path_slashes(dir)
|
975
|
+
dir_list = @server.get_run_attribute(@identifier,
|
976
|
+
"#{@links[:wdir]}/#{dir}", "*/*", @credentials)
|
439
977
|
|
440
978
|
# compile a list of directory entries stripping the
|
441
979
|
# directory name from the front of each filename
|
442
980
|
lists = []
|
443
981
|
values = []
|
444
982
|
|
445
|
-
|
446
|
-
doc = XML::Document.string(dir_list)
|
983
|
+
doc = xml_document(dir_list)
|
447
984
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
end
|
985
|
+
xpath_find(doc, XPaths[:dir]).each do |e|
|
986
|
+
if top
|
987
|
+
lists << xml_node_content(e).split('/')[-1]
|
988
|
+
else
|
989
|
+
index = (xml_node_attribute(e, 'name').to_i - 1)
|
990
|
+
lists[index] = xml_node_content(e).split('/')[-1]
|
455
991
|
end
|
992
|
+
end
|
456
993
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
end
|
464
|
-
end
|
465
|
-
rescue XML::Error => xmle
|
466
|
-
# We expect to get a DOCUMENT_EMPTY error in some cases. All others
|
467
|
-
# should be re-raised.
|
468
|
-
if xmle.code != XML::Error::DOCUMENT_EMPTY
|
469
|
-
raise xmle
|
994
|
+
xpath_find(doc, XPaths[:file]).each do |e|
|
995
|
+
if top
|
996
|
+
values << xml_node_content(e).split('/')[-1]
|
997
|
+
else
|
998
|
+
index = (xml_node_attribute(e, 'name').to_i - 1)
|
999
|
+
values[index] = xml_node_content(e).split('/')[-1]
|
470
1000
|
end
|
471
1001
|
end
|
472
1002
|
|
@@ -474,7 +1004,7 @@ module T2Server
|
|
474
1004
|
end
|
475
1005
|
|
476
1006
|
def _get_output(output, refs=false, top=true)
|
477
|
-
output.
|
1007
|
+
output = Util.strip_path_slashes(output)
|
478
1008
|
|
479
1009
|
# if at the top level we need to check if the port represents a list
|
480
1010
|
# or a singleton value
|
@@ -482,9 +1012,12 @@ module T2Server
|
|
482
1012
|
lists, items = _ls_ports("out")
|
483
1013
|
if items.include? output
|
484
1014
|
if refs
|
485
|
-
return "#{@server.uri}/rest/runs/#{@
|
1015
|
+
return "#{@server.uri}/rest/runs/#{@identifier}/" +
|
1016
|
+
"#{@links[:wdir]}/out/#{output}"
|
486
1017
|
else
|
487
|
-
return @server.get_run_attribute(@
|
1018
|
+
return @server.get_run_attribute(@identifier,
|
1019
|
+
"#{@links[:wdir]}/out/#{output}", "application/octet-stream",
|
1020
|
+
@credentials)
|
488
1021
|
end
|
489
1022
|
end
|
490
1023
|
end
|
@@ -496,55 +1029,117 @@ module T2Server
|
|
496
1029
|
result = []
|
497
1030
|
|
498
1031
|
# for each list recurse into it and add the items to the result
|
499
|
-
lists.each
|
1032
|
+
lists.each do |list|
|
1033
|
+
result << _get_output("#{output}/#{list}", refs, false)
|
1034
|
+
end
|
500
1035
|
|
501
1036
|
# for each item, add it to the output list
|
502
1037
|
items.each do |item|
|
503
1038
|
if refs
|
504
|
-
result << "#{@server.uri}/rest/runs/#{@
|
1039
|
+
result << "#{@server.uri}/rest/runs/#{@identifier}/" +
|
1040
|
+
"#{@links[:wdir]}/out/#{output}/#{item}"
|
505
1041
|
else
|
506
|
-
result << @server.get_run_attribute(@
|
1042
|
+
result << @server.get_run_attribute(@identifier,
|
1043
|
+
"#{@links[:wdir]}/out/#{output}/#{item}",
|
1044
|
+
"application/octet-stream", @credentials)
|
507
1045
|
end
|
508
1046
|
end
|
509
1047
|
|
510
1048
|
result
|
511
1049
|
end
|
512
1050
|
|
513
|
-
def
|
1051
|
+
def _get_input_port_info
|
1052
|
+
ports = {}
|
1053
|
+
port_desc = @server.get_run_attribute(@identifier, @links[:inputexp],
|
1054
|
+
"application/xml", @credentials)
|
1055
|
+
|
1056
|
+
doc = xml_document(port_desc)
|
1057
|
+
|
1058
|
+
xpath_find(doc, XPaths[:port_in]).each do |inp|
|
1059
|
+
port = InputPort.new(self, inp)
|
1060
|
+
ports[port.name] = port
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
ports
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def _get_output_port_info
|
1067
|
+
ports = {}
|
1068
|
+
port_desc = @server.get_run_attribute(@identifier, @links[:output],
|
1069
|
+
"application/xml", @credentials)
|
1070
|
+
|
1071
|
+
doc = xml_document(port_desc)
|
1072
|
+
|
1073
|
+
xpath_find(doc, XPaths[:port_out]).each do |out|
|
1074
|
+
port = OutputPort.new(self, out)
|
1075
|
+
ports[port.name] = port
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
ports
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
def get_attributes(doc)
|
514
1082
|
# first parse out the basic stuff
|
515
|
-
links =
|
516
|
-
|
1083
|
+
links = {}
|
1084
|
+
|
1085
|
+
[:expiry, :workflow, :status, :createtime, :starttime, :finishtime,
|
1086
|
+
:wdir, :inputs, :output, :securectx, :listeners].each do |key|
|
1087
|
+
links[key] = xpath_attr(doc, XPaths[key], "href").split('/')[-1]
|
1088
|
+
end
|
1089
|
+
|
517
1090
|
# get inputs
|
518
|
-
inputs = @server.get_run_attribute(@
|
519
|
-
|
520
|
-
|
521
|
-
|
1091
|
+
inputs = @server.get_run_attribute(@identifier, links[:inputs],
|
1092
|
+
"application/xml",@credentials)
|
1093
|
+
doc = xml_document(inputs)
|
1094
|
+
|
1095
|
+
links[:baclava] = "#{links[:inputs]}/" +
|
1096
|
+
xpath_attr(doc, XPaths[:baclava], "href").split('/')[-1]
|
1097
|
+
links[:inputexp] = "#{links[:inputs]}/" +
|
1098
|
+
xpath_attr(doc, XPaths[:inputexp], "href").split('/')[-1]
|
522
1099
|
|
523
1100
|
# set io properties
|
524
1101
|
links[:io] = "#{links[:listeners]}/io"
|
525
1102
|
links[:stdout] = "#{links[:io]}/properties/stdout"
|
526
1103
|
links[:stderr] = "#{links[:io]}/properties/stderr"
|
527
1104
|
links[:exitcode] = "#{links[:io]}/properties/exitcode"
|
528
|
-
|
1105
|
+
|
1106
|
+
# security properties - only available to the owner of a run
|
1107
|
+
if owner?
|
1108
|
+
securectx = @server.get_run_attribute(@identifier, links[:securectx],
|
1109
|
+
"application/xml", @credentials)
|
1110
|
+
doc = xml_document(securectx)
|
1111
|
+
|
1112
|
+
[:sec_creds, :sec_perms, :sec_trusts].each do |key|
|
1113
|
+
links[key] = "#{links[:securectx]}/" + xpath_attr(doc, XPaths[key],
|
1114
|
+
"href").split('/')[-1]
|
1115
|
+
end
|
1116
|
+
end
|
1117
|
+
|
529
1118
|
links
|
530
1119
|
end
|
531
1120
|
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
1121
|
+
# :stopdoc:
|
1122
|
+
STATE2TEXT = {
|
1123
|
+
:initialized => "Initialized",
|
1124
|
+
:running => "Operating",
|
1125
|
+
:finished => "Finished",
|
1126
|
+
:stopped => "Stopped"
|
1127
|
+
}
|
1128
|
+
|
1129
|
+
TEXT2STATE = {
|
1130
|
+
"Initialized" => :initialized,
|
1131
|
+
"Operating" => :running,
|
1132
|
+
"Finished" => :finished,
|
1133
|
+
"Stopped" => :stopped
|
1134
|
+
}
|
1135
|
+
# :startdoc:
|
1136
|
+
|
1137
|
+
def state_to_text(state)
|
1138
|
+
STATE2TEXT[state.to_sym]
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
def text_to_state(text)
|
1142
|
+
TEXT2STATE[text]
|
548
1143
|
end
|
549
1144
|
end
|
550
1145
|
end
|