t2-server 0.9.3 → 1.0.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/CHANGES.rdoc +79 -0
- data/LICENCE.rdoc +1 -1
- data/README.rdoc +94 -26
- data/Rakefile +6 -5
- data/bin/t2-delete-runs +25 -23
- data/bin/t2-get-output +11 -13
- data/bin/t2-run-workflow +91 -29
- data/bin/t2-server-info +29 -12
- data/extras/t2-server-stress +184 -0
- data/lib/t2-server-cli.rb +48 -23
- data/lib/t2-server.rb +2 -1
- data/lib/t2-server/admin.rb +7 -4
- data/lib/t2-server/exceptions.rb +23 -4
- data/lib/t2-server/interaction.rb +241 -0
- data/lib/t2-server/net/connection.rb +90 -60
- data/lib/t2-server/net/credentials.rb +25 -9
- data/lib/t2-server/net/parameters.rb +21 -6
- data/lib/t2-server/port.rb +229 -140
- data/lib/t2-server/run-cache.rb +99 -0
- data/lib/t2-server/run.rb +349 -332
- data/lib/t2-server/server.rb +115 -164
- data/lib/t2-server/util.rb +11 -9
- data/lib/t2-server/xml/libxml.rb +3 -2
- data/lib/t2-server/xml/nokogiri.rb +4 -3
- data/lib/t2-server/xml/rexml.rb +3 -2
- data/lib/t2-server/xml/xml.rb +47 -36
- data/lib/{t2server.rb → t2-server/xml/xpath_cache.rb} +29 -7
- data/t2-server.gemspec +16 -5
- data/test/tc_misc.rb +61 -0
- data/test/tc_perms.rb +17 -1
- data/test/tc_run.rb +164 -34
- data/test/tc_secure.rb +11 -2
- data/test/tc_server.rb +23 -2
- data/test/ts_t2server.rb +10 -8
- data/test/workflows/missing_outputs.t2flow +440 -0
- data/version.yml +3 -3
- metadata +42 -4
@@ -0,0 +1,99 @@
|
|
1
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
2
|
+
#
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
#
|
11
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
# this list of conditions and the following disclaimer in the documentation
|
13
|
+
# and/or other materials provided with the distribution.
|
14
|
+
#
|
15
|
+
# * Neither the names of The University of Manchester nor the names of its
|
16
|
+
# contributors may be used to endorse or promote products derived from this
|
17
|
+
# software without specific prior written permission.
|
18
|
+
#
|
19
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
23
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
#
|
31
|
+
# Author: Robert Haines
|
32
|
+
|
33
|
+
# :stopdoc:
|
34
|
+
module T2Server
|
35
|
+
|
36
|
+
class Server
|
37
|
+
|
38
|
+
# This class is used to cache Run objects in a Server so they don't need to
|
39
|
+
# be created so often. When manipulating this cache the user credentials
|
40
|
+
# should be passed in, or the global user ":all" will be used instead.
|
41
|
+
class RunCache
|
42
|
+
|
43
|
+
def initialize(server)
|
44
|
+
@server = server
|
45
|
+
@cache = {}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add a run, or runs, to the cache.
|
49
|
+
def add_run(runs, credentials = nil)
|
50
|
+
cache = user_cache(credentials)
|
51
|
+
|
52
|
+
[*runs].each do |run|
|
53
|
+
cache[run.id] = run
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# This method adds all new runs (creating instances where required) in
|
58
|
+
# the list provided AND removes any runs no longer in the list.
|
59
|
+
def refresh_all!(run_list, credentials = nil)
|
60
|
+
cache = user_cache(credentials)
|
61
|
+
|
62
|
+
# Add new runs to the user cache.
|
63
|
+
run_list.each_key do |id|
|
64
|
+
if !cache.has_key? id
|
65
|
+
cache[id] = Run.create(@server, "", credentials, run_list[id])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Clear out the expired runs.
|
70
|
+
if cache.length > run_list.length
|
71
|
+
cache.delete_if {|key, _| !run_list.member? key}
|
72
|
+
end
|
73
|
+
|
74
|
+
cache
|
75
|
+
end
|
76
|
+
|
77
|
+
# Delete all runs objects from the cache. This does not delete runs from
|
78
|
+
# the remote server - just their locally cached instances.
|
79
|
+
def clear!(credentials = nil)
|
80
|
+
user_cache(credentials).clear
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get all the specified user's runs.
|
84
|
+
def runs(credentials = nil)
|
85
|
+
user_cache(credentials)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def user_cache(credentials)
|
91
|
+
user = credentials.nil? ? :all : credentials.username
|
92
|
+
@cache[user] ||= {}
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
# :startdoc:
|
data/lib/t2-server/run.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2010-
|
1
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
2
2
|
#
|
3
3
|
# All rights reserved.
|
4
4
|
#
|
@@ -59,43 +59,46 @@ module T2Server
|
|
59
59
|
attr_reader :server
|
60
60
|
|
61
61
|
# :stopdoc:
|
62
|
-
|
62
|
+
XPATHS = {
|
63
63
|
# Run XPath queries
|
64
|
-
:run_desc =>
|
65
|
-
:dir =>
|
66
|
-
:file =>
|
67
|
-
:expiry =>
|
68
|
-
:workflow =>
|
69
|
-
:status =>
|
70
|
-
:createtime =>
|
71
|
-
:starttime =>
|
72
|
-
:finishtime =>
|
73
|
-
:wdir =>
|
74
|
-
:inputs =>
|
75
|
-
:output =>
|
76
|
-
:securectx =>
|
77
|
-
:listeners =>
|
78
|
-
:baclava =>
|
79
|
-
:inputexp =>
|
64
|
+
:run_desc => "/nsr:runDescription",
|
65
|
+
:dir => "//nss:dir",
|
66
|
+
:file => "//nss:file",
|
67
|
+
:expiry => "//nsr:expiry",
|
68
|
+
:workflow => "//nsr:creationWorkflow",
|
69
|
+
:status => "//nsr:status",
|
70
|
+
:createtime => "//nsr:createTime",
|
71
|
+
:starttime => "//nsr:startTime",
|
72
|
+
:finishtime => "//nsr:finishTime",
|
73
|
+
:wdir => "//nsr:workingDirectory",
|
74
|
+
:inputs => "//nsr:inputs",
|
75
|
+
:output => "//nsr:output",
|
76
|
+
:securectx => "//nsr:securityContext",
|
77
|
+
:listeners => "//nsr:listeners",
|
78
|
+
:baclava => "//nsr:baclava",
|
79
|
+
:inputexp => "//nsr:expected",
|
80
|
+
:name => "//nsr:name",
|
81
|
+
:feed => "//nsr:interaction",
|
80
82
|
|
81
83
|
# Port descriptions XPath queries
|
82
|
-
:port_in =>
|
83
|
-
:port_out =>
|
84
|
+
:port_in => "//port:input",
|
85
|
+
:port_out => "//port:output",
|
84
86
|
|
85
87
|
# Run security XPath queries
|
86
|
-
:sec_creds =>
|
87
|
-
:sec_perms =>
|
88
|
-
:sec_trusts =>
|
89
|
-
:sec_perm =>
|
90
|
-
|
91
|
-
:
|
92
|
-
:
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:sec_trust =>
|
96
|
-
XML::Methods.xpath_compile("/nsr:trustedIdentities/nsr:trust")
|
88
|
+
:sec_creds => "//nsr:credentials",
|
89
|
+
:sec_perms => "//nsr:permissions",
|
90
|
+
:sec_trusts => "//nsr:trusts",
|
91
|
+
:sec_perm => "/nsr:permissionsDescriptor/nsr:permission",
|
92
|
+
:sec_uname => "nsr:userName",
|
93
|
+
:sec_uperm => "nsr:permission",
|
94
|
+
:sec_cred => "/nsr:credential",
|
95
|
+
:sec_suri => "nss:serviceURI",
|
96
|
+
:sec_trust => "/nsr:trustedIdentities/nsr:trust"
|
97
97
|
}
|
98
98
|
|
99
|
+
@@xpaths = XML::XPathCache.instance
|
100
|
+
@@xpaths.register_xpaths XPATHS
|
101
|
+
|
99
102
|
# The name to be used internally for retrieving results via baclava
|
100
103
|
BACLAVA_FILE = "out.xml"
|
101
104
|
|
@@ -110,6 +113,9 @@ module T2Server
|
|
110
113
|
|
111
114
|
@credentials = credentials
|
112
115
|
|
116
|
+
# Has this Run object been deleted from the server?
|
117
|
+
@deleted = false
|
118
|
+
|
113
119
|
# The following three fields hold cached data about the run that is only
|
114
120
|
# downloaded the first time it is requested.
|
115
121
|
@run_doc = nil
|
@@ -119,6 +125,9 @@ module T2Server
|
|
119
125
|
# initialize ports lists to nil as an empty list means no inputs/outputs
|
120
126
|
@input_ports = nil
|
121
127
|
@output_ports = nil
|
128
|
+
|
129
|
+
# The interaction reader to use for this run, if required.
|
130
|
+
@interaction_reader = nil
|
122
131
|
end
|
123
132
|
# :startdoc:
|
124
133
|
|
@@ -131,10 +140,10 @@ module T2Server
|
|
131
140
|
# Create a new run in the :initialized state. The run will be created on
|
132
141
|
# the server with address supplied by _server_. This can either be a
|
133
142
|
# String of the form <tt>http://example.com:8888/blah</tt> or an already
|
134
|
-
# created instance of T2Server::Server. The _workflow_
|
135
|
-
#
|
136
|
-
# connection parameters can be supplied if required but
|
137
|
-
# If _server_ is an instance of T2Server::Server then
|
143
|
+
# created instance of T2Server::Server. The _workflow_ may be supplied
|
144
|
+
# as a string in t2flow format, a filename or a File or IO object. User
|
145
|
+
# credentials and connection parameters can be supplied if required but
|
146
|
+
# are both optional. If _server_ is an instance of T2Server::Server then
|
138
147
|
# _connection_parameters_ will be ignored.
|
139
148
|
#
|
140
149
|
# This method will _yield_ the newly created Run if a block is given.
|
@@ -154,36 +163,59 @@ module T2Server
|
|
154
163
|
end
|
155
164
|
end
|
156
165
|
|
157
|
-
|
158
|
-
|
159
|
-
end
|
166
|
+
# If server is not a Server object, get one.
|
167
|
+
server = Server.new(server, conn_params) if server.class != Server
|
160
168
|
|
161
|
-
|
162
|
-
|
163
|
-
end
|
169
|
+
# If we are not given a URI to a run then we know we need to create one.
|
170
|
+
uri ||= server.initialize_run(workflow, credentials)
|
164
171
|
|
172
|
+
# Create the run object and yield it if necessary.
|
165
173
|
run = new(server, uri, credentials)
|
166
174
|
yield(run) if block_given?
|
167
175
|
run
|
168
176
|
end
|
169
177
|
|
170
|
-
# :stopdoc:
|
171
|
-
def uuid
|
172
|
-
warn "[DEPRECATION] 'uuid' is deprecated and will be removed in 1.0. " +
|
173
|
-
"Please use Run#id or Run#identifier instead."
|
174
|
-
@identifier
|
175
|
-
end
|
176
|
-
# :startdoc:
|
177
|
-
|
178
178
|
# :call-seq:
|
179
|
-
# owner ->
|
179
|
+
# owner -> string
|
180
180
|
#
|
181
181
|
# Get the username of the owner of this run. The owner is the user who
|
182
182
|
# created the run on the server.
|
183
183
|
def owner
|
184
|
-
@owner
|
184
|
+
@owner ||= _get_run_owner
|
185
|
+
end
|
185
186
|
|
186
|
-
|
187
|
+
# :call-seq:
|
188
|
+
# name -> String
|
189
|
+
#
|
190
|
+
# Get the name of this run.
|
191
|
+
#
|
192
|
+
# Initially this name is derived by Taverna Server from the name
|
193
|
+
# annotation in the workflow file and the time at which the run was
|
194
|
+
# initialized. It can be set with the <tt>name=</tt> method.
|
195
|
+
#
|
196
|
+
# For Taverna Server versions prior to version 2.5.0 this is a no-op and
|
197
|
+
# the empty string is returned for consistency.
|
198
|
+
def name
|
199
|
+
return "" if links[:name].nil?
|
200
|
+
@server.read(links[:name], "text/plain", @credentials)
|
201
|
+
end
|
202
|
+
|
203
|
+
# :call-seq:
|
204
|
+
# name = new_name -> bool
|
205
|
+
#
|
206
|
+
# Set the name of this run. +true+ is returned upon success. The maximum
|
207
|
+
# length of names supported by the server is 48 characters. Anything
|
208
|
+
# longer than 48 characters will be truncated before upload.
|
209
|
+
#
|
210
|
+
# Initially this name is derived by Taverna Server from the name
|
211
|
+
# annotation in the workflow file and the time at which the run was
|
212
|
+
# initialized.
|
213
|
+
#
|
214
|
+
# For Taverna Server versions prior to version 2.5.0 this is a no-op but
|
215
|
+
# +true+ is still returned for consistency.
|
216
|
+
def name=(name)
|
217
|
+
return true if links[:name].nil?
|
218
|
+
@server.update(links[:name], name[0...48], "text/plain", @credentials)
|
187
219
|
end
|
188
220
|
|
189
221
|
# :call-seq:
|
@@ -192,44 +224,27 @@ module T2Server
|
|
192
224
|
# Delete this run from the server.
|
193
225
|
def delete
|
194
226
|
@server.delete(@uri, @credentials)
|
227
|
+
@deleted = true
|
195
228
|
end
|
196
229
|
|
197
|
-
# :
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
def set_input(input, value)
|
204
|
-
warn "[DEPRECATION] 'Run#set_input' is deprecated and will be removed " +
|
205
|
-
"in 1.0. Input ports are set directly instead. The most direct " +
|
206
|
-
"replacement for this method is: 'Run#input_port(input).value = value'"
|
207
|
-
|
208
|
-
input_port(input).value = value
|
209
|
-
end
|
210
|
-
|
211
|
-
def set_input_file(input, filename)
|
212
|
-
warn "[DEPRECATION] 'Run#set_input_file' is deprecated and will be " +
|
213
|
-
"removed in 1.0. Input ports are set directly instead. The most " +
|
214
|
-
"direct replacement for this method is: " +
|
215
|
-
"'Run#input_port(input).remote_file = filename'"
|
216
|
-
|
217
|
-
input_port(input).remote_file = filename
|
230
|
+
# :call-seq:
|
231
|
+
# deleted? -> true or false
|
232
|
+
#
|
233
|
+
# Has this run been deleted from the server?
|
234
|
+
def deleted?
|
235
|
+
@deleted
|
218
236
|
end
|
219
|
-
# :startdoc:
|
220
237
|
|
221
238
|
# :call-seq:
|
222
|
-
# input_ports ->
|
239
|
+
# input_ports -> hash
|
223
240
|
#
|
224
241
|
# Return a hash (name, port) of all the input ports this run expects.
|
225
242
|
def input_ports
|
226
|
-
@input_ports
|
227
|
-
|
228
|
-
@input_ports
|
243
|
+
@input_ports ||= _get_input_port_info
|
229
244
|
end
|
230
245
|
|
231
246
|
# :call-seq:
|
232
|
-
# input_port(port) ->
|
247
|
+
# input_port(port) -> port
|
233
248
|
#
|
234
249
|
# Get _port_.
|
235
250
|
def input_port(port)
|
@@ -237,12 +252,12 @@ module T2Server
|
|
237
252
|
end
|
238
253
|
|
239
254
|
# :call-seq:
|
240
|
-
# output_ports ->
|
255
|
+
# output_ports -> hash
|
241
256
|
#
|
242
257
|
# Return a hash (name, port) of all the output ports this run has. Until
|
243
258
|
# the run is finished this method will return _nil_.
|
244
259
|
def output_ports
|
245
|
-
if finished?
|
260
|
+
if finished? && @output_ports.nil?
|
246
261
|
@output_ports = _get_output_port_info
|
247
262
|
end
|
248
263
|
|
@@ -250,34 +265,13 @@ module T2Server
|
|
250
265
|
end
|
251
266
|
|
252
267
|
# :call-seq:
|
253
|
-
# output_port(port) ->
|
268
|
+
# output_port(port) -> port
|
254
269
|
#
|
255
270
|
# Get output port _port_.
|
256
271
|
def output_port(port)
|
257
272
|
output_ports[port] if finished?
|
258
273
|
end
|
259
274
|
|
260
|
-
# :stopdoc:
|
261
|
-
def get_output_ports
|
262
|
-
warn "[DEPRECATION] 'get_output_ports' is deprecated and will be " +
|
263
|
-
"removed in 1.0. Please use 'Run#output_ports' instead."
|
264
|
-
lists, items = _ls_ports("out")
|
265
|
-
items + lists
|
266
|
-
end
|
267
|
-
|
268
|
-
def get_output(output, refs=false)
|
269
|
-
warn "[DEPRECATION] 'get_output' is deprecated and will be removed " +
|
270
|
-
"in 1.0. Please use 'Run#output_port(port).values' instead."
|
271
|
-
_get_output(output, refs)
|
272
|
-
end
|
273
|
-
|
274
|
-
def get_output_refs(output)
|
275
|
-
warn "[DEPRECATION] 'get_output_refs' is deprecated and will be " +
|
276
|
-
"removed in 1.0. Please use 'Run#output_port(port).data' instead."
|
277
|
-
_get_output(output, true)
|
278
|
-
end
|
279
|
-
# :startdoc:
|
280
|
-
|
281
275
|
# :call-seq:
|
282
276
|
# expiry -> string
|
283
277
|
#
|
@@ -287,7 +281,7 @@ module T2Server
|
|
287
281
|
end
|
288
282
|
|
289
283
|
# :call-seq:
|
290
|
-
# expiry=
|
284
|
+
# expiry = time -> true or false
|
291
285
|
#
|
292
286
|
# Set the expiry time of this run to _time_. _time_ should either be a Time
|
293
287
|
# object or something that the Time class can parse. If the value given
|
@@ -323,13 +317,15 @@ module T2Server
|
|
323
317
|
# Get the status of this run. Status can be one of :initialized,
|
324
318
|
# :running or :finished.
|
325
319
|
def status
|
326
|
-
|
320
|
+
return :deleted if @deleted
|
321
|
+
Status.to_sym(@server.read(links[:status], "text/plain", @credentials))
|
327
322
|
end
|
328
323
|
|
329
324
|
# :call-seq:
|
330
|
-
# start
|
325
|
+
# start -> true or false
|
331
326
|
#
|
332
|
-
# Start this run on the server.
|
327
|
+
# Start this run on the server. Returns true if the run was started, false
|
328
|
+
# otherwise.
|
333
329
|
#
|
334
330
|
# Raises RunStateError if the run is not in the :initialized state.
|
335
331
|
def start
|
@@ -339,8 +335,12 @@ module T2Server
|
|
339
335
|
# set all the inputs
|
340
336
|
_check_and_set_inputs unless baclava_input?
|
341
337
|
|
342
|
-
|
343
|
-
@
|
338
|
+
begin
|
339
|
+
@server.update(links[:status], Status.to_text(:running), "text/plain",
|
340
|
+
@credentials)
|
341
|
+
rescue ServerAtCapacityError => sace
|
342
|
+
false
|
343
|
+
end
|
344
344
|
end
|
345
345
|
|
346
346
|
# :call-seq:
|
@@ -349,23 +349,11 @@ module T2Server
|
|
349
349
|
# Wait (block) for this run to finish. How often (in seconds) the run is
|
350
350
|
# tested for completion can be specified with check_interval.
|
351
351
|
#
|
352
|
-
# Raises RunStateError if the run is still in the :
|
353
|
-
def wait(
|
352
|
+
# Raises RunStateError if the run is still in the :initialized state.
|
353
|
+
def wait(interval = 1)
|
354
354
|
state = status
|
355
355
|
raise RunStateError.new(state, :running) if state == :initialized
|
356
356
|
|
357
|
-
interval = 1
|
358
|
-
params.each do |param|
|
359
|
-
case param
|
360
|
-
when Hash
|
361
|
-
warn "[DEPRECATION] 'Run#wait(params={})' is deprecated and will " +
|
362
|
-
"be removed in 1.0. Please use Run#wait(check_interval) instead."
|
363
|
-
interval = param[:interval] || 1
|
364
|
-
when Integer
|
365
|
-
interval = param
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
357
|
# wait
|
370
358
|
until finished?
|
371
359
|
sleep(interval)
|
@@ -373,7 +361,7 @@ module T2Server
|
|
373
361
|
end
|
374
362
|
|
375
363
|
# :call-seq:
|
376
|
-
# exitcode ->
|
364
|
+
# exitcode -> fixnum
|
377
365
|
#
|
378
366
|
# Get the return code of the run. Zero indicates success.
|
379
367
|
def exitcode
|
@@ -397,7 +385,32 @@ module T2Server
|
|
397
385
|
end
|
398
386
|
|
399
387
|
# :call-seq:
|
400
|
-
#
|
388
|
+
# log -> string
|
389
|
+
# log(filename) -> fixnum
|
390
|
+
# log(stream) -> fixnum
|
391
|
+
# log {|chunk| ...}
|
392
|
+
#
|
393
|
+
# Get the internal Taverna Server log from this run.
|
394
|
+
#
|
395
|
+
# Calling this method with no parameters will simply return a text string.
|
396
|
+
# Providing a filename will stream the data directly to that file and
|
397
|
+
# return the number of bytes written. Passing in an object that has a
|
398
|
+
# +write+ method (for example, an instance of File or IO) will stream the
|
399
|
+
# text directly to that object and return the number of bytes that were
|
400
|
+
# streamed. Passing in a block will allow access to the underlying data
|
401
|
+
# stream:
|
402
|
+
# run.log do |chunk|
|
403
|
+
# print chunk
|
404
|
+
# end
|
405
|
+
def log(param = nil, &block)
|
406
|
+
raise ArgumentError,
|
407
|
+
'both a parameter and block given for baclava_output' if param && block
|
408
|
+
|
409
|
+
download_or_stream(param, links[:logfile], "text/plain", &block)
|
410
|
+
end
|
411
|
+
|
412
|
+
# :call-seq:
|
413
|
+
# mkdir(dir) -> true or false
|
401
414
|
#
|
402
415
|
# Create a directory in the run's working directory on the server. This
|
403
416
|
# could be used to store input data.
|
@@ -426,7 +439,7 @@ module T2Server
|
|
426
439
|
end
|
427
440
|
|
428
441
|
# :call-seq:
|
429
|
-
# upload_data(data, remote_name, remote_directory = "") ->
|
442
|
+
# upload_data(data, remote_name, remote_directory = "") -> true or false
|
430
443
|
#
|
431
444
|
# Upload data to the server and store it in <tt>remote_file</tt>. The
|
432
445
|
# remote directory to put this file in can also be specified, but if it is
|
@@ -436,19 +449,8 @@ module T2Server
|
|
436
449
|
@server.upload_data(data, remote_name, location_uri, @credentials)
|
437
450
|
end
|
438
451
|
|
439
|
-
# :stopdoc:
|
440
|
-
def upload_input_file(input, filename, params={})
|
441
|
-
warn "[DEPRECATION] 'Run#upload_input_file' is deprecated and will be " +
|
442
|
-
"removed in 1.0. Input ports are set directly instead. The most " +
|
443
|
-
"direct replacement for this method is: " +
|
444
|
-
"'Run#input_port(input).file = filename'"
|
445
|
-
|
446
|
-
input_port(input).file = filename
|
447
|
-
end
|
448
|
-
# :startdoc:
|
449
|
-
|
450
452
|
# :call-seq:
|
451
|
-
# baclava_input=
|
453
|
+
# baclava_input = filename -> true or false
|
452
454
|
#
|
453
455
|
# Use a baclava file for the workflow inputs.
|
454
456
|
def baclava_input=(filename)
|
@@ -463,22 +465,8 @@ module T2Server
|
|
463
465
|
result
|
464
466
|
end
|
465
467
|
|
466
|
-
# :stopdoc:
|
467
|
-
def upload_baclava_input(filename)
|
468
|
-
warn "[DEPRECATION] 'upload_baclava_input' is deprecated and will be " +
|
469
|
-
"removed in 1.0. Please use 'Run#baclava_input=' instead."
|
470
|
-
self.baclava_input = filename
|
471
|
-
end
|
472
|
-
|
473
|
-
def upload_baclava_file(filename)
|
474
|
-
warn "[DEPRECATION] 'upload_baclava_file' is deprecated and will be " +
|
475
|
-
"removed in 1.0. Please use 'Run#baclava_input=' instead."
|
476
|
-
self.baclava_input = filename
|
477
|
-
end
|
478
|
-
# :startdoc:
|
479
|
-
|
480
468
|
# :call-seq:
|
481
|
-
# request_baclava_output ->
|
469
|
+
# request_baclava_output -> true or false
|
482
470
|
#
|
483
471
|
# Set the server to save the outputs of this run in baclava format. This
|
484
472
|
# must be done before the run is started.
|
@@ -491,16 +479,8 @@ module T2Server
|
|
491
479
|
@credentials)
|
492
480
|
end
|
493
481
|
|
494
|
-
# :stopdoc:
|
495
|
-
def set_baclava_output(name="")
|
496
|
-
warn "[DEPRECATION] 'set_baclava_output' is deprecated and will be " +
|
497
|
-
"removed in 1.0. Please use 'Run#request_baclava_output' instead."
|
498
|
-
self.request_baclava_output
|
499
|
-
end
|
500
|
-
# :startdoc:
|
501
|
-
|
502
482
|
# :call-seq:
|
503
|
-
# baclava_input? ->
|
483
|
+
# baclava_input? -> true or false
|
504
484
|
#
|
505
485
|
# Have the inputs to this run been set by a baclava document?
|
506
486
|
def baclava_input?
|
@@ -508,7 +488,7 @@ module T2Server
|
|
508
488
|
end
|
509
489
|
|
510
490
|
# :call-seq:
|
511
|
-
# baclava_output? ->
|
491
|
+
# baclava_output? -> true or false
|
512
492
|
#
|
513
493
|
# Has this run been set to return results in baclava format?
|
514
494
|
def baclava_output?
|
@@ -517,43 +497,74 @@ module T2Server
|
|
517
497
|
|
518
498
|
# :call-seq:
|
519
499
|
# baclava_output -> string
|
500
|
+
# baclava_output(filename) -> fixnum
|
501
|
+
# baclava_output(stream) -> fixnum
|
502
|
+
# baclava_output {|chunk| ...}
|
520
503
|
#
|
521
504
|
# Get the outputs of this run in baclava format. This can only be done if
|
522
505
|
# the output has been requested in baclava format by #set_baclava_output
|
523
506
|
# before starting the run.
|
524
|
-
|
507
|
+
#
|
508
|
+
# Calling this method with no parameters will simply return a blob of
|
509
|
+
# XML data. Providing a filename will stream the data directly to that
|
510
|
+
# file and return the number of bytes written. Passing in an object that
|
511
|
+
# has a +write+ method (for example, an instance of File or IO) will
|
512
|
+
# stream the XML data directly to that object and return the number of
|
513
|
+
# bytes that were streamed. Passing in a block will allow access to the
|
514
|
+
# underlying data stream:
|
515
|
+
# run.baclava_output do |chunk|
|
516
|
+
# print chunk
|
517
|
+
# end
|
518
|
+
#
|
519
|
+
# Raises RunStateError if the run has not finished running.
|
520
|
+
def baclava_output(param = nil, &block)
|
521
|
+
raise ArgumentError,
|
522
|
+
'both a parameter and block given for baclava_output' if param && block
|
523
|
+
|
525
524
|
state = status
|
526
525
|
raise RunStateError.new(state, :finished) if state != :finished
|
527
526
|
|
528
527
|
raise AccessForbiddenError.new("baclava output") if !@baclava_out
|
529
528
|
|
530
529
|
baclava_uri = Util.append_to_uri_path(links[:wdir], BACLAVA_FILE)
|
531
|
-
|
530
|
+
download_or_stream(param, baclava_uri, "*/*", &block)
|
532
531
|
end
|
533
532
|
|
534
|
-
# :stopdoc:
|
535
|
-
def get_baclava_output
|
536
|
-
warn "[DEPRECATION] 'get_baclava_output' is deprecated and will be " +
|
537
|
-
"removed in 1.0. Please use 'Run#baclava_output' instead."
|
538
|
-
baclava_output
|
539
|
-
end
|
540
|
-
# :startdoc:
|
541
|
-
|
542
533
|
# :call-seq:
|
543
534
|
# zip_output -> binary blob
|
535
|
+
# zip_output(filename) -> fixnum
|
536
|
+
# zip_output(stream) -> fixnum
|
537
|
+
# zip_output {|chunk| ...}
|
544
538
|
#
|
545
539
|
# Get the working directory of this run directly from the server in zip
|
546
540
|
# format.
|
547
|
-
|
541
|
+
#
|
542
|
+
# Calling this method with no parameters will simply return a blob of
|
543
|
+
# zipped data. Providing a filename will stream the data directly to that
|
544
|
+
# file and return the number of bytes written. Passing in an object that
|
545
|
+
# has a +write+ method (for example, an instance of File or IO) will
|
546
|
+
# stream the zip data directly to that object and return the number of
|
547
|
+
# bytes that were streamed. Passing in a block will allow access to the
|
548
|
+
# underlying data stream:
|
549
|
+
# run.zip_output do |chunk|
|
550
|
+
# print chunk
|
551
|
+
# end
|
552
|
+
#
|
553
|
+
# Raises RunStateError if the run has not finished running.
|
554
|
+
def zip_output(param = nil, port = "", &block)
|
555
|
+
raise ArgumentError,
|
556
|
+
"both a parameter and block given for zip_output" if param && block
|
557
|
+
|
548
558
|
state = status
|
549
559
|
raise RunStateError.new(state, :finished) if state != :finished
|
550
560
|
|
551
|
-
|
552
|
-
|
561
|
+
path = port.empty? ? "out" : "out/#{port}"
|
562
|
+
output_uri = Util.append_to_uri_path(links[:wdir], path)
|
563
|
+
download_or_stream(param, output_uri, "application/zip", &block)
|
553
564
|
end
|
554
565
|
|
555
566
|
# :call-seq:
|
556
|
-
# initialized? ->
|
567
|
+
# initialized? -> true or false
|
557
568
|
#
|
558
569
|
# Is this run in the :initialized state?
|
559
570
|
def initialized?
|
@@ -561,7 +572,7 @@ module T2Server
|
|
561
572
|
end
|
562
573
|
|
563
574
|
# :call-seq:
|
564
|
-
# running? ->
|
575
|
+
# running? -> true or false
|
565
576
|
#
|
566
577
|
# Is this run in the :running state?
|
567
578
|
def running?
|
@@ -569,13 +580,28 @@ module T2Server
|
|
569
580
|
end
|
570
581
|
|
571
582
|
# :call-seq:
|
572
|
-
# finished? ->
|
583
|
+
# finished? -> true or false
|
573
584
|
#
|
574
585
|
# Is this run in the :finished state?
|
575
586
|
def finished?
|
576
587
|
status == :finished
|
577
588
|
end
|
578
589
|
|
590
|
+
# :call-seq:
|
591
|
+
# error? -> true or false
|
592
|
+
#
|
593
|
+
# Are there errors in this run's outputs? Returns false if the run is not
|
594
|
+
# finished yet.
|
595
|
+
def error?
|
596
|
+
return false unless finished?
|
597
|
+
|
598
|
+
output_ports.values.each do |output|
|
599
|
+
return true if output.error?
|
600
|
+
end
|
601
|
+
|
602
|
+
false
|
603
|
+
end
|
604
|
+
|
579
605
|
# :call-seq:
|
580
606
|
# create_time -> string
|
581
607
|
#
|
@@ -601,7 +627,7 @@ module T2Server
|
|
601
627
|
end
|
602
628
|
|
603
629
|
# :call-seq:
|
604
|
-
# owner? ->
|
630
|
+
# owner? -> true or false
|
605
631
|
#
|
606
632
|
# Are the credentials being used to access this run those of the owner?
|
607
633
|
# The owner of the run can give other users certain access rights to their
|
@@ -639,9 +665,9 @@ module T2Server
|
|
639
665
|
doc = xml_document(@server.read(links[:sec_perms], "application/xml",
|
640
666
|
@credentials))
|
641
667
|
|
642
|
-
xpath_find(doc,
|
643
|
-
user = xml_node_content(xpath_first(p,
|
644
|
-
perm = xml_node_content(xpath_first(p,
|
668
|
+
xpath_find(doc, @@xpaths[:sec_perm]).each do |p|
|
669
|
+
user = xml_node_content(xpath_first(p, @@xpaths[:sec_uname]))
|
670
|
+
perm = xml_node_content(xpath_first(p, @@xpaths[:sec_uperm])).to_sym
|
645
671
|
perms[user] = perm
|
646
672
|
end
|
647
673
|
|
@@ -657,11 +683,11 @@ module T2Server
|
|
657
683
|
def permission(username)
|
658
684
|
return unless owner?
|
659
685
|
|
660
|
-
permissions[username]
|
686
|
+
permissions[username] || :none
|
661
687
|
end
|
662
688
|
|
663
689
|
# :call-seq:
|
664
|
-
# revoke_permission(username) ->
|
690
|
+
# revoke_permission(username) -> true or false
|
665
691
|
#
|
666
692
|
# Revoke whatever permissions that have been granted to the user. Only the
|
667
693
|
# owner of a run may revoke permissions on it. +nil+ is returned if a user
|
@@ -729,7 +755,7 @@ module T2Server
|
|
729
755
|
end
|
730
756
|
|
731
757
|
# :call-seq:
|
732
|
-
# credentials ->
|
758
|
+
# credentials -> hash
|
733
759
|
#
|
734
760
|
# Return a hash (service_uri => credential_uri) of all the credentials
|
735
761
|
# provided for this run. Only the owner of a run may query its credentials.
|
@@ -741,8 +767,8 @@ module T2Server
|
|
741
767
|
doc = xml_document(@server.read(links[:sec_creds], "application/xml",
|
742
768
|
@credentials))
|
743
769
|
|
744
|
-
xpath_find(doc,
|
745
|
-
uri = URI.parse(xml_node_content(xpath_first(c,
|
770
|
+
xpath_find(doc, @@xpaths[:sec_cred]).each do |c|
|
771
|
+
uri = URI.parse(xml_node_content(xpath_first(c, @@xpaths[:sec_suri])))
|
746
772
|
cred_uri = URI.parse(xml_node_attribute(c, "href"))
|
747
773
|
creds[uri] = cred_uri
|
748
774
|
end
|
@@ -763,7 +789,7 @@ module T2Server
|
|
763
789
|
end
|
764
790
|
|
765
791
|
# :call-seq:
|
766
|
-
# delete_credential(service_uri) ->
|
792
|
+
# delete_credential(service_uri) -> true or false
|
767
793
|
#
|
768
794
|
# Delete the credential that has been provided for the specified service.
|
769
795
|
# Only the owner of a run may delete its credentials. +nil+ is returned if
|
@@ -775,7 +801,7 @@ module T2Server
|
|
775
801
|
end
|
776
802
|
|
777
803
|
# :call-seq:
|
778
|
-
# delete_all_credentials ->
|
804
|
+
# delete_all_credentials -> true or false
|
779
805
|
#
|
780
806
|
# Delete all credentials associated with this workflow run. Only the owner
|
781
807
|
# of a run may delete its credentials. +nil+ is returned if a user other
|
@@ -805,7 +831,7 @@ module T2Server
|
|
805
831
|
end
|
806
832
|
|
807
833
|
# :call-seq:
|
808
|
-
# trusts ->
|
834
|
+
# trusts -> array
|
809
835
|
#
|
810
836
|
# Return a list of all the URIs of trusts that have been registered for
|
811
837
|
# this run. At present there is no way to differentiate between trusts
|
@@ -819,7 +845,7 @@ module T2Server
|
|
819
845
|
doc = xml_document(@server.read(links[:sec_trusts], "application/xml",
|
820
846
|
@credentials))
|
821
847
|
|
822
|
-
xpath_find(doc,
|
848
|
+
xpath_find(doc, @@xpaths[:sec_trust]). each do |t|
|
823
849
|
t_uris << URI.parse(xml_node_attribute(t, "href"))
|
824
850
|
end
|
825
851
|
|
@@ -827,7 +853,7 @@ module T2Server
|
|
827
853
|
end
|
828
854
|
|
829
855
|
# :call-seq:
|
830
|
-
# delete_trust(URI) ->
|
856
|
+
# delete_trust(URI) -> true or false
|
831
857
|
#
|
832
858
|
# Delete the trust with the provided URI. Only the owner of a run may
|
833
859
|
# delete its trusts. +nil+ is returned if a user other than the owner uses
|
@@ -839,7 +865,7 @@ module T2Server
|
|
839
865
|
end
|
840
866
|
|
841
867
|
# :call-seq:
|
842
|
-
# delete_all_trusts ->
|
868
|
+
# delete_all_trusts -> true or false
|
843
869
|
#
|
844
870
|
# Delete all trusted identities associated with this workflow run. Only
|
845
871
|
# the owner of a run may delete its trusts. +nil+ is returned if a user
|
@@ -854,17 +880,76 @@ module T2Server
|
|
854
880
|
# Outputs are represented as a directory structure with the eventual list
|
855
881
|
# items (leaves) as files. This method (not part of the public API)
|
856
882
|
# downloads a file from the run's working directory.
|
857
|
-
def download_output_data(uri, range = nil)
|
858
|
-
@server.read(uri, "application/octet-stream", range, @credentials
|
883
|
+
def download_output_data(uri, range = nil, &block)
|
884
|
+
@server.read(uri, "application/octet-stream", range, @credentials,
|
885
|
+
&block)
|
886
|
+
end
|
887
|
+
|
888
|
+
# Read from the run's notification feed.
|
889
|
+
def read_notification_feed
|
890
|
+
@server.read(links[:feed], "application/atom+xml", @credentials)
|
891
|
+
end
|
892
|
+
|
893
|
+
# Write to the run's notification feed.
|
894
|
+
def write_notification(entry)
|
895
|
+
@server.create(links[:feed], entry, "application/atom+xml", @credentials)
|
896
|
+
end
|
897
|
+
|
898
|
+
# Read a file from the interactions directory for this run on the server.
|
899
|
+
def read_interaction_data(name)
|
900
|
+
uri = Util.append_to_uri_path(links[:feeddir], name)
|
901
|
+
@server.read(uri, "*/*", @credentials)
|
902
|
+
end
|
903
|
+
|
904
|
+
# Write a file to the interactions directory for this run on the server.
|
905
|
+
def write_interaction_data(name, data)
|
906
|
+
uri = Util.append_to_uri_path(links[:feeddir], name)
|
907
|
+
@server.update(uri, data, "*/*", @credentials)
|
908
|
+
end
|
909
|
+
|
910
|
+
# This is a slightly unpleasant hack to help proxy notification
|
911
|
+
# communications through a third party.
|
912
|
+
def notifications_uri
|
913
|
+
links[:feed] || ""
|
914
|
+
end
|
915
|
+
|
916
|
+
# This is a slightly unpleasant hack to help proxy interaction
|
917
|
+
# communications through a third party.
|
918
|
+
def interactions_uri
|
919
|
+
links[:feeddir] || ""
|
859
920
|
end
|
860
921
|
# :startdoc:
|
861
922
|
|
923
|
+
# :call-seq:
|
924
|
+
# notifications(type = :new_requests) -> array
|
925
|
+
#
|
926
|
+
# Poll the server for notifications and return them in a list. Returns the
|
927
|
+
# empty list if there are none, or if the server does not support the
|
928
|
+
# Interaction Service.
|
929
|
+
#
|
930
|
+
# The +type+ parameter is used to select which types of notifications are
|
931
|
+
# returned as follows:
|
932
|
+
# * <tt>:requests</tt> - Interaction requests.
|
933
|
+
# * <tt>:replies</tt> - Interaction replies.
|
934
|
+
# * <tt>:new_requests</tt> - Interaction requests that are new since the
|
935
|
+
# last time they were polled (default).
|
936
|
+
# * <tt>:all</tt> - All interaction requests and replies.
|
937
|
+
def notifications(type = :new_requests)
|
938
|
+
return [] if links[:feed].nil?
|
939
|
+
|
940
|
+
@interaction_reader ||= Interaction::Feed.new(self)
|
941
|
+
|
942
|
+
if type == :new_requests
|
943
|
+
@interaction_reader.new_requests
|
944
|
+
else
|
945
|
+
@interaction_reader.notifications(type)
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
862
949
|
private
|
863
950
|
|
864
951
|
def links
|
865
|
-
@links
|
866
|
-
|
867
|
-
@links
|
952
|
+
@links ||= _get_run_links
|
868
953
|
end
|
869
954
|
|
870
955
|
# Check each input to see if it requires a list input and call the
|
@@ -887,24 +972,18 @@ module T2Server
|
|
887
972
|
input_ports.each_value do |port|
|
888
973
|
next unless port.set?
|
889
974
|
|
975
|
+
uri = Util.append_to_uri_path(links[:inputs], "input/#{port.name}")
|
890
976
|
if port.file?
|
891
977
|
# If we're using a local file upload it first then set the port to
|
892
978
|
# use a remote file.
|
893
|
-
unless port.remote_file?
|
894
|
-
file = upload_file(port.file)
|
895
|
-
port.remote_file = file
|
896
|
-
end
|
979
|
+
port.remote_file = upload_file(port.file) unless port.remote_file?
|
897
980
|
|
898
|
-
xml_value = xml_text_node(port.file)
|
899
|
-
uri = Util.append_to_uri_path(links[:inputs], "input/#{port.name}")
|
900
|
-
@server.update(uri, XML::Fragments::RUNINPUTFILE % xml_value,
|
901
|
-
"application/xml", @credentials)
|
981
|
+
xml_value = XML::Fragments::RUNINPUTFILE % xml_text_node(port.file)
|
902
982
|
else
|
903
|
-
xml_value = xml_text_node(port.value)
|
904
|
-
uri = Util.append_to_uri_path(links[:inputs], "input/#{port.name}")
|
905
|
-
@server.update(uri, XML::Fragments::RUNINPUTVALUE % xml_value,
|
906
|
-
"application/xml", @credentials)
|
983
|
+
xml_value = XML::Fragments::RUNINPUTVALUE % xml_text_node(port.value)
|
907
984
|
end
|
985
|
+
|
986
|
+
@server.update(uri, xml_value, "application/xml", @credentials)
|
908
987
|
end
|
909
988
|
end
|
910
989
|
|
@@ -950,90 +1029,6 @@ module T2Server
|
|
950
1029
|
u.to_s
|
951
1030
|
end
|
952
1031
|
|
953
|
-
# List a directory in the run's workspace on the server. If dir is left
|
954
|
-
# blank then / is listed. As there is no concept of changing into a
|
955
|
-
# directory (cd) in Taverna Server then all paths passed into _ls_ports
|
956
|
-
# should be full paths starting at "root". The contents of a directory are
|
957
|
-
# returned as a list of two lists, "lists" and "values" respectively.
|
958
|
-
def _ls_ports(dir="", top=true)
|
959
|
-
dir = Util.strip_path_slashes(dir)
|
960
|
-
uri = Util.append_to_uri_path(links[:wdir], dir)
|
961
|
-
dir_list = @server.read(uri, "*/*", @credentials)
|
962
|
-
|
963
|
-
# compile a list of directory entries stripping the
|
964
|
-
# directory name from the front of each filename
|
965
|
-
lists = []
|
966
|
-
values = []
|
967
|
-
|
968
|
-
doc = xml_document(dir_list)
|
969
|
-
|
970
|
-
xpath_find(doc, XPaths[:dir]).each do |e|
|
971
|
-
if top
|
972
|
-
lists << xml_node_content(e).split('/')[-1]
|
973
|
-
else
|
974
|
-
index = (xml_node_attribute(e, 'name').to_i - 1)
|
975
|
-
lists[index] = xml_node_content(e).split('/')[-1]
|
976
|
-
end
|
977
|
-
end
|
978
|
-
|
979
|
-
xpath_find(doc, XPaths[:file]).each do |e|
|
980
|
-
if top
|
981
|
-
values << xml_node_content(e).split('/')[-1]
|
982
|
-
else
|
983
|
-
index = (xml_node_attribute(e, 'name').to_i - 1)
|
984
|
-
values[index] = xml_node_content(e).split('/')[-1]
|
985
|
-
end
|
986
|
-
end
|
987
|
-
|
988
|
-
[lists, values]
|
989
|
-
end
|
990
|
-
|
991
|
-
def _get_output(output, refs=false, top=true)
|
992
|
-
output = Util.strip_path_slashes(output)
|
993
|
-
|
994
|
-
# if at the top level we need to check if the port represents a list
|
995
|
-
# or a singleton value
|
996
|
-
if top
|
997
|
-
lists, items = _ls_ports("out")
|
998
|
-
if items.include? output
|
999
|
-
if refs
|
1000
|
-
return "#{@server.uri}/rest/runs/#{@identifier}/" +
|
1001
|
-
"#{links[:wdir]}/out/#{output}"
|
1002
|
-
else
|
1003
|
-
out_uri = Util.append_to_uri_path(links[:wdir], "out/#{output}")
|
1004
|
-
return @server.read(out_uri, "application/octet-stream",
|
1005
|
-
@credentials)
|
1006
|
-
end
|
1007
|
-
end
|
1008
|
-
end
|
1009
|
-
|
1010
|
-
# we're not at the top level so look at the contents of the output port
|
1011
|
-
lists, items = _ls_ports("out/#{output}", false)
|
1012
|
-
|
1013
|
-
# build up lists of results
|
1014
|
-
result = []
|
1015
|
-
|
1016
|
-
# for each list recurse into it and add the items to the result
|
1017
|
-
lists.each do |list|
|
1018
|
-
result << _get_output("#{output}/#{list}", refs, false)
|
1019
|
-
end
|
1020
|
-
|
1021
|
-
# for each item, add it to the output list
|
1022
|
-
items.each do |item|
|
1023
|
-
if refs
|
1024
|
-
result << "#{@server.uri}/rest/runs/#{@identifier}/" +
|
1025
|
-
"#{links[:wdir]}/out/#{output}/#{item}"
|
1026
|
-
else
|
1027
|
-
out_uri = Util.append_to_uri_path(links[:wdir],
|
1028
|
-
"out/#{output}/#{item}")
|
1029
|
-
result << @server.read(out_uri, "application/octet-stream",
|
1030
|
-
@credentials)
|
1031
|
-
end
|
1032
|
-
end
|
1033
|
-
|
1034
|
-
result
|
1035
|
-
end
|
1036
|
-
|
1037
1032
|
def _get_input_port_info
|
1038
1033
|
ports = {}
|
1039
1034
|
port_desc = @server.read(links[:inputexp], "application/xml",
|
@@ -1041,7 +1036,7 @@ module T2Server
|
|
1041
1036
|
|
1042
1037
|
doc = xml_document(port_desc)
|
1043
1038
|
|
1044
|
-
xpath_find(doc,
|
1039
|
+
xpath_find(doc, @@xpaths[:port_in]).each do |inp|
|
1045
1040
|
port = InputPort.new(self, inp)
|
1046
1041
|
ports[port.name] = port
|
1047
1042
|
end
|
@@ -1060,7 +1055,7 @@ module T2Server
|
|
1060
1055
|
|
1061
1056
|
doc = xml_document(port_desc)
|
1062
1057
|
|
1063
|
-
xpath_find(doc,
|
1058
|
+
xpath_find(doc, @@xpaths[:port_out]).each do |out|
|
1064
1059
|
port = OutputPort.new(self, out)
|
1065
1060
|
ports[port.name] = port
|
1066
1061
|
end
|
@@ -1080,32 +1075,31 @@ module T2Server
|
|
1080
1075
|
def _get_run_owner
|
1081
1076
|
doc = _get_run_description
|
1082
1077
|
|
1083
|
-
xpath_attr(doc,
|
1078
|
+
xpath_attr(doc, @@xpaths[:run_desc], "owner")
|
1084
1079
|
end
|
1085
1080
|
|
1086
1081
|
def _get_run_links
|
1087
1082
|
doc = _get_run_description
|
1088
1083
|
|
1089
1084
|
# first parse out the basic stuff
|
1090
|
-
links =
|
1085
|
+
links = get_uris_from_doc(doc, [:expiry, :workflow, :status,
|
1086
|
+
:createtime, :starttime, :finishtime, :wdir, :inputs, :output,
|
1087
|
+
:securectx, :listeners, :name, :feed])
|
1091
1088
|
|
1092
|
-
|
1093
|
-
|
1094
|
-
links[key] = URI.parse(xpath_attr(doc, XPaths[key], "href"))
|
1095
|
-
end
|
1089
|
+
# Working dir links
|
1090
|
+
_get_wdir_links(links)
|
1096
1091
|
|
1097
1092
|
# get inputs
|
1098
1093
|
inputs = @server.read(links[:inputs], "application/xml",@credentials)
|
1099
1094
|
doc = xml_document(inputs)
|
1100
1095
|
|
1101
|
-
links
|
1102
|
-
links[:inputexp] = URI.parse(xpath_attr(doc, XPaths[:inputexp], "href"))
|
1096
|
+
links.merge! get_uris_from_doc(doc, [:baclava, :inputexp])
|
1103
1097
|
|
1104
1098
|
# set io properties
|
1105
1099
|
links[:io] = Util.append_to_uri_path(links[:listeners], "io")
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1100
|
+
[:stdout, :stderr, :exitcode].each do |res|
|
1101
|
+
links[res] = Util.append_to_uri_path(links[:io], "properties/#{res}")
|
1102
|
+
end
|
1109
1103
|
|
1110
1104
|
# security properties - only available to the owner of a run
|
1111
1105
|
if owner?
|
@@ -1113,39 +1107,62 @@ module T2Server
|
|
1113
1107
|
@credentials)
|
1114
1108
|
doc = xml_document(securectx)
|
1115
1109
|
|
1116
|
-
|
1117
|
-
|
1118
|
-
# "href").split('/')[-1]
|
1119
|
-
links[key] = Util.append_to_uri_path(links[:securectx],
|
1120
|
-
xpath_attr(doc, XPaths[key], "href").split('/')[-1])
|
1121
|
-
end
|
1110
|
+
links.merge! get_uris_from_doc(doc,
|
1111
|
+
[:sec_creds, :sec_perms, :sec_trusts])
|
1122
1112
|
end
|
1123
1113
|
|
1124
1114
|
links
|
1125
1115
|
end
|
1126
1116
|
|
1127
|
-
|
1128
|
-
|
1129
|
-
:
|
1130
|
-
:running => "Operating",
|
1131
|
-
:finished => "Finished",
|
1132
|
-
:stopped => "Stopped"
|
1133
|
-
}
|
1117
|
+
def _get_wdir_links(links)
|
1118
|
+
# Logs directory
|
1119
|
+
links[:logdir] = Util.append_to_uri_path(links[:wdir], "logs")
|
1134
1120
|
|
1135
|
-
|
1136
|
-
|
1137
|
-
"Operating" => :running,
|
1138
|
-
"Finished" => :finished,
|
1139
|
-
"Stopped" => :stopped
|
1140
|
-
}
|
1141
|
-
# :startdoc:
|
1121
|
+
# Log file
|
1122
|
+
links[:logfile] = Util.append_to_uri_path(links[:logdir], "detail.log")
|
1142
1123
|
|
1143
|
-
|
1144
|
-
|
1124
|
+
# Interaction working directory, if we have a feed.
|
1125
|
+
unless links[:feed].nil?
|
1126
|
+
links[:feeddir] = Util.append_to_uri_path(links[:wdir], "interactions")
|
1127
|
+
end
|
1145
1128
|
end
|
1146
1129
|
|
1147
|
-
def
|
1148
|
-
|
1130
|
+
def download_or_stream(param, uri, type, &block)
|
1131
|
+
if param.respond_to? :write
|
1132
|
+
@server.read_to_stream(param, uri, type, @credentials)
|
1133
|
+
elsif param.instance_of? String
|
1134
|
+
@server.read_to_file(param, uri, type, @credentials)
|
1135
|
+
else
|
1136
|
+
@server.read(uri, type, @credentials, &block)
|
1137
|
+
end
|
1149
1138
|
end
|
1139
|
+
|
1140
|
+
# :stopdoc:
|
1141
|
+
class Status
|
1142
|
+
STATE2TEXT = {
|
1143
|
+
:initialized => "Initialized",
|
1144
|
+
:running => "Operating",
|
1145
|
+
:finished => "Finished",
|
1146
|
+
:stopped => "Stopped",
|
1147
|
+
:deleted => "Deleted"
|
1148
|
+
}
|
1149
|
+
|
1150
|
+
TEXT2STATE = {
|
1151
|
+
"Initialized" => :initialized,
|
1152
|
+
"Operating" => :running,
|
1153
|
+
"Finished" => :finished,
|
1154
|
+
"Stopped" => :stopped
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
def Status.to_text(state)
|
1158
|
+
STATE2TEXT[state.to_sym]
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
def Status.to_sym(text)
|
1162
|
+
TEXT2STATE[text]
|
1163
|
+
end
|
1164
|
+
end
|
1165
|
+
# :startdoc:
|
1166
|
+
|
1150
1167
|
end
|
1151
1168
|
end
|