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/server.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,459 +30,455 @@
|
|
30
30
|
#
|
31
31
|
# Author: Robert Haines
|
32
32
|
|
33
|
-
require 'rubygems'
|
34
33
|
require 'base64'
|
35
34
|
require 'uri'
|
36
|
-
require 'net/https'
|
37
|
-
require 'libxml'
|
38
35
|
|
39
36
|
module T2Server
|
40
37
|
|
41
38
|
# An interface for directly communicating with one or more Taverna 2 Server
|
42
39
|
# instances.
|
43
40
|
class Server
|
44
|
-
include
|
41
|
+
include XML::Methods
|
45
42
|
|
46
|
-
|
43
|
+
# The version of the remote Taverna Server instance.
|
44
|
+
attr_reader :version
|
47
45
|
|
48
|
-
# The URI of this server instance.
|
49
|
-
attr_reader :uri
|
50
|
-
|
51
|
-
# The maximum number of runs that this server will allow at any one time.
|
52
|
-
# Runs in any state (+Initialized+, +Running+ and +Finished+) are counted
|
53
|
-
# against this maximum.
|
54
|
-
attr_reader :run_limit
|
55
|
-
|
56
|
-
# list of servers we know about
|
57
|
-
@@servers = []
|
58
|
-
|
59
46
|
# :stopdoc:
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
@password = password
|
76
|
-
|
77
|
-
@http.use_ssl = true
|
78
|
-
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
79
|
-
end
|
80
|
-
|
81
|
-
# add a slash to the end of this address to work around this bug:
|
82
|
-
# http://www.mygrid.org.uk/dev/issues/browse/TAVSERV-113
|
83
|
-
@links = parse_description(get_attribute("#{@rest_path}/"))
|
84
|
-
#@links.each {|key, val| puts "#{key}: #{val}"}
|
85
|
-
|
86
|
-
# get max runs
|
87
|
-
@run_limit = get_attribute(@links[:runlimit]).to_i
|
88
|
-
|
89
|
-
# initialise run list
|
90
|
-
@runs = {}
|
91
|
-
@runs = get_runs
|
92
|
-
end
|
47
|
+
XPaths = {
|
48
|
+
# Server top-level XPath queries
|
49
|
+
:server => XML::Methods.xpath_compile("//nsr:serverDescription"),
|
50
|
+
:policy => XML::Methods.xpath_compile("//nsr:policy"),
|
51
|
+
:run => XML::Methods.xpath_compile("//nsr:run"),
|
52
|
+
:runs => XML::Methods.xpath_compile("//nsr:runs"),
|
53
|
+
|
54
|
+
# Server policy XPath queries
|
55
|
+
:runlimit => XML::Methods.xpath_compile("//nsr:runLimit"),
|
56
|
+
:permwkf => XML::Methods.xpath_compile("//nsr:permittedWorkflows"),
|
57
|
+
:permlstn => XML::Methods.xpath_compile("//nsr:permittedListeners"),
|
58
|
+
:permlstt => XML::Methods.xpath_compile("//nsr:permittedListenerTypes"),
|
59
|
+
:notify =>
|
60
|
+
XML::Methods.xpath_compile("//nsr:enabledNotificationFabrics")
|
61
|
+
}
|
93
62
|
# :startdoc:
|
94
63
|
|
95
64
|
# :call-seq:
|
96
|
-
#
|
65
|
+
# new(uri, connection_parameters = nil) -> Server
|
66
|
+
# new(uri, connection_parameters = nil) {|self| ...}
|
97
67
|
#
|
98
|
-
#
|
99
|
-
#
|
68
|
+
# Create a new Server instance that represents the real server at _uri_.
|
69
|
+
# If _connection_parameters_ are supplied they will be used to set up the
|
70
|
+
# network connection to the server.
|
100
71
|
#
|
101
|
-
#
|
102
|
-
|
103
|
-
def Server.connect(uri, username="", password="")
|
72
|
+
# It will _yield_ itself if a block is given.
|
73
|
+
def initialize(uri, params = nil)
|
104
74
|
# we want to use URIs here but strings can be passed in
|
105
|
-
|
106
|
-
uri = URI.parse(uri
|
75
|
+
unless uri.is_a? URI
|
76
|
+
uri = URI.parse(Util.strip_path_slashes(uri))
|
107
77
|
end
|
108
|
-
|
78
|
+
|
109
79
|
# strip username and password from the URI if present
|
110
|
-
|
111
|
-
|
112
|
-
new_uri = URI::HTTP.new(uri.scheme, nil, uri.host, uri.port, nil,
|
80
|
+
if uri.user != nil
|
81
|
+
uri = URI::HTTP.new(uri.scheme, nil, uri.host, uri.port, nil,
|
113
82
|
uri.path, nil, nil, nil);
|
114
|
-
|
115
|
-
# see if we've already got this server
|
116
|
-
server = @@servers.find {|s| s.uri == new_uri}
|
117
|
-
|
118
|
-
if !server
|
119
|
-
# no, so create new one and return it
|
120
|
-
server = new(new_uri, username, password)
|
121
|
-
@@servers << server
|
122
83
|
end
|
123
|
-
|
124
|
-
|
84
|
+
|
85
|
+
# setup connection
|
86
|
+
@connection = ConnectionFactory.connect(uri, params)
|
87
|
+
|
88
|
+
# add a slash to the end of this address to work around this bug:
|
89
|
+
# http://www.mygrid.org.uk/dev/issues/browse/TAVSERV-113
|
90
|
+
server_description = xml_document(get_attribute("#{uri.path}/rest/",
|
91
|
+
"application/xml"))
|
92
|
+
@version = get_version(server_description)
|
93
|
+
@links = get_description(server_description)
|
94
|
+
@links[:admin] = "#{uri.path}/admin"
|
95
|
+
|
96
|
+
# initialize run object cache
|
97
|
+
@runs = {}
|
98
|
+
|
99
|
+
yield(self) if block_given?
|
100
|
+
end
|
101
|
+
|
102
|
+
# :stopdoc:
|
103
|
+
def Server.connect(uri, username="", password="")
|
104
|
+
warn "[DEPRECATION] 'Server#connect' is deprecated and will be " +
|
105
|
+
"removed in 1.0."
|
106
|
+
new(uri)
|
107
|
+
end
|
108
|
+
# :startdoc:
|
109
|
+
|
110
|
+
# :call-seq:
|
111
|
+
# administrator(credentials = nil) -> Administrator
|
112
|
+
# administrator(credentials = nil) {|admin| ...}
|
113
|
+
#
|
114
|
+
# Return an instance of the Taverna Server administrator interface. This
|
115
|
+
# method will _yield_ the newly created administrator if a block is given.
|
116
|
+
def administrator(credentials = nil)
|
117
|
+
admin = Administrator.new(self, credentials)
|
118
|
+
|
119
|
+
yield(admin) if block_given?
|
120
|
+
admin
|
125
121
|
end
|
126
122
|
|
127
123
|
# :call-seq:
|
128
|
-
#
|
124
|
+
# create_run(workflow, credentials = nil) -> run
|
125
|
+
# create_run(workflow, credentials = nil) {|run| ...}
|
129
126
|
#
|
130
127
|
# Create a run on this server using the specified _workflow_.
|
131
|
-
|
132
|
-
|
133
|
-
|
128
|
+
# This method will _yield_ the newly created Run if a block is given.
|
129
|
+
def create_run(workflow, credentials = nil)
|
130
|
+
id = initialize_run(workflow, credentials)
|
131
|
+
run = Run.create(self, "", credentials, id)
|
132
|
+
|
133
|
+
# cache newly created run object - this must be done per user
|
134
|
+
user = credentials.nil? ? :all : credentials.username
|
135
|
+
@runs[user] = {} unless @runs[user]
|
136
|
+
@runs[user][id] = run
|
137
|
+
|
138
|
+
yield(run) if block_given?
|
139
|
+
run
|
134
140
|
end
|
135
141
|
|
136
142
|
# :call-seq:
|
137
|
-
#
|
143
|
+
# initialize_run(workflow, credentials = nil) -> string
|
138
144
|
#
|
139
145
|
# Create a run on this server using the specified _workflow_ but do not
|
140
|
-
# return it as a Run instance. Return its
|
141
|
-
def initialize_run(workflow)
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
response = @http.request(request, Fragments::WORKFLOW % workflow)
|
149
|
-
rescue InternalHTTPError => e
|
150
|
-
raise ConnectionError.new(e)
|
151
|
-
end
|
152
|
-
|
153
|
-
case response
|
154
|
-
when Net::HTTPCreated
|
155
|
-
# return the uuid of the newly created run
|
156
|
-
epr = URI.parse(response['location'])
|
157
|
-
epr.path[-36..-1]
|
158
|
-
when Net::HTTPForbidden
|
159
|
-
raise ServerAtCapacityError.new(@run_limit)
|
160
|
-
when Net::HTTPUnauthorized
|
161
|
-
raise AuthorizationError.new(@username)
|
162
|
-
else
|
163
|
-
raise UnexpectedServerResponse.new(response)
|
164
|
-
end
|
146
|
+
# return it as a Run instance. Return its identifier instead.
|
147
|
+
def initialize_run(workflow, credentials = nil)
|
148
|
+
# set up the run object cache - this must be done per user
|
149
|
+
user = credentials.nil? ? :all : credentials.username
|
150
|
+
@runs[user] = {} unless @runs[user]
|
151
|
+
|
152
|
+
@connection.POST_run("#{@links[:runs]}",
|
153
|
+
XML::Fragments::WORKFLOW % workflow, credentials)
|
165
154
|
end
|
166
155
|
|
167
156
|
# :call-seq:
|
168
|
-
#
|
157
|
+
# uri -> URI
|
169
158
|
#
|
170
|
-
#
|
171
|
-
def
|
172
|
-
@
|
159
|
+
# The URI of the connection to the remote Taverna Server.
|
160
|
+
def uri
|
161
|
+
@connection.uri
|
173
162
|
end
|
174
163
|
|
175
164
|
# :call-seq:
|
176
|
-
#
|
165
|
+
# run_limit(credentials = nil) -> num
|
166
|
+
#
|
167
|
+
# The maximum number of runs that this server will allow at any one time.
|
168
|
+
# Runs in any state (+Initialized+, +Running+ and +Finished+) are counted
|
169
|
+
# against this maximum.
|
170
|
+
def run_limit(credentials = nil)
|
171
|
+
get_attribute(@links[:runlimit], "text/plain", credentials).to_i
|
172
|
+
end
|
173
|
+
|
174
|
+
# :call-seq:
|
175
|
+
# runs(credentials = nil) -> [runs]
|
177
176
|
#
|
178
177
|
# Return the set of runs on this server.
|
179
|
-
def runs
|
180
|
-
get_runs.values
|
178
|
+
def runs(credentials = nil)
|
179
|
+
get_runs(credentials).values
|
181
180
|
end
|
182
181
|
|
183
182
|
# :call-seq:
|
184
|
-
#
|
183
|
+
# run(identifier, credentials = nil) -> run
|
185
184
|
#
|
186
185
|
# Return the specified run.
|
187
|
-
def run(
|
188
|
-
get_runs[
|
186
|
+
def run(identifier, credentials = nil)
|
187
|
+
get_runs(credentials)[identifier]
|
189
188
|
end
|
190
189
|
|
191
190
|
# :call-seq:
|
192
|
-
#
|
191
|
+
# delete_run(run, credentials = nil) -> bool
|
193
192
|
#
|
194
193
|
# Delete the specified run from the server, discarding all of its state.
|
195
|
-
# _run_ can be either a Run instance or a
|
196
|
-
def delete_run(run)
|
197
|
-
# get the
|
194
|
+
# _run_ can be either a Run instance or a identifier.
|
195
|
+
def delete_run(run, credentials = nil)
|
196
|
+
# get the identifier from the run if that is what is passed in
|
198
197
|
if run.instance_of? Run
|
199
|
-
run = run.
|
198
|
+
run = run.identifier
|
200
199
|
end
|
201
200
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
begin
|
207
|
-
response = @http.request(request)
|
208
|
-
rescue InternalHTTPError => e
|
209
|
-
raise ConnectionError.new(e)
|
210
|
-
end
|
211
|
-
|
212
|
-
case response
|
213
|
-
when Net::HTTPNoContent
|
214
|
-
# Success, carry on...
|
215
|
-
@runs.delete(run)
|
201
|
+
if delete_attribute("#{@links[:runs]}/#{run}", credentials)
|
202
|
+
# delete cached run object - this must be done per user
|
203
|
+
user = credentials.nil? ? :all : credentials.username
|
204
|
+
@runs[user].delete(run) if @runs[user]
|
216
205
|
true
|
217
|
-
when Net::HTTPNotFound
|
218
|
-
raise RunNotFoundError.new(run)
|
219
|
-
when Net::HTTPForbidden
|
220
|
-
raise AccessForbiddenError.new("run #{run}")
|
221
|
-
when Net::HTTPUnauthorized
|
222
|
-
raise AuthorizationError.new(@username)
|
223
|
-
else
|
224
|
-
raise UnexpectedServerResponse.new(response)
|
225
206
|
end
|
226
207
|
end
|
227
208
|
|
228
209
|
# :call-seq:
|
229
|
-
#
|
210
|
+
# delete_all_runs(credentials = nil)
|
230
211
|
#
|
231
212
|
# Delete all runs on this server, discarding all of their state.
|
232
|
-
def delete_all_runs
|
213
|
+
def delete_all_runs(credentials = nil)
|
233
214
|
# first refresh run list
|
234
|
-
runs.each {|run| run.delete}
|
215
|
+
runs(credentials).each {|run| run.delete}
|
235
216
|
end
|
236
217
|
|
237
|
-
# :
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
218
|
+
# :stopdoc:
|
219
|
+
def set_run_input(run, input, value, credentials = nil)
|
220
|
+
warn "[DEPRECATION] 'Server#set_run_input' is deprecated and will be " +
|
221
|
+
"removed in 1.0. Input ports are set directly instead. The most " +
|
222
|
+
"direct replacement for this method is: " +
|
223
|
+
"'Run#input_port(input).value = value'"
|
224
|
+
|
225
|
+
# get the run from the identifier if that is what is passed in
|
244
226
|
if not run.instance_of? Run
|
245
|
-
run = run(run)
|
227
|
+
run = run(run, credentials)
|
246
228
|
end
|
247
229
|
|
248
|
-
|
249
|
-
path = "#{@links[:runs]}/#{run.uuid}/#{run.inputs}/input/#{input}"
|
250
|
-
set_attribute(path, Fragments::RUNINPUTVALUE % xml_value, "application/xml")
|
251
|
-
rescue AttributeNotFoundError => e
|
252
|
-
if get_runs.has_key? run.uuid
|
253
|
-
raise e
|
254
|
-
else
|
255
|
-
raise RunNotFoundError.new(run.uuid)
|
256
|
-
end
|
230
|
+
run.input_port(input).value = value
|
257
231
|
end
|
258
232
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
# get the run from the
|
233
|
+
def set_run_input_file(run, input, filename, credentials = nil)
|
234
|
+
warn "[DEPRECATION] 'Server#set_run_input_file' is deprecated and " +
|
235
|
+
"will be removed in 1.0. Input ports are set directly instead. The " +
|
236
|
+
"most direct replacement for this method is: " +
|
237
|
+
"'Run#input_port(input).remote_file = filename'"
|
238
|
+
|
239
|
+
# get the run from the identifier if that is what is passed in
|
266
240
|
if not run.instance_of? Run
|
267
|
-
run = run(run)
|
241
|
+
run = run(run, credentials)
|
268
242
|
end
|
269
243
|
|
270
|
-
|
271
|
-
path = "#{@links[:runs]}/#{run.uuid}/#{run.inputs}/input/#{input}"
|
272
|
-
set_attribute(path, Fragments::RUNINPUTFILE % xml_value, "application/xml")
|
273
|
-
rescue AttributeNotFoundError => e
|
274
|
-
if get_runs.has_key? run.uuid
|
275
|
-
raise e
|
276
|
-
else
|
277
|
-
raise RunNotFoundError.new(run.uuid)
|
278
|
-
end
|
244
|
+
run.input_port(input).remote_file = filename
|
279
245
|
end
|
280
246
|
|
281
|
-
|
282
|
-
|
283
|
-
#
|
284
|
-
# Create a directory _dir_ within the directory _root_ on _run_. _run_ can
|
285
|
-
# be either a Run instance or a UUID. This is mainly for use by Run#mkdir.
|
286
|
-
def make_run_dir(run, root, dir)
|
287
|
-
# get the uuid from the run if that is what is passed in
|
247
|
+
def create_dir(run, root, dir, credentials = nil)
|
248
|
+
# get the identifier from the run if that is what is passed in
|
288
249
|
if run.instance_of? Run
|
289
|
-
run = run.
|
250
|
+
run = run.identifier
|
290
251
|
end
|
291
252
|
|
292
253
|
raise AccessForbiddenError.new("subdirectories (#{dir})") if dir.include? ?/
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
254
|
+
@connection.POST_dir("#{@links[:runs]}/#{run}/#{root}",
|
255
|
+
XML::Fragments::MKDIR % dir, run, dir, credentials)
|
256
|
+
end
|
257
|
+
|
258
|
+
def make_run_dir(run, root, dir, credentials = nil)
|
259
|
+
warn "[DEPRECATION] 'Server#make_run_dir' is deprecated and will be " +
|
260
|
+
"removed in 1.0. Please use 'Run#mkdir' instead."
|
261
|
+
|
262
|
+
create_dir(run, root, dir, credentials)
|
263
|
+
end
|
264
|
+
|
265
|
+
def upload_file(run, filename, location, rename, credentials = nil)
|
266
|
+
contents = IO.read(filename)
|
267
|
+
rename = filename.split('/')[-1] if rename == ""
|
268
|
+
|
269
|
+
if upload_data(run, contents, rename, location, credentials)
|
270
|
+
rename
|
302
271
|
end
|
272
|
+
end
|
303
273
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
when Net::HTTPNotFound
|
309
|
-
raise RunNotFoundError.new(run)
|
310
|
-
when Net::HTTPForbidden
|
311
|
-
raise AccessForbiddenError.new("#{dir} on run #{run}")
|
312
|
-
when Net::HTTPUnauthorized
|
313
|
-
raise AuthorizationError.new(@username)
|
314
|
-
else
|
315
|
-
raise UnexpectedServerResponse.new(response)
|
274
|
+
def upload_data(run, data, remote_name, location, credentials = nil)
|
275
|
+
# get the identifier from the run if that is what is passed in
|
276
|
+
if run.instance_of? Run
|
277
|
+
run = run.identifier
|
316
278
|
end
|
279
|
+
|
280
|
+
contents = Base64.encode64(data)
|
281
|
+
|
282
|
+
@connection.POST_file("#{@links[:runs]}/#{run}/#{location}",
|
283
|
+
XML::Fragments::UPLOAD % [remote_name, contents], run, credentials)
|
317
284
|
end
|
318
285
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
286
|
+
def upload_run_file(run, filename, location, rename, credentials = nil)
|
287
|
+
warn "[DEPRECATION] 'Server#upload_run_file' is deprecated and will " +
|
288
|
+
"be removed in 1.0. Please use 'Run#upload_file' or " +
|
289
|
+
"'Run#input_port(input).file = filename' instead."
|
290
|
+
|
291
|
+
upload_file(run, filename, location, rename, credentials)
|
292
|
+
end
|
293
|
+
|
294
|
+
def create_run_attribute(run, path, value, type, credentials = nil)
|
295
|
+
# get the identifier from the run if that is what is passed in
|
326
296
|
if run.instance_of? Run
|
327
|
-
run = run.
|
297
|
+
run = run.identifier
|
328
298
|
end
|
329
299
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
300
|
+
create_attribute("#{@links[:runs]}/#{run}/#{path}", value, type,
|
301
|
+
credentials)
|
302
|
+
rescue AttributeNotFoundError => e
|
303
|
+
if get_runs(credentials).has_key? run
|
304
|
+
raise e
|
305
|
+
else
|
306
|
+
raise RunNotFoundError.new(run)
|
336
307
|
end
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
308
|
+
end
|
309
|
+
|
310
|
+
def get_run_attribute(run, path, type, credentials = nil)
|
311
|
+
# get the identifier from the run if that is what is passed in
|
312
|
+
if run.instance_of? Run
|
313
|
+
run = run.identifier
|
341
314
|
end
|
342
315
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
when Net::HTTPNotFound
|
348
|
-
raise RunNotFoundError.new(run)
|
349
|
-
when Net::HTTPForbidden
|
350
|
-
raise AccessForbiddenError.new("run #{run}")
|
351
|
-
when Net::HTTPUnauthorized
|
352
|
-
raise AuthorizationError.new(@username)
|
316
|
+
get_attribute("#{@links[:runs]}/#{run}/#{path}", type, credentials)
|
317
|
+
rescue AttributeNotFoundError => e
|
318
|
+
if get_runs(credentials).has_key? run
|
319
|
+
raise e
|
353
320
|
else
|
354
|
-
raise
|
321
|
+
raise RunNotFoundError.new(run)
|
355
322
|
end
|
356
323
|
end
|
357
324
|
|
358
|
-
|
359
|
-
|
360
|
-
#
|
361
|
-
# Get the attribute at _path_ in _run_. _run_ can be either a Run instance
|
362
|
-
# or a UUID.
|
363
|
-
def get_run_attribute(run, path)
|
364
|
-
# get the uuid from the run if that is what is passed in
|
325
|
+
def set_run_attribute(run, path, value, type, credentials = nil)
|
326
|
+
# get the identifier from the run if that is what is passed in
|
365
327
|
if run.instance_of? Run
|
366
|
-
run = run.
|
328
|
+
run = run.identifier
|
367
329
|
end
|
368
330
|
|
369
|
-
|
331
|
+
set_attribute("#{@links[:runs]}/#{run}/#{path}", value, type,
|
332
|
+
credentials)
|
370
333
|
rescue AttributeNotFoundError => e
|
371
|
-
if get_runs.has_key? run
|
334
|
+
if get_runs(credentials).has_key? run
|
372
335
|
raise e
|
373
336
|
else
|
374
337
|
raise RunNotFoundError.new(run)
|
375
338
|
end
|
376
339
|
end
|
377
340
|
|
378
|
-
|
379
|
-
|
380
|
-
#
|
381
|
-
# Set the attribute at _path_ in _run_ to _value_. _run_ can be either a
|
382
|
-
# Run instance or a UUID.
|
383
|
-
def set_run_attribute(run, path, value)
|
384
|
-
# get the uuid from the run if that is what is passed in
|
341
|
+
def delete_run_attribute(run, path, credentials = nil)
|
342
|
+
# get the identifier from the run if that is what is passed in
|
385
343
|
if run.instance_of? Run
|
386
|
-
run = run.
|
344
|
+
run = run.identifier
|
387
345
|
end
|
388
346
|
|
389
|
-
|
347
|
+
delete_attribute("#{@links[:runs]}/#{run}/#{path}", credentials)
|
390
348
|
rescue AttributeNotFoundError => e
|
391
|
-
if get_runs.has_key? run
|
349
|
+
if get_runs(credentials).has_key? run
|
392
350
|
raise e
|
393
351
|
else
|
394
352
|
raise RunNotFoundError.new(run)
|
395
353
|
end
|
396
354
|
end
|
397
355
|
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
request.basic_auth @username, @password
|
403
|
-
end
|
404
|
-
begin
|
405
|
-
response = @http.request(request)
|
406
|
-
rescue InternalHTTPError => e
|
407
|
-
raise ConnectionError.new(e)
|
356
|
+
def download_run_file(run, path, range, credentials = nil)
|
357
|
+
# get the identifier from the run if that is what is passed in
|
358
|
+
if run.instance_of? Run
|
359
|
+
run = run.identifier
|
408
360
|
end
|
409
361
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
raise
|
415
|
-
when Net::HTTPForbidden
|
416
|
-
raise AccessForbiddenError.new("attribute #{path}")
|
417
|
-
when Net::HTTPUnauthorized
|
418
|
-
raise AuthorizationError.new(@username)
|
362
|
+
get_attribute("#{@links[:runs]}/#{run}/#{path}",
|
363
|
+
"application/octet-stream", range, credentials)
|
364
|
+
rescue AttributeNotFoundError => e
|
365
|
+
if get_runs(credentials).has_key? run
|
366
|
+
raise e
|
419
367
|
else
|
420
|
-
raise
|
368
|
+
raise RunNotFoundError.new(run)
|
421
369
|
end
|
422
370
|
end
|
423
371
|
|
424
|
-
def
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
372
|
+
def get_admin_attribute(path, credentials = nil)
|
373
|
+
get_attribute("#{@links[:admin]}/#{path}", "*/*", credentials)
|
374
|
+
end
|
375
|
+
|
376
|
+
def set_admin_attribute(path, value, credentials = nil)
|
377
|
+
set_attribute("#{@links[:admin]}/#{path}", value, "text/plain",
|
378
|
+
credentials)
|
379
|
+
end
|
380
|
+
|
381
|
+
def admin_resource_writable?(path, credentials = nil)
|
382
|
+
headers = @connection.OPTIONS("#{@links[:admin]}/#{path}", credentials)
|
383
|
+
headers["allow"][0].split(",").include? "PUT"
|
384
|
+
end
|
385
|
+
# :startdoc:
|
386
|
+
|
387
|
+
private
|
388
|
+
def create_attribute(path, value, type, credentials = nil)
|
389
|
+
@connection.POST(path, value, type, credentials)
|
390
|
+
end
|
391
|
+
|
392
|
+
def get_attribute(path, type, *rest)
|
393
|
+
credentials = nil
|
394
|
+
range = nil
|
395
|
+
|
396
|
+
rest.each do |param|
|
397
|
+
case param
|
398
|
+
when HttpCredentials
|
399
|
+
credentials = param
|
400
|
+
when Range
|
401
|
+
range = param
|
402
|
+
when Array
|
403
|
+
range = param[0]..param[1]
|
404
|
+
end
|
429
405
|
end
|
406
|
+
|
430
407
|
begin
|
431
|
-
|
432
|
-
rescue
|
433
|
-
|
408
|
+
@connection.GET(path, type, range, credentials)
|
409
|
+
rescue ConnectionRedirectError => cre
|
410
|
+
@connection = cre.redirect
|
411
|
+
retry
|
434
412
|
end
|
413
|
+
end
|
435
414
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
415
|
+
def set_attribute(path, value, type, credentials = nil)
|
416
|
+
@connection.PUT(path, value, type, credentials)
|
417
|
+
end
|
418
|
+
|
419
|
+
def delete_attribute(path, credentials = nil)
|
420
|
+
@connection.DELETE(path, credentials)
|
421
|
+
end
|
422
|
+
|
423
|
+
def get_version(doc)
|
424
|
+
version = xpath_attr(doc, XPaths[:server], "serverVersion")
|
425
|
+
if version == nil
|
426
|
+
raise RuntimeError.new("Taverna Servers prior to version 2.3 " +
|
427
|
+
"are no longer supported.")
|
446
428
|
else
|
447
|
-
|
429
|
+
return version.to_f
|
448
430
|
end
|
449
431
|
end
|
450
432
|
|
451
|
-
def
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
433
|
+
def get_description(doc)
|
434
|
+
links = {}
|
435
|
+
links[:runs] = URI.parse(xpath_attr(doc, XPaths[:runs], "href")).path
|
436
|
+
|
437
|
+
links[:policy] = URI.parse(xpath_attr(doc, XPaths[:policy], "href")).path
|
438
|
+
doc = xml_document(get_attribute(links[:policy], "application/xml"))
|
439
|
+
|
440
|
+
links[:permlisteners] =
|
441
|
+
URI.parse(xpath_attr(doc, XPaths[:permlstt], "href")).path
|
442
|
+
links[:notifications] =
|
443
|
+
URI.parse(xpath_attr(doc, XPaths[:notify], "href")).path
|
444
|
+
|
445
|
+
links[:runlimit] =
|
446
|
+
URI.parse(xpath_attr(doc, XPaths[:runlimit], "href")).path
|
447
|
+
links[:permworkflows] =
|
448
|
+
URI.parse(xpath_attr(doc, XPaths[:permwkf], "href")).path
|
449
|
+
|
450
|
+
links
|
460
451
|
end
|
461
452
|
|
462
|
-
def get_runs
|
463
|
-
run_list = get_attribute("#{@links[:runs]}"
|
453
|
+
def get_runs(credentials = nil)
|
454
|
+
run_list = get_attribute("#{@links[:runs]}", "application/xml",
|
455
|
+
credentials)
|
464
456
|
|
465
|
-
doc =
|
457
|
+
doc = xml_document(run_list)
|
466
458
|
|
467
|
-
# get list of run
|
468
|
-
|
469
|
-
doc
|
470
|
-
|
459
|
+
# get list of run identifiers
|
460
|
+
ids = []
|
461
|
+
xpath_find(doc, XPaths[:run]).each do |run|
|
462
|
+
ids << xml_node_attribute(run, "href").split('/')[-1]
|
471
463
|
end
|
472
464
|
|
465
|
+
# cache run objects - this must be done per user
|
466
|
+
user = credentials.nil? ? :all : credentials.username
|
467
|
+
@runs[user] = {} unless @runs[user]
|
468
|
+
|
473
469
|
# add new runs
|
474
|
-
|
475
|
-
if !@runs.has_key?
|
476
|
-
@runs[
|
470
|
+
ids.each do |id|
|
471
|
+
if !@runs[user].has_key? id
|
472
|
+
@runs[user][id] = Run.create(self, "", credentials, id)
|
477
473
|
end
|
478
474
|
end
|
479
475
|
|
480
476
|
# clear out the expired runs
|
481
|
-
if @runs.length >
|
482
|
-
@runs.delete_if {|key, val| !
|
477
|
+
if @runs[user].length > ids.length
|
478
|
+
@runs[user].delete_if {|key, val| !ids.member? key}
|
483
479
|
end
|
484
480
|
|
485
|
-
@runs
|
481
|
+
@runs[user]
|
486
482
|
end
|
487
|
-
end
|
483
|
+
end
|
488
484
|
end
|